@oneuptime/common 10.0.65 → 10.0.66

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.
Files changed (210) hide show
  1. package/Models/DatabaseModels/DockerHostOwnerTeam.ts +464 -0
  2. package/Models/DatabaseModels/DockerHostOwnerUser.ts +463 -0
  3. package/Models/DatabaseModels/Index.ts +24 -0
  4. package/Models/DatabaseModels/KubernetesClusterOwnerTeam.ts +464 -0
  5. package/Models/DatabaseModels/KubernetesClusterOwnerUser.ts +463 -0
  6. package/Models/DatabaseModels/KubernetesResource.ts +548 -0
  7. package/Models/DatabaseModels/MetricPipelineRule.ts +804 -0
  8. package/Models/DatabaseModels/MetricRecordingRule.ts +470 -0
  9. package/Models/DatabaseModels/Monitor.ts +2 -0
  10. package/Models/DatabaseModels/Project.ts +53 -0
  11. package/Models/DatabaseModels/Service.ts +79 -0
  12. package/Models/DatabaseModels/TraceDropFilter.ts +508 -0
  13. package/Models/DatabaseModels/TracePipeline.ts +436 -0
  14. package/Models/DatabaseModels/TracePipelineProcessor.ts +454 -0
  15. package/Models/DatabaseModels/TraceRecordingRule.ts +470 -0
  16. package/Models/DatabaseModels/TraceScrubRule.ts +546 -0
  17. package/Server/API/KubernetesResourceAPI.ts +129 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.ts +399 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.ts +205 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.ts +335 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.ts +29 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.ts +53 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -1
  24. package/Server/Services/DockerHostOwnerTeamService.ts +10 -0
  25. package/Server/Services/DockerHostOwnerUserService.ts +10 -0
  26. package/Server/Services/KubernetesClusterOwnerTeamService.ts +10 -0
  27. package/Server/Services/KubernetesClusterOwnerUserService.ts +10 -0
  28. package/Server/Services/KubernetesResourceService.ts +351 -0
  29. package/Server/Services/MetricPipelineRuleService.ts +10 -0
  30. package/Server/Services/MetricRecordingRuleService.ts +10 -0
  31. package/Server/Services/TraceDropFilterService.ts +10 -0
  32. package/Server/Services/TracePipelineProcessorService.ts +10 -0
  33. package/Server/Services/TracePipelineService.ts +10 -0
  34. package/Server/Services/TraceRecordingRuleService.ts +10 -0
  35. package/Server/Services/TraceScrubRuleService.ts +10 -0
  36. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +71 -9
  37. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +483 -75
  38. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +379 -6
  39. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +502 -0
  40. package/Tests/Utils/MetricUnitUtil.test.ts +216 -0
  41. package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +269 -0
  42. package/Tests/Utils/Metrics/MetricResultUnitConverter.test.ts +231 -0
  43. package/Tests/Utils/RecordingRuleExpression.test.ts +177 -0
  44. package/Types/Kubernetes/KubernetesInventoryExtractor.ts +327 -0
  45. package/Types/Kubernetes/KubernetesObjectParser.ts +1949 -0
  46. package/Types/Metrics/MetricDownsamplingRetentionDays.ts +49 -0
  47. package/Types/Metrics/MetricFormulaConfigData.ts +4 -0
  48. package/Types/Metrics/MetricPipelineRuleFilterCondition.ts +136 -0
  49. package/Types/Metrics/MetricPipelineRuleType.ts +27 -0
  50. package/Types/Metrics/RecordingRuleDefinition.ts +180 -0
  51. package/Types/Monitor/CriteriaFilter.ts +43 -0
  52. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +70 -0
  53. package/Types/Permission.ts +520 -0
  54. package/Types/Trace/TraceAggregationType.ts +17 -0
  55. package/Types/Trace/TraceDropFilterAction.ts +6 -0
  56. package/Types/Trace/TracePipelineProcessorType.ts +56 -0
  57. package/Types/Trace/TraceRecordingRuleDefinition.ts +218 -0
  58. package/Types/Trace/TraceScrubAction.ts +7 -0
  59. package/Types/Trace/TraceScrubField.ts +8 -0
  60. package/Types/Trace/TraceScrubPatternType.ts +10 -0
  61. package/UI/Components/CardSelect/CardSelect.tsx +9 -1
  62. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +6 -10
  63. package/UI/Components/Forms/Fields/FormField.tsx +1 -0
  64. package/UI/Components/Forms/Types/Field.ts +1 -0
  65. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +57 -0
  66. package/UI/Components/Page/Page.tsx +6 -0
  67. package/Utils/MetricUnitUtil.ts +289 -0
  68. package/Utils/Metrics/MetricFormulaEvaluator.ts +610 -0
  69. package/Utils/Metrics/MetricResultUnitConverter.ts +91 -0
  70. package/Utils/Metrics/RecordingRuleExpression.ts +359 -0
  71. package/Utils/ValueFormatter.ts +137 -13
  72. package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js +480 -0
  73. package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js.map +1 -0
  74. package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js +479 -0
  75. package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js.map +1 -0
  76. package/build/dist/Models/DatabaseModels/Index.js +24 -0
  77. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  78. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js +480 -0
  79. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js.map +1 -0
  80. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js +479 -0
  81. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js.map +1 -0
  82. package/build/dist/Models/DatabaseModels/KubernetesResource.js +590 -0
  83. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -0
  84. package/build/dist/Models/DatabaseModels/MetricPipelineRule.js +836 -0
  85. package/build/dist/Models/DatabaseModels/MetricPipelineRule.js.map +1 -0
  86. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js +497 -0
  87. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js.map +1 -0
  88. package/build/dist/Models/DatabaseModels/Monitor.js +2 -0
  89. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  90. package/build/dist/Models/DatabaseModels/Project.js +53 -0
  91. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  92. package/build/dist/Models/DatabaseModels/Service.js +79 -0
  93. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  94. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +536 -0
  95. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -0
  96. package/build/dist/Models/DatabaseModels/TracePipeline.js +462 -0
  97. package/build/dist/Models/DatabaseModels/TracePipeline.js.map +1 -0
  98. package/build/dist/Models/DatabaseModels/TracePipelineProcessor.js +476 -0
  99. package/build/dist/Models/DatabaseModels/TracePipelineProcessor.js.map +1 -0
  100. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js +497 -0
  101. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js.map +1 -0
  102. package/build/dist/Models/DatabaseModels/TraceScrubRule.js +575 -0
  103. package/build/dist/Models/DatabaseModels/TraceScrubRule.js.map +1 -0
  104. package/build/dist/Server/API/KubernetesResourceAPI.js +98 -0
  105. package/build/dist/Server/API/KubernetesResourceAPI.js.map +1 -0
  106. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.js +144 -0
  107. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.js.map +1 -0
  108. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.js +82 -0
  109. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.js.map +1 -0
  110. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.js +118 -0
  111. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.js.map +1 -0
  112. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.js +16 -0
  113. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.js.map +1 -0
  114. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.js +24 -0
  115. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.js.map +1 -0
  116. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  118. package/build/dist/Server/Services/DockerHostOwnerTeamService.js +9 -0
  119. package/build/dist/Server/Services/DockerHostOwnerTeamService.js.map +1 -0
  120. package/build/dist/Server/Services/DockerHostOwnerUserService.js +9 -0
  121. package/build/dist/Server/Services/DockerHostOwnerUserService.js.map +1 -0
  122. package/build/dist/Server/Services/KubernetesClusterOwnerTeamService.js +9 -0
  123. package/build/dist/Server/Services/KubernetesClusterOwnerTeamService.js.map +1 -0
  124. package/build/dist/Server/Services/KubernetesClusterOwnerUserService.js +9 -0
  125. package/build/dist/Server/Services/KubernetesClusterOwnerUserService.js.map +1 -0
  126. package/build/dist/Server/Services/KubernetesResourceService.js +237 -0
  127. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -0
  128. package/build/dist/Server/Services/MetricPipelineRuleService.js +9 -0
  129. package/build/dist/Server/Services/MetricPipelineRuleService.js.map +1 -0
  130. package/build/dist/Server/Services/MetricRecordingRuleService.js +9 -0
  131. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -0
  132. package/build/dist/Server/Services/TraceDropFilterService.js +9 -0
  133. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -0
  134. package/build/dist/Server/Services/TracePipelineProcessorService.js +9 -0
  135. package/build/dist/Server/Services/TracePipelineProcessorService.js.map +1 -0
  136. package/build/dist/Server/Services/TracePipelineService.js +9 -0
  137. package/build/dist/Server/Services/TracePipelineService.js.map +1 -0
  138. package/build/dist/Server/Services/TraceRecordingRuleService.js +9 -0
  139. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -0
  140. package/build/dist/Server/Services/TraceScrubRuleService.js +9 -0
  141. package/build/dist/Server/Services/TraceScrubRuleService.js.map +1 -0
  142. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +56 -9
  143. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  144. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +335 -53
  145. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  146. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +277 -5
  147. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  148. package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js +407 -0
  149. package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js.map +1 -0
  150. package/build/dist/Tests/Utils/MetricUnitUtil.test.js +159 -0
  151. package/build/dist/Tests/Utils/MetricUnitUtil.test.js.map +1 -0
  152. package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js +224 -0
  153. package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js.map +1 -0
  154. package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js +180 -0
  155. package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js.map +1 -0
  156. package/build/dist/Tests/Utils/RecordingRuleExpression.test.js +142 -0
  157. package/build/dist/Tests/Utils/RecordingRuleExpression.test.js.map +1 -0
  158. package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js +200 -0
  159. package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js.map +1 -0
  160. package/build/dist/Types/Kubernetes/KubernetesObjectParser.js +1205 -0
  161. package/build/dist/Types/Kubernetes/KubernetesObjectParser.js.map +1 -0
  162. package/build/dist/Types/Metrics/MetricDownsamplingRetentionDays.js +32 -0
  163. package/build/dist/Types/Metrics/MetricDownsamplingRetentionDays.js.map +1 -0
  164. package/build/dist/Types/Metrics/MetricPipelineRuleFilterCondition.js +103 -0
  165. package/build/dist/Types/Metrics/MetricPipelineRuleFilterCondition.js.map +1 -0
  166. package/build/dist/Types/Metrics/MetricPipelineRuleType.js +27 -0
  167. package/build/dist/Types/Metrics/MetricPipelineRuleType.js.map +1 -0
  168. package/build/dist/Types/Metrics/RecordingRuleDefinition.js +110 -0
  169. package/build/dist/Types/Metrics/RecordingRuleDefinition.js.map +1 -0
  170. package/build/dist/Types/Monitor/CriteriaFilter.js +22 -0
  171. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  172. package/build/dist/Types/Monitor/MetricMonitor/MetricCriteriaContext.js +2 -0
  173. package/build/dist/Types/Monitor/MetricMonitor/MetricCriteriaContext.js.map +1 -0
  174. package/build/dist/Types/Permission.js +454 -0
  175. package/build/dist/Types/Permission.js.map +1 -1
  176. package/build/dist/Types/Trace/TraceAggregationType.js +18 -0
  177. package/build/dist/Types/Trace/TraceAggregationType.js.map +1 -0
  178. package/build/dist/Types/Trace/TraceDropFilterAction.js +7 -0
  179. package/build/dist/Types/Trace/TraceDropFilterAction.js.map +1 -0
  180. package/build/dist/Types/Trace/TracePipelineProcessorType.js +10 -0
  181. package/build/dist/Types/Trace/TracePipelineProcessorType.js.map +1 -0
  182. package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js +145 -0
  183. package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js.map +1 -0
  184. package/build/dist/Types/Trace/TraceScrubAction.js +8 -0
  185. package/build/dist/Types/Trace/TraceScrubAction.js.map +1 -0
  186. package/build/dist/Types/Trace/TraceScrubField.js +9 -0
  187. package/build/dist/Types/Trace/TraceScrubField.js.map +1 -0
  188. package/build/dist/Types/Trace/TraceScrubPatternType.js +11 -0
  189. package/build/dist/Types/Trace/TraceScrubPatternType.js.map +1 -0
  190. package/build/dist/UI/Components/CardSelect/CardSelect.js +3 -1
  191. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -9
  193. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  194. package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
  195. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  196. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +30 -0
  197. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  198. package/build/dist/UI/Components/Page/Page.js +1 -0
  199. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  200. package/build/dist/Utils/MetricUnitUtil.js +232 -0
  201. package/build/dist/Utils/MetricUnitUtil.js.map +1 -0
  202. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +453 -0
  203. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -0
  204. package/build/dist/Utils/Metrics/MetricResultUnitConverter.js +61 -0
  205. package/build/dist/Utils/Metrics/MetricResultUnitConverter.js.map +1 -0
  206. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +298 -0
  207. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -0
  208. package/build/dist/Utils/ValueFormatter.js +123 -13
  209. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  210. package/package.json +1 -1
@@ -0,0 +1,1949 @@
1
+ import { JSONObject } from "../JSON";
2
+
3
+ /*
4
+ * ============================================================
5
+ * OTLP kvlistValue parsing helpers
6
+ * ============================================================
7
+ */
8
+
9
+ /**
10
+ * Extract a value from an OTLP kvlistValue by key.
11
+ * Returns the string/int value or nested kvlistValue as JSONObject.
12
+ */
13
+ export function getKvValue(
14
+ kvList: JSONObject | undefined,
15
+ key: string,
16
+ ): string | JSONObject | null {
17
+ if (!kvList) {
18
+ return null;
19
+ }
20
+ const values: Array<JSONObject> | undefined = kvList["values"] as
21
+ | Array<JSONObject>
22
+ | undefined;
23
+ if (!values) {
24
+ return null;
25
+ }
26
+ for (const entry of values) {
27
+ if (entry["key"] === key) {
28
+ const val: JSONObject | undefined = entry["value"] as
29
+ | JSONObject
30
+ | undefined;
31
+ if (!val) {
32
+ return null;
33
+ }
34
+ // Handle both camelCase (JSON encoding) and snake_case (protobuf via protobufjs)
35
+ if (val["stringValue"] !== undefined) {
36
+ return val["stringValue"] as string;
37
+ }
38
+ if (val["string_value"] !== undefined) {
39
+ return val["string_value"] as string;
40
+ }
41
+ if (val["intValue"] !== undefined) {
42
+ return String(val["intValue"]);
43
+ }
44
+ if (val["int_value"] !== undefined) {
45
+ return String(val["int_value"]);
46
+ }
47
+ if (val["boolValue"] !== undefined) {
48
+ return String(val["boolValue"]);
49
+ }
50
+ if (val["bool_value"] !== undefined) {
51
+ return String(val["bool_value"]);
52
+ }
53
+ if (val["kvlistValue"]) {
54
+ return val["kvlistValue"] as JSONObject;
55
+ }
56
+ if (val["kvlist_value"]) {
57
+ return val["kvlist_value"] as JSONObject;
58
+ }
59
+ if (val["arrayValue"]) {
60
+ return val["arrayValue"] as JSONObject;
61
+ }
62
+ if (val["array_value"]) {
63
+ return val["array_value"] as JSONObject;
64
+ }
65
+ return null;
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+
71
+ /**
72
+ * Extract a string value from an OTLP kvlistValue by key.
73
+ */
74
+ export function getKvStringValue(
75
+ kvList: JSONObject | undefined,
76
+ key: string,
77
+ ): string {
78
+ const val: string | JSONObject | null = getKvValue(kvList, key);
79
+ if (typeof val === "string") {
80
+ return val;
81
+ }
82
+ return "";
83
+ }
84
+
85
+ /**
86
+ * Extract a nested kvlist value (parent → child).
87
+ */
88
+ export function getNestedKvValue(
89
+ kvList: JSONObject | undefined,
90
+ parentKey: string,
91
+ childKey: string,
92
+ ): string {
93
+ const parent: string | JSONObject | null = getKvValue(kvList, parentKey);
94
+ if (!parent || typeof parent === "string") {
95
+ return "";
96
+ }
97
+ return getKvStringValue(parent, childKey);
98
+ }
99
+
100
+ /**
101
+ * Convert a kvlistValue to a flat Record<string, string> (for labels, annotations, env).
102
+ */
103
+ export function getKvListAsRecord(
104
+ kvList: JSONObject | undefined,
105
+ ): Record<string, string> {
106
+ const result: Record<string, string> = {};
107
+ if (!kvList) {
108
+ return result;
109
+ }
110
+ const values: Array<JSONObject> | undefined = kvList["values"] as
111
+ | Array<JSONObject>
112
+ | undefined;
113
+ if (!values) {
114
+ return result;
115
+ }
116
+ for (const entry of values) {
117
+ const key: string = (entry["key"] as string) || "";
118
+ const val: JSONObject | undefined = entry["value"] as
119
+ | JSONObject
120
+ | undefined;
121
+ if (key && val) {
122
+ if (val["stringValue"] !== undefined) {
123
+ result[key] = val["stringValue"] as string;
124
+ } else if (val["string_value"] !== undefined) {
125
+ result[key] = val["string_value"] as string;
126
+ } else if (val["intValue"] !== undefined) {
127
+ result[key] = String(val["intValue"]);
128
+ } else if (val["int_value"] !== undefined) {
129
+ result[key] = String(val["int_value"]);
130
+ } else if (val["boolValue"] !== undefined) {
131
+ result[key] = String(val["boolValue"]);
132
+ } else if (val["bool_value"] !== undefined) {
133
+ result[key] = String(val["bool_value"]);
134
+ }
135
+ }
136
+ }
137
+ return result;
138
+ }
139
+
140
+ /**
141
+ * Convert an OTLP arrayValue to an array of JSONObjects (kvlistValues).
142
+ */
143
+ export function getArrayValues(
144
+ arrayValue: JSONObject | undefined,
145
+ ): Array<JSONObject> {
146
+ if (!arrayValue) {
147
+ return [];
148
+ }
149
+ const values: Array<JSONObject> | undefined = arrayValue["values"] as
150
+ | Array<JSONObject>
151
+ | undefined;
152
+ if (!values) {
153
+ return [];
154
+ }
155
+ return values
156
+ .map((item: JSONObject) => {
157
+ if (item["kvlistValue"]) {
158
+ return item["kvlistValue"] as JSONObject;
159
+ }
160
+ if (item["kvlist_value"]) {
161
+ return item["kvlist_value"] as JSONObject;
162
+ }
163
+ if (item["stringValue"]) {
164
+ return item as JSONObject;
165
+ }
166
+ if (item["string_value"]) {
167
+ return item as JSONObject;
168
+ }
169
+ return null;
170
+ })
171
+ .filter(Boolean) as Array<JSONObject>;
172
+ }
173
+
174
+ /**
175
+ * Recursively convert an OTLP value wrapper to a plain JavaScript value.
176
+ * Handles stringValue, intValue, boolValue, kvlistValue, and arrayValue.
177
+ */
178
+ function convertOtlpValue(valueWrapper: JSONObject): unknown {
179
+ // Handle both camelCase (JSON encoding) and snake_case (protobuf via protobufjs)
180
+ if (valueWrapper["stringValue"] !== undefined) {
181
+ return valueWrapper["stringValue"];
182
+ }
183
+ if (valueWrapper["string_value"] !== undefined) {
184
+ return valueWrapper["string_value"];
185
+ }
186
+ if (valueWrapper["intValue"] !== undefined) {
187
+ return Number(valueWrapper["intValue"]);
188
+ }
189
+ if (valueWrapper["int_value"] !== undefined) {
190
+ return Number(valueWrapper["int_value"]);
191
+ }
192
+ if (valueWrapper["boolValue"] !== undefined) {
193
+ return valueWrapper["boolValue"];
194
+ }
195
+ if (valueWrapper["bool_value"] !== undefined) {
196
+ return valueWrapper["bool_value"];
197
+ }
198
+ if (valueWrapper["doubleValue"] !== undefined) {
199
+ return Number(valueWrapper["doubleValue"]);
200
+ }
201
+ if (valueWrapper["double_value"] !== undefined) {
202
+ return Number(valueWrapper["double_value"]);
203
+ }
204
+ if (valueWrapper["kvlistValue"]) {
205
+ return kvListToPlainObject(valueWrapper["kvlistValue"] as JSONObject);
206
+ }
207
+ if (valueWrapper["kvlist_value"]) {
208
+ return kvListToPlainObject(valueWrapper["kvlist_value"] as JSONObject);
209
+ }
210
+ if (valueWrapper["arrayValue"]) {
211
+ return convertOtlpArray(valueWrapper["arrayValue"] as JSONObject);
212
+ }
213
+ if (valueWrapper["array_value"]) {
214
+ return convertOtlpArray(valueWrapper["array_value"] as JSONObject);
215
+ }
216
+ return null;
217
+ }
218
+
219
+ /**
220
+ * Convert an OTLP arrayValue to a plain JavaScript array.
221
+ */
222
+ function convertOtlpArray(arrayValue: JSONObject): Array<unknown> {
223
+ const values: Array<JSONObject> | undefined = arrayValue["values"] as
224
+ | Array<JSONObject>
225
+ | undefined;
226
+ if (!values) {
227
+ return [];
228
+ }
229
+ return values.map((item: JSONObject) => {
230
+ // Each item in arrayValue.values is a value wrapper
231
+ return convertOtlpValue(item);
232
+ });
233
+ }
234
+
235
+ /**
236
+ * Convert an OTLP kvlistValue (nested key-value structure) to a plain
237
+ * JavaScript object. This preserves the full original K8s manifest structure.
238
+ */
239
+ export function kvListToPlainObject(
240
+ kvList: JSONObject | undefined,
241
+ ): Record<string, unknown> {
242
+ const result: Record<string, unknown> = {};
243
+ if (!kvList) {
244
+ return result;
245
+ }
246
+ const values: Array<JSONObject> | undefined = kvList["values"] as
247
+ | Array<JSONObject>
248
+ | undefined;
249
+ if (!values) {
250
+ return result;
251
+ }
252
+ for (const entry of values) {
253
+ const key: string = (entry["key"] as string) || "";
254
+ const val: JSONObject | undefined = entry["value"] as
255
+ | JSONObject
256
+ | undefined;
257
+ if (key && val) {
258
+ result[key] = convertOtlpValue(val);
259
+ }
260
+ }
261
+ return result;
262
+ }
263
+
264
+ /*
265
+ * ============================================================
266
+ * TypeScript interfaces for parsed K8s objects
267
+ * ============================================================
268
+ */
269
+
270
+ export interface KubernetesObjectMetadata {
271
+ name: string;
272
+ namespace: string;
273
+ uid: string;
274
+ creationTimestamp: string;
275
+ labels: Record<string, string>;
276
+ annotations: Record<string, string>;
277
+ ownerReferences: Array<{
278
+ kind: string;
279
+ name: string;
280
+ uid: string;
281
+ }>;
282
+ }
283
+
284
+ export interface KubernetesContainerEnvVar {
285
+ name: string;
286
+ value: string; // Direct value, or description like "<Secret: my-secret/key>"
287
+ }
288
+
289
+ export interface KubernetesContainerPort {
290
+ name: string;
291
+ containerPort: number;
292
+ protocol: string;
293
+ }
294
+
295
+ export interface KubernetesContainerSpec {
296
+ name: string;
297
+ image: string;
298
+ command: Array<string>;
299
+ args: Array<string>;
300
+ env: Array<KubernetesContainerEnvVar>;
301
+ ports: Array<KubernetesContainerPort>;
302
+ resources: {
303
+ requests: Record<string, string>;
304
+ limits: Record<string, string>;
305
+ };
306
+ volumeMounts: Array<{
307
+ name: string;
308
+ mountPath: string;
309
+ readOnly: boolean;
310
+ }>;
311
+ }
312
+
313
+ export interface KubernetesCondition {
314
+ type: string;
315
+ status: string;
316
+ reason: string;
317
+ message: string;
318
+ lastTransitionTime: string;
319
+ }
320
+
321
+ export interface KubernetesContainerStatus {
322
+ name: string;
323
+ ready: boolean;
324
+ restartCount: number;
325
+ state: string;
326
+ reason: string;
327
+ image: string;
328
+ }
329
+
330
+ export interface KubernetesPodObject {
331
+ metadata: KubernetesObjectMetadata;
332
+ spec: {
333
+ containers: Array<KubernetesContainerSpec>;
334
+ initContainers: Array<KubernetesContainerSpec>;
335
+ serviceAccountName: string;
336
+ nodeName: string;
337
+ nodeSelector: Record<string, string>;
338
+ tolerations: Array<{
339
+ key: string;
340
+ operator: string;
341
+ value: string;
342
+ effect: string;
343
+ }>;
344
+ volumes: Array<{
345
+ name: string;
346
+ type: string;
347
+ source: string;
348
+ }>;
349
+ };
350
+ status: {
351
+ phase: string;
352
+ podIP: string;
353
+ hostIP: string;
354
+ qosClass: string;
355
+ conditions: Array<KubernetesCondition>;
356
+ containerStatuses: Array<KubernetesContainerStatus>;
357
+ initContainerStatuses: Array<KubernetesContainerStatus>;
358
+ };
359
+ }
360
+
361
+ export interface KubernetesNodeObject {
362
+ metadata: KubernetesObjectMetadata;
363
+ status: {
364
+ conditions: Array<KubernetesCondition>;
365
+ nodeInfo: {
366
+ osImage: string;
367
+ kernelVersion: string;
368
+ containerRuntimeVersion: string;
369
+ kubeletVersion: string;
370
+ architecture: string;
371
+ operatingSystem: string;
372
+ };
373
+ allocatable: Record<string, string>;
374
+ capacity: Record<string, string>;
375
+ addresses: Array<{ type: string; address: string }>;
376
+ };
377
+ }
378
+
379
+ export interface KubernetesDeploymentObject {
380
+ metadata: KubernetesObjectMetadata;
381
+ spec: {
382
+ replicas: number;
383
+ strategy: string;
384
+ selector: Record<string, string>;
385
+ };
386
+ status: {
387
+ replicas: number;
388
+ readyReplicas: number;
389
+ availableReplicas: number;
390
+ unavailableReplicas: number;
391
+ conditions: Array<KubernetesCondition>;
392
+ };
393
+ }
394
+
395
+ export interface KubernetesStatefulSetObject {
396
+ metadata: KubernetesObjectMetadata;
397
+ spec: {
398
+ replicas: number;
399
+ serviceName: string;
400
+ podManagementPolicy: string;
401
+ updateStrategy: string;
402
+ };
403
+ status: {
404
+ replicas: number;
405
+ readyReplicas: number;
406
+ currentReplicas: number;
407
+ };
408
+ }
409
+
410
+ export interface KubernetesDaemonSetObject {
411
+ metadata: KubernetesObjectMetadata;
412
+ spec: {
413
+ updateStrategy: string;
414
+ };
415
+ status: {
416
+ desiredNumberScheduled: number;
417
+ currentNumberScheduled: number;
418
+ numberReady: number;
419
+ numberMisscheduled: number;
420
+ numberAvailable: number;
421
+ };
422
+ }
423
+
424
+ export interface KubernetesJobObject {
425
+ metadata: KubernetesObjectMetadata;
426
+ spec: {
427
+ completions: number;
428
+ parallelism: number;
429
+ backoffLimit: number;
430
+ };
431
+ status: {
432
+ active: number;
433
+ succeeded: number;
434
+ failed: number;
435
+ startTime: string;
436
+ completionTime: string;
437
+ conditions: Array<KubernetesCondition>;
438
+ };
439
+ }
440
+
441
+ export interface KubernetesCronJobObject {
442
+ metadata: KubernetesObjectMetadata;
443
+ spec: {
444
+ schedule: string;
445
+ suspend: boolean;
446
+ concurrencyPolicy: string;
447
+ successfulJobsHistoryLimit: number;
448
+ failedJobsHistoryLimit: number;
449
+ };
450
+ status: {
451
+ lastScheduleTime: string;
452
+ activeCount: number;
453
+ };
454
+ }
455
+
456
+ export interface KubernetesNamespaceObject {
457
+ metadata: KubernetesObjectMetadata;
458
+ status: {
459
+ phase: string;
460
+ };
461
+ }
462
+
463
+ export interface KubernetesPVCObject {
464
+ metadata: KubernetesObjectMetadata;
465
+ spec: {
466
+ accessModes: Array<string>;
467
+ storageClassName: string;
468
+ volumeName: string;
469
+ resources: {
470
+ requests: {
471
+ storage: string;
472
+ };
473
+ };
474
+ };
475
+ status: {
476
+ phase: string; // Bound, Pending, Lost
477
+ capacity: {
478
+ storage: string;
479
+ };
480
+ };
481
+ }
482
+
483
+ export interface KubernetesPVObject {
484
+ metadata: KubernetesObjectMetadata;
485
+ spec: {
486
+ capacity: {
487
+ storage: string;
488
+ };
489
+ accessModes: Array<string>;
490
+ storageClassName: string;
491
+ persistentVolumeReclaimPolicy: string;
492
+ claimRef: {
493
+ name: string;
494
+ namespace: string;
495
+ };
496
+ };
497
+ status: {
498
+ phase: string; // Available, Bound, Released, Failed
499
+ };
500
+ }
501
+
502
+ export interface KubernetesHPAMetricSpec {
503
+ type: string;
504
+ resourceName: string;
505
+ targetType: string;
506
+ targetValue: string;
507
+ }
508
+
509
+ export interface KubernetesHPACondition {
510
+ type: string;
511
+ status: string;
512
+ reason: string;
513
+ message: string;
514
+ lastTransitionTime: string;
515
+ }
516
+
517
+ export interface KubernetesHPAObject {
518
+ metadata: KubernetesObjectMetadata;
519
+ spec: {
520
+ minReplicas: number;
521
+ maxReplicas: number;
522
+ scaleTargetRef: {
523
+ kind: string;
524
+ name: string;
525
+ };
526
+ metrics: Array<KubernetesHPAMetricSpec>;
527
+ };
528
+ status: {
529
+ currentReplicas: number;
530
+ desiredReplicas: number;
531
+ conditions: Array<KubernetesHPACondition>;
532
+ };
533
+ }
534
+
535
+ export interface KubernetesVPAContainerRecommendation {
536
+ containerName: string;
537
+ target: Record<string, string>;
538
+ lowerBound: Record<string, string>;
539
+ upperBound: Record<string, string>;
540
+ }
541
+
542
+ export interface KubernetesVPAObject {
543
+ metadata: KubernetesObjectMetadata;
544
+ spec: {
545
+ targetRef: {
546
+ kind: string;
547
+ name: string;
548
+ };
549
+ updatePolicy: {
550
+ updateMode: string;
551
+ };
552
+ resourcePolicy: string;
553
+ };
554
+ status: {
555
+ recommendation: {
556
+ containerRecommendations: Array<KubernetesVPAContainerRecommendation>;
557
+ };
558
+ };
559
+ }
560
+
561
+ /*
562
+ * ============================================================
563
+ * Parsers
564
+ * ============================================================
565
+ */
566
+
567
+ function parseMetadata(kvList: JSONObject): KubernetesObjectMetadata {
568
+ const labelsKvList: string | JSONObject | null = getKvValue(kvList, "labels");
569
+ const annotationsKvList: string | JSONObject | null = getKvValue(
570
+ kvList,
571
+ "annotations",
572
+ );
573
+ const ownerRefsArrayValue: string | JSONObject | null = getKvValue(
574
+ kvList,
575
+ "ownerReferences",
576
+ );
577
+
578
+ const ownerReferences: Array<{
579
+ kind: string;
580
+ name: string;
581
+ uid: string;
582
+ }> = [];
583
+ if (ownerRefsArrayValue && typeof ownerRefsArrayValue !== "string") {
584
+ const refs: Array<JSONObject> = getArrayValues(ownerRefsArrayValue);
585
+ for (const ref of refs) {
586
+ ownerReferences.push({
587
+ kind: getKvStringValue(ref, "kind"),
588
+ name: getKvStringValue(ref, "name"),
589
+ uid: getKvStringValue(ref, "uid"),
590
+ });
591
+ }
592
+ }
593
+
594
+ return {
595
+ name: getKvStringValue(kvList, "name"),
596
+ namespace: getKvStringValue(kvList, "namespace"),
597
+ uid: getKvStringValue(kvList, "uid"),
598
+ creationTimestamp: getKvStringValue(kvList, "creationTimestamp"),
599
+ labels:
600
+ labelsKvList && typeof labelsKvList !== "string"
601
+ ? getKvListAsRecord(labelsKvList)
602
+ : {},
603
+ annotations:
604
+ annotationsKvList && typeof annotationsKvList !== "string"
605
+ ? getKvListAsRecord(annotationsKvList)
606
+ : {},
607
+ ownerReferences,
608
+ };
609
+ }
610
+
611
+ function parseContainerEnv(
612
+ envArrayValue: JSONObject | null,
613
+ ): Array<KubernetesContainerEnvVar> {
614
+ if (!envArrayValue || typeof envArrayValue === "string") {
615
+ return [];
616
+ }
617
+ const envItems: Array<JSONObject> = getArrayValues(envArrayValue);
618
+ const result: Array<KubernetesContainerEnvVar> = [];
619
+
620
+ for (const envKvList of envItems) {
621
+ const name: string = getKvStringValue(envKvList, "name");
622
+ const directValue: string = getKvStringValue(envKvList, "value");
623
+
624
+ if (directValue) {
625
+ result.push({ name, value: directValue });
626
+ } else {
627
+ // Check for valueFrom (secretKeyRef, configMapKeyRef, fieldRef)
628
+ const valueFrom: string | JSONObject | null = getKvValue(
629
+ envKvList,
630
+ "valueFrom",
631
+ );
632
+ if (valueFrom && typeof valueFrom !== "string") {
633
+ const secretRef: string | JSONObject | null = getKvValue(
634
+ valueFrom,
635
+ "secretKeyRef",
636
+ );
637
+ const configMapRef: string | JSONObject | null = getKvValue(
638
+ valueFrom,
639
+ "configMapKeyRef",
640
+ );
641
+ const fieldRef: string | JSONObject | null = getKvValue(
642
+ valueFrom,
643
+ "fieldRef",
644
+ );
645
+
646
+ if (secretRef && typeof secretRef !== "string") {
647
+ const secretName: string = getKvStringValue(secretRef, "name");
648
+ const secretKey: string = getKvStringValue(secretRef, "key");
649
+ result.push({
650
+ name,
651
+ value: `<Secret: ${secretName}/${secretKey}>`,
652
+ });
653
+ } else if (configMapRef && typeof configMapRef !== "string") {
654
+ const cmName: string = getKvStringValue(configMapRef, "name");
655
+ const cmKey: string = getKvStringValue(configMapRef, "key");
656
+ result.push({
657
+ name,
658
+ value: `<ConfigMap: ${cmName}/${cmKey}>`,
659
+ });
660
+ } else if (fieldRef && typeof fieldRef !== "string") {
661
+ const fieldPath: string = getKvStringValue(fieldRef, "fieldPath");
662
+ result.push({ name, value: `<FieldRef: ${fieldPath}>` });
663
+ } else {
664
+ result.push({ name, value: "<from valueFrom>" });
665
+ }
666
+ } else {
667
+ result.push({ name, value: directValue || "" });
668
+ }
669
+ }
670
+ }
671
+ return result;
672
+ }
673
+
674
+ function parseContainerSpec(kvList: JSONObject): KubernetesContainerSpec {
675
+ const portsArrayValue: string | JSONObject | null = getKvValue(
676
+ kvList,
677
+ "ports",
678
+ );
679
+ const ports: Array<KubernetesContainerPort> = [];
680
+ if (portsArrayValue && typeof portsArrayValue !== "string") {
681
+ const portItems: Array<JSONObject> = getArrayValues(portsArrayValue);
682
+ for (const portKv of portItems) {
683
+ ports.push({
684
+ name: getKvStringValue(portKv, "name"),
685
+ containerPort: parseInt(getKvStringValue(portKv, "containerPort")) || 0,
686
+ protocol: getKvStringValue(portKv, "protocol") || "TCP",
687
+ });
688
+ }
689
+ }
690
+
691
+ const envArrayValue: string | JSONObject | null = getKvValue(kvList, "env");
692
+ const env: Array<KubernetesContainerEnvVar> = parseContainerEnv(
693
+ envArrayValue as JSONObject | null,
694
+ );
695
+
696
+ const volumeMountsArray: string | JSONObject | null = getKvValue(
697
+ kvList,
698
+ "volumeMounts",
699
+ );
700
+ const volumeMounts: Array<{
701
+ name: string;
702
+ mountPath: string;
703
+ readOnly: boolean;
704
+ }> = [];
705
+ if (volumeMountsArray && typeof volumeMountsArray !== "string") {
706
+ const mountItems: Array<JSONObject> = getArrayValues(volumeMountsArray);
707
+ for (const mountKv of mountItems) {
708
+ volumeMounts.push({
709
+ name: getKvStringValue(mountKv, "name"),
710
+ mountPath: getKvStringValue(mountKv, "mountPath"),
711
+ readOnly: getKvStringValue(mountKv, "readOnly") === "true",
712
+ });
713
+ }
714
+ }
715
+
716
+ const resourcesKv: string | JSONObject | null = getKvValue(
717
+ kvList,
718
+ "resources",
719
+ );
720
+ let requests: Record<string, string> = {};
721
+ let limits: Record<string, string> = {};
722
+ if (resourcesKv && typeof resourcesKv !== "string") {
723
+ const reqKv: string | JSONObject | null = getKvValue(
724
+ resourcesKv,
725
+ "requests",
726
+ );
727
+ const limKv: string | JSONObject | null = getKvValue(resourcesKv, "limits");
728
+ if (reqKv && typeof reqKv !== "string") {
729
+ requests = getKvListAsRecord(reqKv);
730
+ }
731
+ if (limKv && typeof limKv !== "string") {
732
+ limits = getKvListAsRecord(limKv);
733
+ }
734
+ }
735
+
736
+ const commandArray: string | JSONObject | null = getKvValue(
737
+ kvList,
738
+ "command",
739
+ );
740
+ const command: Array<string> = [];
741
+ if (commandArray && typeof commandArray !== "string") {
742
+ const cmdValues: Array<JSONObject> =
743
+ (commandArray["values"] as Array<JSONObject>) || [];
744
+ for (const v of cmdValues) {
745
+ if (v["stringValue"]) {
746
+ command.push(v["stringValue"] as string);
747
+ }
748
+ }
749
+ }
750
+
751
+ const argsArray: string | JSONObject | null = getKvValue(kvList, "args");
752
+ const args: Array<string> = [];
753
+ if (argsArray && typeof argsArray !== "string") {
754
+ const argValues: Array<JSONObject> =
755
+ (argsArray["values"] as Array<JSONObject>) || [];
756
+ for (const v of argValues) {
757
+ if (v["stringValue"]) {
758
+ args.push(v["stringValue"] as string);
759
+ }
760
+ }
761
+ }
762
+
763
+ return {
764
+ name: getKvStringValue(kvList, "name"),
765
+ image: getKvStringValue(kvList, "image"),
766
+ command,
767
+ args,
768
+ env,
769
+ ports,
770
+ resources: { requests, limits },
771
+ volumeMounts,
772
+ };
773
+ }
774
+
775
+ function parseConditions(
776
+ conditionsArrayValue: JSONObject | null,
777
+ ): Array<KubernetesCondition> {
778
+ if (!conditionsArrayValue) {
779
+ return [];
780
+ }
781
+ const items: Array<JSONObject> = getArrayValues(conditionsArrayValue);
782
+ return items.map((kvList: JSONObject) => {
783
+ return {
784
+ type: getKvStringValue(kvList, "type"),
785
+ status: getKvStringValue(kvList, "status"),
786
+ reason: getKvStringValue(kvList, "reason"),
787
+ message: getKvStringValue(kvList, "message"),
788
+ lastTransitionTime: getKvStringValue(kvList, "lastTransitionTime"),
789
+ };
790
+ });
791
+ }
792
+
793
+ function parseContainerStatuses(
794
+ statusesArrayValue: JSONObject | null,
795
+ ): Array<KubernetesContainerStatus> {
796
+ if (!statusesArrayValue) {
797
+ return [];
798
+ }
799
+ const items: Array<JSONObject> = getArrayValues(statusesArrayValue);
800
+ return items.map((kvList: JSONObject) => {
801
+ // state is a kvlist with one key (running/waiting/terminated)
802
+ const stateKv: string | JSONObject | null = getKvValue(kvList, "state");
803
+ let state: string = "Unknown";
804
+ let reason: string = "";
805
+ if (stateKv && typeof stateKv !== "string") {
806
+ const stateValues: Array<JSONObject> | undefined = stateKv["values"] as
807
+ | Array<JSONObject>
808
+ | undefined;
809
+ if (stateValues && stateValues.length > 0 && stateValues[0]) {
810
+ state = (stateValues[0]["key"] as string) || "Unknown";
811
+ // Extract reason from the state's nested kvlist value (e.g., waiting -> { reason: "CrashLoopBackOff" })
812
+ const stateDetail: JSONObject | undefined = stateValues[0]["value"] as
813
+ | JSONObject
814
+ | undefined;
815
+ if (stateDetail && stateDetail["kvlistValue"]) {
816
+ reason = getKvStringValue(
817
+ stateDetail["kvlistValue"] as JSONObject,
818
+ "reason",
819
+ );
820
+ }
821
+ }
822
+ }
823
+
824
+ return {
825
+ name: getKvStringValue(kvList, "name"),
826
+ ready: getKvStringValue(kvList, "ready") === "true",
827
+ restartCount: parseInt(getKvStringValue(kvList, "restartCount")) || 0,
828
+ state,
829
+ reason,
830
+ image: getKvStringValue(kvList, "image"),
831
+ };
832
+ });
833
+ }
834
+
835
+ /**
836
+ * Parse a raw OTLP log body into a Pod object.
837
+ * The body format: { kvlistValue: { values: [{ key: "type", value: ... }, { key: "object", value: { kvlistValue: ... } }] } }
838
+ */
839
+ export function parsePodObject(
840
+ objectKvList: JSONObject,
841
+ ): KubernetesPodObject | null {
842
+ try {
843
+ const metadataKv: string | JSONObject | null = getKvValue(
844
+ objectKvList,
845
+ "metadata",
846
+ );
847
+ if (!metadataKv || typeof metadataKv === "string") {
848
+ return null;
849
+ }
850
+ const metadata: KubernetesObjectMetadata = parseMetadata(metadataKv);
851
+
852
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
853
+ const statusKv: string | JSONObject | null = getKvValue(
854
+ objectKvList,
855
+ "status",
856
+ );
857
+
858
+ // Parse containers
859
+ const containers: Array<KubernetesContainerSpec> = [];
860
+ const initContainers: Array<KubernetesContainerSpec> = [];
861
+
862
+ if (specKv && typeof specKv !== "string") {
863
+ const containersArray: string | JSONObject | null = getKvValue(
864
+ specKv,
865
+ "containers",
866
+ );
867
+ if (containersArray && typeof containersArray !== "string") {
868
+ const containerItems: Array<JSONObject> =
869
+ getArrayValues(containersArray);
870
+ for (const cKv of containerItems) {
871
+ containers.push(parseContainerSpec(cKv));
872
+ }
873
+ }
874
+
875
+ const initContainersArray: string | JSONObject | null = getKvValue(
876
+ specKv,
877
+ "initContainers",
878
+ );
879
+ if (initContainersArray && typeof initContainersArray !== "string") {
880
+ const initItems: Array<JSONObject> =
881
+ getArrayValues(initContainersArray);
882
+ for (const cKv of initItems) {
883
+ initContainers.push(parseContainerSpec(cKv));
884
+ }
885
+ }
886
+ }
887
+
888
+ // Parse volumes
889
+ const volumes: Array<{ name: string; type: string; source: string }> = [];
890
+ if (specKv && typeof specKv !== "string") {
891
+ const volumesArray: string | JSONObject | null = getKvValue(
892
+ specKv,
893
+ "volumes",
894
+ );
895
+ if (volumesArray && typeof volumesArray !== "string") {
896
+ const volItems: Array<JSONObject> = getArrayValues(volumesArray);
897
+ for (const volKv of volItems) {
898
+ const name: string = getKvStringValue(volKv, "name");
899
+ // Volume type is one of: configMap, secret, emptyDir, hostPath, persistentVolumeClaim, etc.
900
+ const volValues: Array<JSONObject> | undefined = volKv["values"] as
901
+ | Array<JSONObject>
902
+ | undefined;
903
+ let volType: string = "unknown";
904
+ let volSource: string = "";
905
+ if (volValues) {
906
+ for (const v of volValues) {
907
+ const k: string = (v["key"] as string) || "";
908
+ if (k !== "name") {
909
+ volType = k;
910
+ const innerVal: JSONObject | undefined = v["value"] as
911
+ | JSONObject
912
+ | undefined;
913
+ if (innerVal && innerVal["kvlistValue"]) {
914
+ const innerKv: JSONObject = innerVal[
915
+ "kvlistValue"
916
+ ] as JSONObject;
917
+ volSource =
918
+ getKvStringValue(innerKv, "name") ||
919
+ getKvStringValue(innerKv, "path") ||
920
+ getKvStringValue(innerKv, "claimName") ||
921
+ volType;
922
+ }
923
+ break;
924
+ }
925
+ }
926
+ }
927
+ volumes.push({ name, type: volType, source: volSource });
928
+ }
929
+ }
930
+ }
931
+
932
+ // Parse tolerations
933
+ const tolerations: Array<{
934
+ key: string;
935
+ operator: string;
936
+ value: string;
937
+ effect: string;
938
+ }> = [];
939
+ if (specKv && typeof specKv !== "string") {
940
+ const tolArray: string | JSONObject | null = getKvValue(
941
+ specKv,
942
+ "tolerations",
943
+ );
944
+ if (tolArray && typeof tolArray !== "string") {
945
+ const tolItems: Array<JSONObject> = getArrayValues(tolArray);
946
+ for (const tolKv of tolItems) {
947
+ tolerations.push({
948
+ key: getKvStringValue(tolKv, "key"),
949
+ operator: getKvStringValue(tolKv, "operator"),
950
+ value: getKvStringValue(tolKv, "value"),
951
+ effect: getKvStringValue(tolKv, "effect"),
952
+ });
953
+ }
954
+ }
955
+ }
956
+
957
+ // Parse nodeSelector
958
+ let nodeSelector: Record<string, string> = {};
959
+ if (specKv && typeof specKv !== "string") {
960
+ const nsKv: string | JSONObject | null = getKvValue(
961
+ specKv,
962
+ "nodeSelector",
963
+ );
964
+ if (nsKv && typeof nsKv !== "string") {
965
+ nodeSelector = getKvListAsRecord(nsKv);
966
+ }
967
+ }
968
+
969
+ // Parse status
970
+ let phase: string = "";
971
+ let podIP: string = "";
972
+ let hostIP: string = "";
973
+ let qosClass: string = "";
974
+ let conditions: Array<KubernetesCondition> = [];
975
+ let containerStatuses: Array<KubernetesContainerStatus> = [];
976
+ let initContainerStatuses: Array<KubernetesContainerStatus> = [];
977
+
978
+ if (statusKv && typeof statusKv !== "string") {
979
+ phase = getKvStringValue(statusKv, "phase");
980
+ podIP = getKvStringValue(statusKv, "podIP");
981
+ hostIP = getKvStringValue(statusKv, "hostIP");
982
+ qosClass = getKvStringValue(statusKv, "qosClass");
983
+
984
+ const condArray: string | JSONObject | null = getKvValue(
985
+ statusKv,
986
+ "conditions",
987
+ );
988
+ conditions = parseConditions(condArray as JSONObject | null);
989
+
990
+ const csArray: string | JSONObject | null = getKvValue(
991
+ statusKv,
992
+ "containerStatuses",
993
+ );
994
+ containerStatuses = parseContainerStatuses(csArray as JSONObject | null);
995
+
996
+ const icsArray: string | JSONObject | null = getKvValue(
997
+ statusKv,
998
+ "initContainerStatuses",
999
+ );
1000
+ initContainerStatuses = parseContainerStatuses(
1001
+ icsArray as JSONObject | null,
1002
+ );
1003
+ }
1004
+
1005
+ return {
1006
+ metadata,
1007
+ spec: {
1008
+ containers,
1009
+ initContainers,
1010
+ serviceAccountName: specKv
1011
+ ? getKvStringValue(specKv as JSONObject, "serviceAccountName")
1012
+ : "",
1013
+ nodeName: specKv
1014
+ ? getKvStringValue(specKv as JSONObject, "nodeName")
1015
+ : "",
1016
+ nodeSelector,
1017
+ tolerations,
1018
+ volumes,
1019
+ },
1020
+ status: {
1021
+ phase,
1022
+ podIP,
1023
+ hostIP,
1024
+ qosClass,
1025
+ conditions,
1026
+ containerStatuses,
1027
+ initContainerStatuses,
1028
+ },
1029
+ };
1030
+ } catch {
1031
+ return null;
1032
+ }
1033
+ }
1034
+
1035
+ export function parseNodeObject(
1036
+ objectKvList: JSONObject,
1037
+ ): KubernetesNodeObject | null {
1038
+ try {
1039
+ const metadataKv: string | JSONObject | null = getKvValue(
1040
+ objectKvList,
1041
+ "metadata",
1042
+ );
1043
+ if (!metadataKv || typeof metadataKv === "string") {
1044
+ return null;
1045
+ }
1046
+
1047
+ const statusKv: string | JSONObject | null = getKvValue(
1048
+ objectKvList,
1049
+ "status",
1050
+ );
1051
+
1052
+ let conditions: Array<KubernetesCondition> = [];
1053
+ let nodeInfo: KubernetesNodeObject["status"]["nodeInfo"] = {
1054
+ osImage: "",
1055
+ kernelVersion: "",
1056
+ containerRuntimeVersion: "",
1057
+ kubeletVersion: "",
1058
+ architecture: "",
1059
+ operatingSystem: "",
1060
+ };
1061
+ let allocatable: Record<string, string> = {};
1062
+ let capacity: Record<string, string> = {};
1063
+ let addresses: Array<{ type: string; address: string }> = [];
1064
+
1065
+ if (statusKv && typeof statusKv !== "string") {
1066
+ const condArray: string | JSONObject | null = getKvValue(
1067
+ statusKv,
1068
+ "conditions",
1069
+ );
1070
+ conditions = parseConditions(condArray as JSONObject | null);
1071
+
1072
+ const nodeInfoKv: string | JSONObject | null = getKvValue(
1073
+ statusKv,
1074
+ "nodeInfo",
1075
+ );
1076
+ if (nodeInfoKv && typeof nodeInfoKv !== "string") {
1077
+ nodeInfo = {
1078
+ osImage: getKvStringValue(nodeInfoKv, "osImage"),
1079
+ kernelVersion: getKvStringValue(nodeInfoKv, "kernelVersion"),
1080
+ containerRuntimeVersion: getKvStringValue(
1081
+ nodeInfoKv,
1082
+ "containerRuntimeVersion",
1083
+ ),
1084
+ kubeletVersion: getKvStringValue(nodeInfoKv, "kubeletVersion"),
1085
+ architecture: getKvStringValue(nodeInfoKv, "architecture"),
1086
+ operatingSystem: getKvStringValue(nodeInfoKv, "operatingSystem"),
1087
+ };
1088
+ }
1089
+
1090
+ const allocKv: string | JSONObject | null = getKvValue(
1091
+ statusKv,
1092
+ "allocatable",
1093
+ );
1094
+ if (allocKv && typeof allocKv !== "string") {
1095
+ allocatable = getKvListAsRecord(allocKv);
1096
+ }
1097
+
1098
+ const capKv: string | JSONObject | null = getKvValue(
1099
+ statusKv,
1100
+ "capacity",
1101
+ );
1102
+ if (capKv && typeof capKv !== "string") {
1103
+ capacity = getKvListAsRecord(capKv);
1104
+ }
1105
+
1106
+ const addrArray: string | JSONObject | null = getKvValue(
1107
+ statusKv,
1108
+ "addresses",
1109
+ );
1110
+ if (addrArray && typeof addrArray !== "string") {
1111
+ const addrItems: Array<JSONObject> = getArrayValues(addrArray);
1112
+ addresses = addrItems.map((a: JSONObject) => {
1113
+ return {
1114
+ type: getKvStringValue(a, "type"),
1115
+ address: getKvStringValue(a, "address"),
1116
+ };
1117
+ });
1118
+ }
1119
+ }
1120
+
1121
+ return {
1122
+ metadata: parseMetadata(metadataKv),
1123
+ status: {
1124
+ conditions,
1125
+ nodeInfo,
1126
+ allocatable,
1127
+ capacity,
1128
+ addresses,
1129
+ },
1130
+ };
1131
+ } catch {
1132
+ return null;
1133
+ }
1134
+ }
1135
+
1136
+ export function parseDeploymentObject(
1137
+ objectKvList: JSONObject,
1138
+ ): KubernetesDeploymentObject | null {
1139
+ try {
1140
+ const metadataKv: string | JSONObject | null = getKvValue(
1141
+ objectKvList,
1142
+ "metadata",
1143
+ );
1144
+ if (!metadataKv || typeof metadataKv === "string") {
1145
+ return null;
1146
+ }
1147
+
1148
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1149
+ const statusKv: string | JSONObject | null = getKvValue(
1150
+ objectKvList,
1151
+ "status",
1152
+ );
1153
+
1154
+ let replicas: number = 0;
1155
+ let strategy: string = "";
1156
+ let selector: Record<string, string> = {};
1157
+ if (specKv && typeof specKv !== "string") {
1158
+ replicas = parseInt(getKvStringValue(specKv, "replicas")) || 0;
1159
+ const strategyKv: string | JSONObject | null = getKvValue(
1160
+ specKv,
1161
+ "strategy",
1162
+ );
1163
+ if (strategyKv && typeof strategyKv !== "string") {
1164
+ strategy = getKvStringValue(strategyKv, "type");
1165
+ }
1166
+ const selectorKv: string | JSONObject | null = getKvValue(
1167
+ specKv,
1168
+ "selector",
1169
+ );
1170
+ if (selectorKv && typeof selectorKv !== "string") {
1171
+ const matchLabelsKv: string | JSONObject | null = getKvValue(
1172
+ selectorKv,
1173
+ "matchLabels",
1174
+ );
1175
+ if (matchLabelsKv && typeof matchLabelsKv !== "string") {
1176
+ selector = getKvListAsRecord(matchLabelsKv);
1177
+ }
1178
+ }
1179
+ }
1180
+
1181
+ let statusReplicas: number = 0;
1182
+ let readyReplicas: number = 0;
1183
+ let availableReplicas: number = 0;
1184
+ let unavailableReplicas: number = 0;
1185
+ let conditions: Array<KubernetesCondition> = [];
1186
+ if (statusKv && typeof statusKv !== "string") {
1187
+ statusReplicas = parseInt(getKvStringValue(statusKv, "replicas")) || 0;
1188
+ readyReplicas =
1189
+ parseInt(getKvStringValue(statusKv, "readyReplicas")) || 0;
1190
+ availableReplicas =
1191
+ parseInt(getKvStringValue(statusKv, "availableReplicas")) || 0;
1192
+ unavailableReplicas =
1193
+ parseInt(getKvStringValue(statusKv, "unavailableReplicas")) || 0;
1194
+ const condArray: string | JSONObject | null = getKvValue(
1195
+ statusKv,
1196
+ "conditions",
1197
+ );
1198
+ conditions = parseConditions(condArray as JSONObject | null);
1199
+ }
1200
+
1201
+ return {
1202
+ metadata: parseMetadata(metadataKv),
1203
+ spec: { replicas, strategy, selector },
1204
+ status: {
1205
+ replicas: statusReplicas,
1206
+ readyReplicas,
1207
+ availableReplicas,
1208
+ unavailableReplicas,
1209
+ conditions,
1210
+ },
1211
+ };
1212
+ } catch {
1213
+ return null;
1214
+ }
1215
+ }
1216
+
1217
+ export function parseStatefulSetObject(
1218
+ objectKvList: JSONObject,
1219
+ ): KubernetesStatefulSetObject | null {
1220
+ try {
1221
+ const metadataKv: string | JSONObject | null = getKvValue(
1222
+ objectKvList,
1223
+ "metadata",
1224
+ );
1225
+ if (!metadataKv || typeof metadataKv === "string") {
1226
+ return null;
1227
+ }
1228
+
1229
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1230
+ const statusKv: string | JSONObject | null = getKvValue(
1231
+ objectKvList,
1232
+ "status",
1233
+ );
1234
+
1235
+ let replicas: number = 0;
1236
+ let serviceName: string = "";
1237
+ let podManagementPolicy: string = "";
1238
+ let updateStrategy: string = "";
1239
+ if (specKv && typeof specKv !== "string") {
1240
+ replicas = parseInt(getKvStringValue(specKv, "replicas")) || 0;
1241
+ serviceName = getKvStringValue(specKv, "serviceName");
1242
+ podManagementPolicy = getKvStringValue(specKv, "podManagementPolicy");
1243
+ const usKv: string | JSONObject | null = getKvValue(
1244
+ specKv,
1245
+ "updateStrategy",
1246
+ );
1247
+ if (usKv && typeof usKv !== "string") {
1248
+ updateStrategy = getKvStringValue(usKv, "type");
1249
+ }
1250
+ }
1251
+
1252
+ return {
1253
+ metadata: parseMetadata(metadataKv),
1254
+ spec: { replicas, serviceName, podManagementPolicy, updateStrategy },
1255
+ status: {
1256
+ replicas: statusKv
1257
+ ? parseInt(getKvStringValue(statusKv as JSONObject, "replicas")) || 0
1258
+ : 0,
1259
+ readyReplicas: statusKv
1260
+ ? parseInt(
1261
+ getKvStringValue(statusKv as JSONObject, "readyReplicas"),
1262
+ ) || 0
1263
+ : 0,
1264
+ currentReplicas: statusKv
1265
+ ? parseInt(
1266
+ getKvStringValue(statusKv as JSONObject, "currentReplicas"),
1267
+ ) || 0
1268
+ : 0,
1269
+ },
1270
+ };
1271
+ } catch {
1272
+ return null;
1273
+ }
1274
+ }
1275
+
1276
+ export function parseDaemonSetObject(
1277
+ objectKvList: JSONObject,
1278
+ ): KubernetesDaemonSetObject | null {
1279
+ try {
1280
+ const metadataKv: string | JSONObject | null = getKvValue(
1281
+ objectKvList,
1282
+ "metadata",
1283
+ );
1284
+ if (!metadataKv || typeof metadataKv === "string") {
1285
+ return null;
1286
+ }
1287
+
1288
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1289
+ const statusKv: string | JSONObject | null = getKvValue(
1290
+ objectKvList,
1291
+ "status",
1292
+ );
1293
+
1294
+ let updateStrategy: string = "";
1295
+ if (specKv && typeof specKv !== "string") {
1296
+ const usKv: string | JSONObject | null = getKvValue(
1297
+ specKv,
1298
+ "updateStrategy",
1299
+ );
1300
+ if (usKv && typeof usKv !== "string") {
1301
+ updateStrategy = getKvStringValue(usKv, "type");
1302
+ }
1303
+ }
1304
+
1305
+ return {
1306
+ metadata: parseMetadata(metadataKv),
1307
+ spec: { updateStrategy },
1308
+ status: {
1309
+ desiredNumberScheduled: statusKv
1310
+ ? parseInt(
1311
+ getKvStringValue(
1312
+ statusKv as JSONObject,
1313
+ "desiredNumberScheduled",
1314
+ ),
1315
+ ) || 0
1316
+ : 0,
1317
+ currentNumberScheduled: statusKv
1318
+ ? parseInt(
1319
+ getKvStringValue(
1320
+ statusKv as JSONObject,
1321
+ "currentNumberScheduled",
1322
+ ),
1323
+ ) || 0
1324
+ : 0,
1325
+ numberReady: statusKv
1326
+ ? parseInt(getKvStringValue(statusKv as JSONObject, "numberReady")) ||
1327
+ 0
1328
+ : 0,
1329
+ numberMisscheduled: statusKv
1330
+ ? parseInt(
1331
+ getKvStringValue(statusKv as JSONObject, "numberMisscheduled"),
1332
+ ) || 0
1333
+ : 0,
1334
+ numberAvailable: statusKv
1335
+ ? parseInt(
1336
+ getKvStringValue(statusKv as JSONObject, "numberAvailable"),
1337
+ ) || 0
1338
+ : 0,
1339
+ },
1340
+ };
1341
+ } catch {
1342
+ return null;
1343
+ }
1344
+ }
1345
+
1346
+ export function parseJobObject(
1347
+ objectKvList: JSONObject,
1348
+ ): KubernetesJobObject | null {
1349
+ try {
1350
+ const metadataKv: string | JSONObject | null = getKvValue(
1351
+ objectKvList,
1352
+ "metadata",
1353
+ );
1354
+ if (!metadataKv || typeof metadataKv === "string") {
1355
+ return null;
1356
+ }
1357
+
1358
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1359
+ const statusKv: string | JSONObject | null = getKvValue(
1360
+ objectKvList,
1361
+ "status",
1362
+ );
1363
+
1364
+ return {
1365
+ metadata: parseMetadata(metadataKv),
1366
+ spec: {
1367
+ completions: specKv
1368
+ ? parseInt(getKvStringValue(specKv as JSONObject, "completions")) || 0
1369
+ : 0,
1370
+ parallelism: specKv
1371
+ ? parseInt(getKvStringValue(specKv as JSONObject, "parallelism")) || 0
1372
+ : 0,
1373
+ backoffLimit: specKv
1374
+ ? parseInt(getKvStringValue(specKv as JSONObject, "backoffLimit")) ||
1375
+ 0
1376
+ : 0,
1377
+ },
1378
+ status: {
1379
+ active: statusKv
1380
+ ? parseInt(getKvStringValue(statusKv as JSONObject, "active")) || 0
1381
+ : 0,
1382
+ succeeded: statusKv
1383
+ ? parseInt(getKvStringValue(statusKv as JSONObject, "succeeded")) || 0
1384
+ : 0,
1385
+ failed: statusKv
1386
+ ? parseInt(getKvStringValue(statusKv as JSONObject, "failed")) || 0
1387
+ : 0,
1388
+ startTime: statusKv
1389
+ ? getKvStringValue(statusKv as JSONObject, "startTime")
1390
+ : "",
1391
+ completionTime: statusKv
1392
+ ? getKvStringValue(statusKv as JSONObject, "completionTime")
1393
+ : "",
1394
+ conditions: statusKv
1395
+ ? parseConditions(
1396
+ getKvValue(
1397
+ statusKv as JSONObject,
1398
+ "conditions",
1399
+ ) as JSONObject | null,
1400
+ )
1401
+ : [],
1402
+ },
1403
+ };
1404
+ } catch {
1405
+ return null;
1406
+ }
1407
+ }
1408
+
1409
+ export function parseCronJobObject(
1410
+ objectKvList: JSONObject,
1411
+ ): KubernetesCronJobObject | null {
1412
+ try {
1413
+ const metadataKv: string | JSONObject | null = getKvValue(
1414
+ objectKvList,
1415
+ "metadata",
1416
+ );
1417
+ if (!metadataKv || typeof metadataKv === "string") {
1418
+ return null;
1419
+ }
1420
+
1421
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1422
+ const statusKv: string | JSONObject | null = getKvValue(
1423
+ objectKvList,
1424
+ "status",
1425
+ );
1426
+
1427
+ return {
1428
+ metadata: parseMetadata(metadataKv),
1429
+ spec: {
1430
+ schedule: specKv
1431
+ ? getKvStringValue(specKv as JSONObject, "schedule")
1432
+ : "",
1433
+ suspend: specKv
1434
+ ? getKvStringValue(specKv as JSONObject, "suspend") === "true"
1435
+ : false,
1436
+ concurrencyPolicy: specKv
1437
+ ? getKvStringValue(specKv as JSONObject, "concurrencyPolicy")
1438
+ : "",
1439
+ successfulJobsHistoryLimit: specKv
1440
+ ? parseInt(
1441
+ getKvStringValue(
1442
+ specKv as JSONObject,
1443
+ "successfulJobsHistoryLimit",
1444
+ ),
1445
+ ) || 0
1446
+ : 0,
1447
+ failedJobsHistoryLimit: specKv
1448
+ ? parseInt(
1449
+ getKvStringValue(specKv as JSONObject, "failedJobsHistoryLimit"),
1450
+ ) || 0
1451
+ : 0,
1452
+ },
1453
+ status: {
1454
+ lastScheduleTime: statusKv
1455
+ ? getKvStringValue(statusKv as JSONObject, "lastScheduleTime")
1456
+ : "",
1457
+ activeCount: statusKv
1458
+ ? parseInt(getKvStringValue(statusKv as JSONObject, "active")) || 0
1459
+ : 0,
1460
+ },
1461
+ };
1462
+ } catch {
1463
+ return null;
1464
+ }
1465
+ }
1466
+
1467
+ export function parseNamespaceObject(
1468
+ objectKvList: JSONObject,
1469
+ ): KubernetesNamespaceObject | null {
1470
+ try {
1471
+ const metadataKv: string | JSONObject | null = getKvValue(
1472
+ objectKvList,
1473
+ "metadata",
1474
+ );
1475
+ if (!metadataKv || typeof metadataKv === "string") {
1476
+ return null;
1477
+ }
1478
+
1479
+ const statusKv: string | JSONObject | null = getKvValue(
1480
+ objectKvList,
1481
+ "status",
1482
+ );
1483
+
1484
+ return {
1485
+ metadata: parseMetadata(metadataKv),
1486
+ status: {
1487
+ phase: statusKv
1488
+ ? getKvStringValue(statusKv as JSONObject, "phase")
1489
+ : "",
1490
+ },
1491
+ };
1492
+ } catch {
1493
+ return null;
1494
+ }
1495
+ }
1496
+
1497
+ export function parsePVCObject(
1498
+ objectKvList: JSONObject,
1499
+ ): KubernetesPVCObject | null {
1500
+ try {
1501
+ const metadataKv: string | JSONObject | null = getKvValue(
1502
+ objectKvList,
1503
+ "metadata",
1504
+ );
1505
+ if (!metadataKv || typeof metadataKv === "string") {
1506
+ return null;
1507
+ }
1508
+
1509
+ const metadata: KubernetesObjectMetadata = parseMetadata(metadataKv);
1510
+ if (!metadata.name) {
1511
+ return null;
1512
+ }
1513
+
1514
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1515
+ const statusKv: string | JSONObject | null = getKvValue(
1516
+ objectKvList,
1517
+ "status",
1518
+ );
1519
+
1520
+ // Parse spec
1521
+ const accessModes: Array<string> = [];
1522
+ let storageClassName: string = "";
1523
+ let volumeName: string = "";
1524
+ let requestsStorage: string = "";
1525
+
1526
+ if (specKv && typeof specKv !== "string") {
1527
+ storageClassName = getKvStringValue(specKv, "storageClassName");
1528
+ volumeName = getKvStringValue(specKv, "volumeName");
1529
+
1530
+ const accessModesArray: string | JSONObject | null = getKvValue(
1531
+ specKv,
1532
+ "accessModes",
1533
+ );
1534
+ if (accessModesArray && typeof accessModesArray !== "string") {
1535
+ const modeValues: Array<JSONObject> =
1536
+ (accessModesArray["values"] as Array<JSONObject>) || [];
1537
+ for (const v of modeValues) {
1538
+ if (v["stringValue"]) {
1539
+ accessModes.push(v["stringValue"] as string);
1540
+ }
1541
+ }
1542
+ }
1543
+
1544
+ const resourcesKv: string | JSONObject | null = getKvValue(
1545
+ specKv,
1546
+ "resources",
1547
+ );
1548
+ if (resourcesKv && typeof resourcesKv !== "string") {
1549
+ requestsStorage = getNestedKvValue(resourcesKv, "requests", "storage");
1550
+ }
1551
+ }
1552
+
1553
+ // Parse status
1554
+ let phase: string = "";
1555
+ let capacityStorage: string = "";
1556
+
1557
+ if (statusKv && typeof statusKv !== "string") {
1558
+ phase = getKvStringValue(statusKv, "phase");
1559
+ capacityStorage = getNestedKvValue(statusKv, "capacity", "storage");
1560
+ }
1561
+
1562
+ return {
1563
+ metadata,
1564
+ spec: {
1565
+ accessModes,
1566
+ storageClassName,
1567
+ volumeName,
1568
+ resources: {
1569
+ requests: {
1570
+ storage: requestsStorage,
1571
+ },
1572
+ },
1573
+ },
1574
+ status: {
1575
+ phase,
1576
+ capacity: {
1577
+ storage: capacityStorage,
1578
+ },
1579
+ },
1580
+ };
1581
+ } catch {
1582
+ return null;
1583
+ }
1584
+ }
1585
+
1586
+ export function parsePVObject(
1587
+ objectKvList: JSONObject,
1588
+ ): KubernetesPVObject | null {
1589
+ try {
1590
+ const metadataKv: string | JSONObject | null = getKvValue(
1591
+ objectKvList,
1592
+ "metadata",
1593
+ );
1594
+ if (!metadataKv || typeof metadataKv === "string") {
1595
+ return null;
1596
+ }
1597
+
1598
+ const metadata: KubernetesObjectMetadata = parseMetadata(metadataKv);
1599
+ if (!metadata.name) {
1600
+ return null;
1601
+ }
1602
+
1603
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1604
+ const statusKv: string | JSONObject | null = getKvValue(
1605
+ objectKvList,
1606
+ "status",
1607
+ );
1608
+
1609
+ // Parse spec
1610
+ let capacityStorage: string = "";
1611
+ const accessModes: Array<string> = [];
1612
+ let storageClassName: string = "";
1613
+ let persistentVolumeReclaimPolicy: string = "";
1614
+ let claimRefName: string = "";
1615
+ let claimRefNamespace: string = "";
1616
+
1617
+ if (specKv && typeof specKv !== "string") {
1618
+ capacityStorage = getNestedKvValue(specKv, "capacity", "storage");
1619
+ storageClassName = getKvStringValue(specKv, "storageClassName");
1620
+ persistentVolumeReclaimPolicy = getKvStringValue(
1621
+ specKv,
1622
+ "persistentVolumeReclaimPolicy",
1623
+ );
1624
+
1625
+ const accessModesArray: string | JSONObject | null = getKvValue(
1626
+ specKv,
1627
+ "accessModes",
1628
+ );
1629
+ if (accessModesArray && typeof accessModesArray !== "string") {
1630
+ const modeValues: Array<JSONObject> =
1631
+ (accessModesArray["values"] as Array<JSONObject>) || [];
1632
+ for (const v of modeValues) {
1633
+ if (v["stringValue"]) {
1634
+ accessModes.push(v["stringValue"] as string);
1635
+ }
1636
+ }
1637
+ }
1638
+
1639
+ const claimRefKv: string | JSONObject | null = getKvValue(
1640
+ specKv,
1641
+ "claimRef",
1642
+ );
1643
+ if (claimRefKv && typeof claimRefKv !== "string") {
1644
+ claimRefName = getKvStringValue(claimRefKv, "name");
1645
+ claimRefNamespace = getKvStringValue(claimRefKv, "namespace");
1646
+ }
1647
+ }
1648
+
1649
+ // Parse status
1650
+ let phase: string = "";
1651
+ if (statusKv && typeof statusKv !== "string") {
1652
+ phase = getKvStringValue(statusKv, "phase");
1653
+ }
1654
+
1655
+ return {
1656
+ metadata,
1657
+ spec: {
1658
+ capacity: {
1659
+ storage: capacityStorage,
1660
+ },
1661
+ accessModes,
1662
+ storageClassName,
1663
+ persistentVolumeReclaimPolicy,
1664
+ claimRef: {
1665
+ name: claimRefName,
1666
+ namespace: claimRefNamespace,
1667
+ },
1668
+ },
1669
+ status: {
1670
+ phase,
1671
+ },
1672
+ };
1673
+ } catch {
1674
+ return null;
1675
+ }
1676
+ }
1677
+
1678
+ export function parseHPAObject(
1679
+ objectKvList: JSONObject,
1680
+ ): KubernetesHPAObject | null {
1681
+ try {
1682
+ const metadataKv: string | JSONObject | null = getKvValue(
1683
+ objectKvList,
1684
+ "metadata",
1685
+ );
1686
+ if (!metadataKv || typeof metadataKv === "string") {
1687
+ return null;
1688
+ }
1689
+
1690
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1691
+ const statusKv: string | JSONObject | null = getKvValue(
1692
+ objectKvList,
1693
+ "status",
1694
+ );
1695
+
1696
+ let minReplicas: number = 0;
1697
+ let maxReplicas: number = 0;
1698
+ let scaleTargetRef: { kind: string; name: string } = {
1699
+ kind: "",
1700
+ name: "",
1701
+ };
1702
+ const metrics: Array<KubernetesHPAMetricSpec> = [];
1703
+ if (specKv && typeof specKv !== "string") {
1704
+ minReplicas = parseInt(getKvStringValue(specKv, "minReplicas")) || 0;
1705
+ maxReplicas = parseInt(getKvStringValue(specKv, "maxReplicas")) || 0;
1706
+ const targetRefKv: string | JSONObject | null = getKvValue(
1707
+ specKv,
1708
+ "scaleTargetRef",
1709
+ );
1710
+ if (targetRefKv && typeof targetRefKv !== "string") {
1711
+ scaleTargetRef = {
1712
+ kind: getKvStringValue(targetRefKv, "kind"),
1713
+ name: getKvStringValue(targetRefKv, "name"),
1714
+ };
1715
+ }
1716
+ const metricsArrayKv: string | JSONObject | null = getKvValue(
1717
+ specKv,
1718
+ "metrics",
1719
+ );
1720
+ if (metricsArrayKv && typeof metricsArrayKv !== "string") {
1721
+ const metricsItems: Array<JSONObject> = getArrayValues(metricsArrayKv);
1722
+ for (const metricKv of metricsItems) {
1723
+ const metricType: string = getKvStringValue(metricKv, "type");
1724
+ let resourceName: string = "";
1725
+ let targetType: string = "";
1726
+ let targetValue: string = "";
1727
+ const resourceKv: string | JSONObject | null = getKvValue(
1728
+ metricKv,
1729
+ "resource",
1730
+ );
1731
+ if (resourceKv && typeof resourceKv !== "string") {
1732
+ resourceName = getKvStringValue(resourceKv, "name");
1733
+ const targetKv: string | JSONObject | null = getKvValue(
1734
+ resourceKv,
1735
+ "target",
1736
+ );
1737
+ if (targetKv && typeof targetKv !== "string") {
1738
+ targetType = getKvStringValue(targetKv, "type");
1739
+ targetValue =
1740
+ getKvStringValue(targetKv, "averageUtilization") ||
1741
+ getKvStringValue(targetKv, "averageValue") ||
1742
+ getKvStringValue(targetKv, "value");
1743
+ }
1744
+ }
1745
+ metrics.push({
1746
+ type: metricType,
1747
+ resourceName,
1748
+ targetType,
1749
+ targetValue,
1750
+ });
1751
+ }
1752
+ }
1753
+ }
1754
+
1755
+ let currentReplicas: number = 0;
1756
+ let desiredReplicas: number = 0;
1757
+ let conditions: Array<KubernetesHPACondition> = [];
1758
+ if (statusKv && typeof statusKv !== "string") {
1759
+ currentReplicas =
1760
+ parseInt(getKvStringValue(statusKv, "currentReplicas")) || 0;
1761
+ desiredReplicas =
1762
+ parseInt(getKvStringValue(statusKv, "desiredReplicas")) || 0;
1763
+ const condArray: string | JSONObject | null = getKvValue(
1764
+ statusKv,
1765
+ "conditions",
1766
+ );
1767
+ if (condArray && typeof condArray !== "string") {
1768
+ const condItems: Array<JSONObject> = getArrayValues(condArray);
1769
+ conditions = condItems.map(
1770
+ (condKv: JSONObject): KubernetesHPACondition => {
1771
+ return {
1772
+ type: getKvStringValue(condKv, "type"),
1773
+ status: getKvStringValue(condKv, "status"),
1774
+ reason: getKvStringValue(condKv, "reason"),
1775
+ message: getKvStringValue(condKv, "message"),
1776
+ lastTransitionTime: getKvStringValue(
1777
+ condKv,
1778
+ "lastTransitionTime",
1779
+ ),
1780
+ };
1781
+ },
1782
+ );
1783
+ }
1784
+ }
1785
+
1786
+ return {
1787
+ metadata: parseMetadata(metadataKv),
1788
+ spec: { minReplicas, maxReplicas, scaleTargetRef, metrics },
1789
+ status: { currentReplicas, desiredReplicas, conditions },
1790
+ };
1791
+ } catch {
1792
+ return null;
1793
+ }
1794
+ }
1795
+
1796
+ export function parseVPAObject(
1797
+ objectKvList: JSONObject,
1798
+ ): KubernetesVPAObject | null {
1799
+ try {
1800
+ const metadataKv: string | JSONObject | null = getKvValue(
1801
+ objectKvList,
1802
+ "metadata",
1803
+ );
1804
+ if (!metadataKv || typeof metadataKv === "string") {
1805
+ return null;
1806
+ }
1807
+
1808
+ const specKv: string | JSONObject | null = getKvValue(objectKvList, "spec");
1809
+ const statusKv: string | JSONObject | null = getKvValue(
1810
+ objectKvList,
1811
+ "status",
1812
+ );
1813
+
1814
+ let targetRef: { kind: string; name: string } = { kind: "", name: "" };
1815
+ let updatePolicy: { updateMode: string } = { updateMode: "" };
1816
+ let resourcePolicy: string = "";
1817
+ if (specKv && typeof specKv !== "string") {
1818
+ const targetRefKv: string | JSONObject | null = getKvValue(
1819
+ specKv,
1820
+ "targetRef",
1821
+ );
1822
+ if (targetRefKv && typeof targetRefKv !== "string") {
1823
+ targetRef = {
1824
+ kind: getKvStringValue(targetRefKv, "kind"),
1825
+ name: getKvStringValue(targetRefKv, "name"),
1826
+ };
1827
+ }
1828
+ const updatePolicyKv: string | JSONObject | null = getKvValue(
1829
+ specKv,
1830
+ "updatePolicy",
1831
+ );
1832
+ if (updatePolicyKv && typeof updatePolicyKv !== "string") {
1833
+ updatePolicy = {
1834
+ updateMode: getKvStringValue(updatePolicyKv, "updateMode"),
1835
+ };
1836
+ }
1837
+ resourcePolicy = getKvStringValue(specKv, "resourcePolicy");
1838
+ }
1839
+
1840
+ const containerRecommendations: Array<KubernetesVPAContainerRecommendation> =
1841
+ [];
1842
+ if (statusKv && typeof statusKv !== "string") {
1843
+ const recommendationKv: string | JSONObject | null = getKvValue(
1844
+ statusKv,
1845
+ "recommendation",
1846
+ );
1847
+ if (recommendationKv && typeof recommendationKv !== "string") {
1848
+ const containerRecsArrayKv: string | JSONObject | null = getKvValue(
1849
+ recommendationKv,
1850
+ "containerRecommendations",
1851
+ );
1852
+ if (containerRecsArrayKv && typeof containerRecsArrayKv !== "string") {
1853
+ const recItems: Array<JSONObject> =
1854
+ getArrayValues(containerRecsArrayKv);
1855
+ for (const recKv of recItems) {
1856
+ const targetKv: string | JSONObject | null = getKvValue(
1857
+ recKv,
1858
+ "target",
1859
+ );
1860
+ const lowerBoundKv: string | JSONObject | null = getKvValue(
1861
+ recKv,
1862
+ "lowerBound",
1863
+ );
1864
+ const upperBoundKv: string | JSONObject | null = getKvValue(
1865
+ recKv,
1866
+ "upperBound",
1867
+ );
1868
+ containerRecommendations.push({
1869
+ containerName: getKvStringValue(recKv, "containerName"),
1870
+ target:
1871
+ targetKv && typeof targetKv !== "string"
1872
+ ? getKvListAsRecord(targetKv)
1873
+ : {},
1874
+ lowerBound:
1875
+ lowerBoundKv && typeof lowerBoundKv !== "string"
1876
+ ? getKvListAsRecord(lowerBoundKv)
1877
+ : {},
1878
+ upperBound:
1879
+ upperBoundKv && typeof upperBoundKv !== "string"
1880
+ ? getKvListAsRecord(upperBoundKv)
1881
+ : {},
1882
+ });
1883
+ }
1884
+ }
1885
+ }
1886
+ }
1887
+
1888
+ return {
1889
+ metadata: parseMetadata(metadataKv),
1890
+ spec: { targetRef, updatePolicy, resourcePolicy },
1891
+ status: {
1892
+ recommendation: { containerRecommendations },
1893
+ },
1894
+ };
1895
+ } catch {
1896
+ return null;
1897
+ }
1898
+ }
1899
+
1900
+ /**
1901
+ * Extract the K8s object from a raw OTLP log body string.
1902
+ * For k8sobjects pull mode, the body is:
1903
+ * { kvlistValue: { values: [{ key: "type", value: ... }, { key: "object", value: { kvlistValue: ... } }] } }
1904
+ * OR for some modes, the object may be at the top level.
1905
+ */
1906
+ export function extractObjectFromLogBody(
1907
+ bodyString: string,
1908
+ ): JSONObject | null {
1909
+ try {
1910
+ const bodyObj: JSONObject = JSON.parse(bodyString) as JSONObject;
1911
+ // Handle both camelCase (JSON encoding) and snake_case (protobuf via protobufjs)
1912
+ const topKvList: JSONObject | undefined = (bodyObj["kvlistValue"] ||
1913
+ bodyObj["kvlist_value"]) as JSONObject | undefined;
1914
+ if (!topKvList) {
1915
+ return null;
1916
+ }
1917
+
1918
+ // Try to get the "object" key (used in watch mode)
1919
+ const objectVal: string | JSONObject | null = getKvValue(
1920
+ topKvList,
1921
+ "object",
1922
+ );
1923
+ if (objectVal && typeof objectVal !== "string") {
1924
+ return objectVal;
1925
+ }
1926
+
1927
+ /*
1928
+ * If no "object" key, the kvlist might BE the object (pull mode)
1929
+ * Check if it has typical K8s fields
1930
+ */
1931
+ const kind: string | JSONObject | null = getKvValue(topKvList, "kind");
1932
+ if (kind) {
1933
+ return topKvList;
1934
+ }
1935
+
1936
+ // Also check "metadata" as a fallback for objects without "kind"
1937
+ const metadata: string | JSONObject | null = getKvValue(
1938
+ topKvList,
1939
+ "metadata",
1940
+ );
1941
+ if (metadata && typeof metadata !== "string") {
1942
+ return topKvList;
1943
+ }
1944
+
1945
+ return null;
1946
+ } catch {
1947
+ return null;
1948
+ }
1949
+ }