1use std::collections::BTreeMap;
2
3use crate::{ai_catalog::ClientApi, Platform, ResourceType};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_json::Value as JsonValue;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
10#[serde(rename_all = "camelCase")]
11pub struct ResourceHeartbeat {
12 pub deployment_id: Option<String>,
13 pub resource_id: String,
16 pub resource_type: ResourceType,
17 pub controller_platform: Platform,
18 pub backend: HeartbeatBackend,
19 pub observed_at: DateTime<Utc>,
20 pub data: ResourceHeartbeatData,
21 pub raw: Vec<RawHeartbeatSnippet>,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
26#[serde(rename_all = "camelCase")]
27pub struct ObservedInventoryBatch {
28 pub source_kind: String,
31 pub inventory_scope: String,
33 pub controller_platform: Platform,
35 pub backend: HeartbeatBackend,
37 pub observed_at: DateTime<Utc>,
39 pub complete: bool,
43 pub resources: Vec<ObservedResourceSample>,
44}
45
46#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
48#[serde(rename_all = "camelCase")]
49pub struct ObservedResourceSample {
50 pub deployment_id: Option<String>,
51 pub raw_identity: String,
54 pub provider_kind: String,
58 pub display_name: String,
59 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub namespace: Option<String>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub region: Option<String>,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub scope: Option<String>,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub resource_type_hint: Option<ResourceType>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub version: Option<String>,
70 #[serde(default, skip_serializing_if = "Option::is_none")]
71 pub alien_resource_id: Option<String>,
72 pub health: ObservedHealth,
73 pub lifecycle: ProviderLifecycleState,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub message: Option<String>,
76 pub partial: bool,
77 pub provider_stale: bool,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
79 pub counts: Option<ObservedCounts>,
80 #[serde(default, skip_serializing_if = "Vec::is_empty")]
81 pub collection_issues: Vec<HeartbeatCollectionIssue>,
82 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
83 pub labels: BTreeMap<String, String>,
84 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
85 pub attributes: BTreeMap<String, JsonValue>,
86 #[serde(default, skip_serializing_if = "Vec::is_empty")]
87 pub raw: Vec<RawHeartbeatSnippet>,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
91#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
92#[serde(rename_all = "camelCase")]
93pub enum HeartbeatBackend {
94 Aws,
95 Gcp,
96 Azure,
97 Kubernetes,
98 Local,
99 Managed,
100 External,
101 Test,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
105#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
106#[serde(rename_all = "kebab-case")]
107pub enum HeartbeatCollectionIssueReason {
108 Forbidden,
109 NotInstalled,
110 ApiUnavailable,
111 CollectionFailed,
112 TimedOut,
113}
114
115#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
116#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
117#[serde(tag = "resourceType", content = "data")]
118pub enum ResourceHeartbeatData {
119 #[serde(rename = "storage")]
120 Storage(StorageHeartbeatData),
121 #[serde(rename = "worker")]
122 Worker(WorkerHeartbeatData),
123 #[serde(rename = "container")]
124 Container(ContainerHeartbeatData),
125 #[serde(rename = "daemon")]
126 Daemon(DaemonHeartbeatData),
127 #[serde(rename = "compute-cluster")]
128 ComputeCluster(ComputeClusterHeartbeatData),
129 #[serde(rename = "kubernetes-cluster")]
130 KubernetesCluster(KubernetesClusterHeartbeatData),
131 #[serde(rename = "queue")]
132 Queue(QueueHeartbeatData),
133 #[serde(rename = "kv")]
134 Kv(KvHeartbeatData),
135 #[serde(rename = "postgres")]
136 Postgres(PostgresHeartbeatData),
137 #[serde(rename = "vault")]
138 Vault(VaultHeartbeatData),
139 #[serde(rename = "service-account")]
140 ServiceAccount(ServiceAccountHeartbeatData),
141 #[serde(rename = "network")]
142 Network(NetworkHeartbeatData),
143 #[serde(rename = "remote-stack-management")]
144 RemoteStackManagement(RemoteStackManagementHeartbeatData),
145 #[serde(rename = "artifact-registry")]
146 ArtifactRegistry(ArtifactRegistryHeartbeatData),
147 #[serde(rename = "build")]
148 Build(BuildHeartbeatData),
149 #[serde(rename = "service_activation")]
150 ServiceActivation(ServiceActivationHeartbeatData),
151 #[serde(rename = "azure_resource_group")]
152 AzureResourceGroup(AzureResourceGroupHeartbeatData),
153 #[serde(rename = "azure_storage_account")]
154 AzureStorageAccount(AzureStorageAccountHeartbeatData),
155 #[serde(rename = "azure_container_apps_environment")]
156 AzureContainerAppsEnvironment(AzureContainerAppsEnvironmentHeartbeatData),
157 #[serde(rename = "azure_service_bus_namespace")]
158 AzureServiceBusNamespace(AzureServiceBusNamespaceHeartbeatData),
159 #[serde(rename = "ai")]
160 Ai(AiHeartbeatData),
161 #[serde(rename = "key")]
162 Key(KeyHeartbeatData),
163 #[serde(rename = "sandbox")]
164 Sandbox(SandboxHeartbeatData),
165}
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
168#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
169#[serde(rename_all = "kebab-case")]
170pub enum ObservedHealth {
171 Unknown,
172 Healthy,
173 Degraded,
174 Unhealthy,
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
178#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
179#[serde(rename_all = "kebab-case")]
180pub enum ProviderLifecycleState {
181 Unknown,
182 Creating,
183 Updating,
184 Running,
185 Scaling,
186 Stopping,
187 Stopped,
188 Deleting,
189 Deleted,
190 Failed,
191}
192
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
194#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
195#[serde(rename_all = "camelCase")]
196pub struct KeyHeartbeatStatus {
197 pub health: ObservedHealth,
198 pub lifecycle: ProviderLifecycleState,
199 pub message: Option<String>,
200}
201
202#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
203#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
204#[serde(tag = "provider", content = "data", rename_all = "kebab-case")]
205pub enum KeyHeartbeatData {
206 AwsKms(AwsKmsKeyHeartbeatData),
207 GcpCloudKms(GcpCloudKmsKeyHeartbeatData),
208 AzureKeyVault(AzureKeyVaultKeyHeartbeatData),
209}
210
211#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
212#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
213#[serde(rename_all = "camelCase")]
214pub struct AwsKmsKeyHeartbeatData {
215 pub status: KeyHeartbeatStatus,
216 pub key_arn: String,
217 pub key_state: String,
218 pub enabled: bool,
219 pub key_spec: String,
220 pub key_usage: String,
221}
222
223#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
224#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
225#[serde(rename_all = "camelCase")]
226pub struct GcpCloudKmsKeyHeartbeatData {
227 pub status: KeyHeartbeatStatus,
228 pub crypto_key_name: String,
229 pub purpose: String,
230 pub primary_version: Option<String>,
231 pub primary_state: Option<String>,
232 pub algorithm: Option<String>,
233}
234
235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
237#[serde(rename_all = "camelCase")]
238pub struct AzureKeyVaultKeyHeartbeatData {
239 pub status: KeyHeartbeatStatus,
240 pub key_id: String,
241 pub enabled: Option<bool>,
242 pub key_type: String,
243 pub key_operations: Vec<String>,
244 pub recovery_level: Option<String>,
245}
246
247#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
248#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
249#[serde(rename_all = "camelCase")]
250pub struct HeartbeatCollectionIssue {
251 pub source: String,
252 pub reason: HeartbeatCollectionIssueReason,
253 pub severity: HeartbeatIssueSeverity,
254 pub message: String,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
258#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
259#[serde(rename_all = "kebab-case")]
260pub enum HeartbeatIssueSeverity {
261 Info,
262 Warning,
263 Error,
264}
265
266#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
267#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
268#[serde(rename_all = "camelCase")]
269pub struct KubernetesEventSnapshot {
270 pub reason: String,
271 #[serde(rename = "type")]
272 pub type_: Option<String>,
273 pub message: String,
274 pub count: Option<i32>,
275 pub first_timestamp: Option<DateTime<Utc>>,
276 pub last_timestamp: Option<DateTime<Utc>>,
277 pub event_time: Option<DateTime<Utc>>,
278 pub source: Option<KubernetesEventSource>,
279 pub involved_object: Option<KubernetesEventInvolvedObject>,
280 pub raw: Option<JsonValue>,
281}
282
283#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
284#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
285#[serde(rename_all = "camelCase")]
286pub struct KubernetesEventSource {
287 pub component: Option<String>,
288 pub host: Option<String>,
289}
290
291#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
292#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
293#[serde(rename_all = "camelCase")]
294pub struct KubernetesEventInvolvedObject {
295 pub kind: Option<String>,
296 pub namespace: Option<String>,
297 pub name: Option<String>,
298 pub uid: Option<String>,
299 pub api_version: Option<String>,
300 pub resource_version: Option<String>,
301 pub field_path: Option<String>,
302}
303
304#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
305#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
306#[serde(rename_all = "camelCase")]
307pub struct ManagedRuntimeEventSnapshot {
308 pub event_id: Option<String>,
309 pub reason: String,
310 #[serde(rename = "type")]
311 pub type_: Option<String>,
312 pub message: String,
313 pub count: Option<i32>,
314 pub first_timestamp: Option<DateTime<Utc>>,
315 pub last_timestamp: Option<DateTime<Utc>>,
316 pub event_time: Option<DateTime<Utc>>,
317 pub source: Option<ManagedRuntimeEventSource>,
318 pub involved_object: Option<ManagedRuntimeEventInvolvedObject>,
319 pub details: Option<JsonValue>,
320 pub raw: Option<JsonValue>,
321}
322
323#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
324#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
325#[serde(rename_all = "camelCase")]
326pub struct ManagedRuntimeEventSource {
327 pub component: Option<String>,
328 pub host: Option<String>,
329}
330
331#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
332#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
333#[serde(rename_all = "camelCase")]
334pub struct ManagedRuntimeEventInvolvedObject {
335 pub kind: Option<String>,
336 pub id: Option<String>,
337 pub name: Option<String>,
338 pub replica_id: Option<String>,
339 pub machine_id: Option<String>,
340 pub details: Option<JsonValue>,
341}
342
343#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
344#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
345#[serde(rename_all = "camelCase")]
346pub struct LocalRuntimeEventSnapshot {
347 pub timestamp: DateTime<Utc>,
348 pub severity: HeartbeatIssueSeverity,
349 pub kind: String,
350 pub message: String,
351 pub subject: Option<LocalRuntimeEventSubject>,
352 pub raw: Option<JsonValue>,
353}
354
355#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
356#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
357#[serde(rename_all = "camelCase")]
358pub struct LocalRuntimeEventSubject {
359 pub kind: String,
360 pub id: Option<String>,
361 pub name: Option<String>,
362}
363
364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
365#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
366#[serde(rename_all = "camelCase")]
367pub struct RawHeartbeatSnippet {
368 pub source: String,
369 pub format: RawHeartbeatSnippetFormat,
370 pub collected_at: DateTime<Utc>,
371 pub body: String,
372 pub truncated: bool,
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
376#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
377#[serde(rename_all = "kebab-case")]
378pub enum RawHeartbeatSnippetFormat {
379 Json,
380 Yaml,
381 Text,
382}
383
384#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
385#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
386#[serde(rename_all = "camelCase")]
387pub struct ObservedCounts {
388 pub desired: Option<u32>,
389 pub current: Option<u32>,
390 pub ready: Option<u32>,
391}
392
393#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
394#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
395#[serde(rename_all = "camelCase")]
396pub struct MetricSample {
397 pub value: f64,
398 pub unit: MetricUnit,
399}
400
401#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
402#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
403#[serde(rename_all = "kebab-case")]
404pub enum MetricUnit {
405 Count,
406 Percent,
407 Bytes,
408 Cores,
409 Milliseconds,
410 RequestsPerSecond,
411}
412
413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
414#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
415#[serde(tag = "backend", rename_all = "camelCase")]
416pub enum StorageHeartbeatData {
417 AwsS3(AwsS3StorageHeartbeatData),
418 GcpCloudStorage(GcpCloudStorageHeartbeatData),
419 AzureBlob(AzureBlobStorageHeartbeatData),
420 Local(LocalStorageHeartbeatData),
421}
422
423#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
424#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
425#[serde(rename_all = "camelCase")]
426pub struct StorageHeartbeatStatus {
427 pub health: ObservedHealth,
428 pub lifecycle: ProviderLifecycleState,
429 pub message: Option<String>,
430 pub stale: bool,
431 pub partial: bool,
432 pub collection_issues: Vec<HeartbeatCollectionIssue>,
433}
434
435#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
436#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
437#[serde(rename_all = "camelCase")]
438pub struct AwsS3StorageHeartbeatData {
439 pub status: StorageHeartbeatStatus,
440 pub name: String,
441 pub region: Option<String>,
442 pub bucket_location: Option<String>,
443 pub versioning_status: Option<String>,
444 pub versioning_enabled: Option<bool>,
445 pub lifecycle_present: bool,
446 pub lifecycle_rule_count: Option<u64>,
447 pub encryption_config_present: bool,
448 pub encryption_enabled: Option<bool>,
449 pub public_access_block_present: bool,
450 pub block_public_acls: Option<bool>,
451 pub ignore_public_acls: Option<bool>,
452 pub block_public_policy: Option<bool>,
453 pub restrict_public_buckets: Option<bool>,
454 pub bucket_policy_present: Option<bool>,
455 pub bucket_acl_present: Option<bool>,
456}
457
458#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
459#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
460#[serde(rename_all = "camelCase")]
461pub struct AzureBlobStorageHeartbeatData {
462 pub status: StorageHeartbeatStatus,
463 pub name: String,
464 pub storage_account_name: Option<String>,
465 pub resource_group: Option<String>,
466 pub location: Option<String>,
467 pub account_kind: Option<String>,
468 pub sku_name: Option<String>,
469 pub sku_tier: Option<String>,
470 pub access_tier: Option<String>,
471 pub provisioning_state: Option<String>,
472 pub primary_location: Option<String>,
473 pub secondary_location: Option<String>,
474 pub status_of_primary: Option<String>,
475 pub status_of_secondary: Option<String>,
476 pub public_network_access: Option<String>,
477 pub allow_blob_public_access: Option<bool>,
478 pub encryption_key_source: Option<String>,
479 pub blob_encryption_enabled: Option<bool>,
480 pub file_encryption_enabled: Option<bool>,
481 pub queue_encryption_enabled: Option<bool>,
482 pub table_encryption_enabled: Option<bool>,
483 pub blob_versioning_enabled: Option<bool>,
484 pub blob_delete_retention_enabled: Option<bool>,
485 pub blob_delete_retention_days: Option<u64>,
486 pub container_delete_retention_enabled: Option<bool>,
487 pub container_delete_retention_days: Option<u64>,
488 pub change_feed_enabled: Option<bool>,
489 pub change_feed_retention_days: Option<u64>,
490 pub container_public_access: Option<String>,
491}
492
493#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
494#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
495#[serde(rename_all = "camelCase")]
496pub struct GcpCloudStorageHeartbeatData {
497 pub status: StorageHeartbeatStatus,
498 pub name: String,
499 pub bucket_id: Option<String>,
500 pub location: Option<String>,
501 pub location_type: Option<String>,
502 pub storage_class: Option<String>,
503 pub versioning_enabled: Option<bool>,
504 pub lifecycle_present: bool,
505 pub lifecycle_rule_count: Option<u64>,
506 pub retention_policy_effective_time: Option<String>,
507 pub retention_policy_is_locked: Option<bool>,
508 pub retention_period: Option<String>,
509 pub soft_delete_retention_duration_seconds: Option<String>,
510 pub soft_delete_effective_time: Option<String>,
511 pub uniform_bucket_level_access_enabled: Option<bool>,
512 pub uniform_bucket_level_access_locked_time: Option<String>,
513 pub public_access_prevention: Option<String>,
514 pub encryption_config_present: bool,
515 pub default_kms_key_name: Option<String>,
516}
517
518#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
519#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
520#[serde(rename_all = "camelCase")]
521pub struct LocalStorageHeartbeatData {
522 pub status: StorageHeartbeatStatus,
523 pub path: String,
524 pub path_exists: bool,
525 pub is_directory: Option<bool>,
526 pub readonly: Option<bool>,
527 pub modified_at: Option<DateTime<Utc>>,
528}
529
530#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
531#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
532#[serde(tag = "backend", rename_all = "camelCase")]
533pub enum WorkerHeartbeatData {
534 AwsLambda(AwsLambdaWorkerHeartbeatData),
535 GcpCloudRun(GcpCloudRunWorkerHeartbeatData),
536 AzureContainerApps(AzureContainerAppsWorkerHeartbeatData),
537 Kubernetes(KubernetesWorkerHeartbeatData),
538 Local(LocalWorkerHeartbeatData),
539}
540
541#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
542#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
543#[serde(tag = "backend", rename_all = "camelCase")]
544pub enum ContainerHeartbeatData {
545 HorizonPlatform(HorizonContainerHeartbeatData),
546 Kubernetes(KubernetesContainerHeartbeatData),
547 Local(LocalContainerHeartbeatData),
548}
549
550#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
551#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
552#[serde(tag = "backend", rename_all = "camelCase")]
553pub enum DaemonHeartbeatData {
554 Aws(AwsDaemonHeartbeatData),
555 Gcp(GcpDaemonHeartbeatData),
556 Azure(AzureDaemonHeartbeatData),
557 Machines(MachinesDaemonHeartbeatData),
558 Kubernetes(KubernetesDaemonHeartbeatData),
559 Local(LocalDaemonHeartbeatData),
560}
561
562#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
563#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
564#[serde(rename_all = "camelCase")]
565pub struct WorkloadHeartbeatStatus {
566 pub health: ObservedHealth,
567 pub lifecycle: ProviderLifecycleState,
568 pub message: Option<String>,
569 pub stale: bool,
570 pub partial: bool,
571 pub collection_issues: Vec<HeartbeatCollectionIssue>,
572}
573
574#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
575#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
576#[serde(rename_all = "camelCase")]
577pub struct WorkloadReplicaStatus {
578 pub desired: Option<u32>,
579 pub current: Option<u32>,
580 pub ready: Option<u32>,
581 pub available: Option<u32>,
582 pub updated: Option<u32>,
583 pub misscheduled: Option<u32>,
584}
585
586#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
587#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
588#[serde(rename_all = "camelCase")]
589pub struct AwsLambdaWorkerHeartbeatData {
590 pub status: WorkloadHeartbeatStatus,
591 pub function_name: String,
592 pub runtime: Option<String>,
593 pub package_type: Option<String>,
594 pub memory_size_mb: Option<i64>,
595 pub timeout_seconds: Option<i64>,
596 pub version: Option<String>,
597 pub revision_id: Option<String>,
598 pub last_modified: Option<String>,
599 pub state: Option<String>,
600 pub state_reason: Option<String>,
601 pub state_reason_code: Option<String>,
602 pub last_update_status: Option<String>,
603 pub last_update_status_reason: Option<String>,
604 pub last_update_status_reason_code: Option<String>,
605 pub code_sha256: Option<String>,
606 pub layer_count: u32,
607 pub function_url_auth_type: Option<String>,
608 pub function_url_cors_present: bool,
609 pub trigger_count: u32,
610}
611
612#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
613#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
614#[serde(rename_all = "camelCase")]
615pub struct GcpCloudRunWorkerHeartbeatData {
616 pub status: WorkloadHeartbeatStatus,
617 pub service: String,
618 pub region: Option<String>,
619 pub uri: Option<String>,
620 pub urls: Vec<String>,
621 pub latest_created_revision: Option<String>,
622 pub latest_ready_revision: Option<String>,
623 pub generation: Option<i64>,
624 pub observed_generation: Option<i64>,
625 pub traffic_count: u32,
626 pub min_instance_count: Option<i32>,
627 pub max_instance_count: Option<i32>,
628 pub container_image: Option<String>,
629 pub cpu_limit: Option<String>,
630 pub memory_limit: Option<String>,
631}
632
633#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
634#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
635#[serde(rename_all = "camelCase")]
636pub struct AzureContainerAppsWorkerHeartbeatData {
637 pub status: WorkloadHeartbeatStatus,
638 pub app_name: String,
639 pub revision: Option<String>,
640 pub environment_name: Option<String>,
641 pub provisioning_state: Option<String>,
642 pub running_status: Option<String>,
643 pub ingress_fqdn: Option<String>,
644 pub min_replicas: Option<i32>,
645 pub max_replicas: Option<i32>,
646 pub cpu: Option<f64>,
647 pub memory: Option<String>,
648}
649
650#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
651#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
652#[serde(rename_all = "camelCase")]
653pub struct KubernetesWorkerHeartbeatData {
654 pub status: WorkloadHeartbeatStatus,
655 pub namespace: String,
656 pub name: String,
657 pub workload_kind: KubernetesWorkloadKind,
658 pub replicas: WorkloadReplicaStatus,
659 pub restarts: Option<u32>,
660 pub cpu: Option<MetricSample>,
661 pub memory: Option<MetricSample>,
662 pub workload: Option<KubernetesWorkloadStatus>,
663 pub pods: Vec<KubernetesPodRuntimeUnitStatus>,
664 pub trigger_count: u32,
665 pub events: Vec<KubernetesEventSnapshot>,
666}
667
668#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
669#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
670#[serde(rename_all = "camelCase")]
671pub struct LocalWorkerHeartbeatData {
672 pub status: WorkloadHeartbeatStatus,
673 pub pid: Option<u32>,
674 pub command_supported: bool,
675 pub image_path_present: bool,
676 pub readiness_probe_ok: Option<bool>,
677 pub trigger_count: u32,
678 pub cpu: Option<MetricSample>,
679 pub memory: Option<MetricSample>,
680 pub process: Option<LocalRuntimeUnitStatus>,
681 pub events: Vec<LocalRuntimeEventSnapshot>,
682}
683
684#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
685#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
686#[serde(rename_all = "camelCase")]
687pub struct HorizonContainerHeartbeatData {
688 pub status: WorkloadHeartbeatStatus,
689 pub container_id: String,
690 pub image: Option<String>,
691 #[serde(default)]
692 pub observed_image: Option<String>,
693 #[serde(default)]
694 pub latest_update_timestamp: Option<String>,
695 pub scheduling_mode: HorizonWorkloadSchedulingMode,
696 pub replicas: WorkloadReplicaStatus,
697 pub cpu: Option<MetricSample>,
698 pub memory: Option<MetricSample>,
699 pub attention_count: u32,
700 pub replica_units: Vec<ManagedRuntimeUnitStatus>,
701 pub events: Vec<ManagedRuntimeEventSnapshot>,
702}
703
704#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
705#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
706#[serde(rename_all = "camelCase")]
707pub enum HorizonWorkloadSchedulingMode {
708 Replicated,
709 Stateful,
710 Daemon,
711}
712
713#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
714#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
715#[serde(rename_all = "camelCase")]
716pub struct KubernetesContainerHeartbeatData {
717 pub status: WorkloadHeartbeatStatus,
718 pub namespace: String,
719 pub name: String,
720 pub workload_kind: KubernetesWorkloadKind,
721 pub replicas: WorkloadReplicaStatus,
722 pub restarts: Option<u32>,
723 pub cpu: Option<MetricSample>,
724 pub memory: Option<MetricSample>,
725 pub workload: Option<KubernetesWorkloadStatus>,
726 pub pods: Vec<KubernetesPodRuntimeUnitStatus>,
727 pub events: Vec<KubernetesEventSnapshot>,
728}
729
730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
731#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
732#[serde(rename_all = "camelCase")]
733pub struct LocalContainerHeartbeatData {
734 pub status: WorkloadHeartbeatStatus,
735 pub container_id: Option<String>,
736 pub name: Option<String>,
737 pub image: Option<String>,
738 pub runtime_status: Option<String>,
739 pub restart_count: Option<u32>,
740 pub port_count: u32,
741 pub bind_mount_count: u32,
742 pub local_url: Option<String>,
743 pub runtime_reachable: bool,
744 pub cpu: Option<MetricSample>,
745 pub memory: Option<MetricSample>,
746 pub container_unit: Option<LocalRuntimeUnitStatus>,
747 pub events: Vec<LocalRuntimeEventSnapshot>,
748}
749
750#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
751#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
752#[serde(rename_all = "camelCase")]
753pub struct AwsDaemonHeartbeatData {
754 pub status: WorkloadHeartbeatStatus,
755 pub horizon_cluster_id: String,
756 #[serde(default)]
757 pub daemon_name: String,
758 pub horizon_status: String,
759 pub horizon_status_reason: Option<String>,
760 pub horizon_status_message: Option<String>,
761 pub capacity_group: String,
762 pub desired_machines: u32,
763 pub assigned_machines: u32,
764 pub healthy_instances: u32,
765 pub unavailable_instances: u32,
766 pub command_supported: bool,
767 #[serde(default)]
768 pub observed_image: Option<String>,
769 pub latest_update_timestamp: String,
770 pub daemon_instances: Vec<ManagedRuntimeUnitStatus>,
771 pub events: Vec<ManagedRuntimeEventSnapshot>,
772}
773
774#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
775#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
776#[serde(rename_all = "camelCase")]
777pub struct GcpDaemonHeartbeatData {
778 pub status: WorkloadHeartbeatStatus,
779 pub horizon_cluster_id: String,
780 #[serde(default)]
781 pub daemon_name: String,
782 pub horizon_status: String,
783 pub horizon_status_reason: Option<String>,
784 pub horizon_status_message: Option<String>,
785 pub capacity_group: String,
786 pub desired_machines: u32,
787 pub assigned_machines: u32,
788 pub healthy_instances: u32,
789 pub unavailable_instances: u32,
790 pub command_supported: bool,
791 #[serde(default)]
792 pub observed_image: Option<String>,
793 pub latest_update_timestamp: String,
794 pub daemon_instances: Vec<ManagedRuntimeUnitStatus>,
795 pub events: Vec<ManagedRuntimeEventSnapshot>,
796}
797
798#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
799#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
800#[serde(rename_all = "camelCase")]
801pub struct AzureDaemonHeartbeatData {
802 pub status: WorkloadHeartbeatStatus,
803 pub horizon_cluster_id: String,
804 #[serde(default)]
805 pub daemon_name: String,
806 pub horizon_status: String,
807 pub horizon_status_reason: Option<String>,
808 pub horizon_status_message: Option<String>,
809 pub capacity_group: String,
810 pub desired_machines: u32,
811 pub assigned_machines: u32,
812 pub healthy_instances: u32,
813 pub unavailable_instances: u32,
814 pub command_supported: bool,
815 #[serde(default)]
816 pub observed_image: Option<String>,
817 pub latest_update_timestamp: String,
818 pub daemon_instances: Vec<ManagedRuntimeUnitStatus>,
819 pub events: Vec<ManagedRuntimeEventSnapshot>,
820}
821
822#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
823#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
824#[serde(rename_all = "camelCase")]
825pub struct MachinesDaemonHeartbeatData {
826 pub status: WorkloadHeartbeatStatus,
827 pub horizon_cluster_id: String,
828 #[serde(default)]
829 pub daemon_name: String,
830 pub horizon_status: String,
831 pub horizon_status_reason: Option<String>,
832 pub horizon_status_message: Option<String>,
833 pub capacity_group: String,
834 pub desired_machines: u32,
835 pub assigned_machines: u32,
836 pub healthy_instances: u32,
837 pub unavailable_instances: u32,
838 pub command_supported: bool,
839 #[serde(default)]
840 pub observed_image: Option<String>,
841 pub latest_update_timestamp: String,
842 pub daemon_instances: Vec<ManagedRuntimeUnitStatus>,
843 pub events: Vec<ManagedRuntimeEventSnapshot>,
844}
845
846#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
847#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
848#[serde(rename_all = "camelCase")]
849pub struct ManagedRuntimeUnitStatus {
850 pub replica_id: String,
851 pub name: String,
852 pub machine_id: Option<String>,
853 pub node_name: Option<String>,
854 pub ip: Option<String>,
855 pub ready: bool,
856 pub phase: Option<String>,
857 pub status: Option<String>,
858 pub reason: Option<String>,
859 pub message: Option<String>,
860 pub restart_count: Option<u32>,
861 pub waiting_reason: Option<String>,
862 pub terminated_reason: Option<String>,
863 pub metrics_healthy: Option<bool>,
864 pub metrics_status: Option<String>,
865 pub metrics_last_updated: Option<String>,
866 pub cpu: Option<MetricSample>,
867 pub memory: Option<MetricSample>,
868}
869
870#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
871#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
872#[serde(rename_all = "camelCase")]
873pub struct KubernetesDaemonHeartbeatData {
874 pub status: WorkloadHeartbeatStatus,
875 pub namespace: String,
876 pub name: String,
877 pub replicas: WorkloadReplicaStatus,
878 pub restarts: Option<u32>,
879 pub command_supported: bool,
880 pub cpu: Option<MetricSample>,
881 pub memory: Option<MetricSample>,
882 pub workload: Option<KubernetesWorkloadStatus>,
883 pub pods: Vec<KubernetesPodRuntimeUnitStatus>,
884 pub events: Vec<KubernetesEventSnapshot>,
885}
886
887#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
888#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
889#[serde(rename_all = "camelCase")]
890pub struct LocalDaemonHeartbeatData {
891 pub status: WorkloadHeartbeatStatus,
892 #[serde(default)]
893 pub daemon_name: String,
894 pub runtime_id: String,
895 pub pid: Option<u32>,
896 pub command_supported: bool,
897 pub image_path_present: bool,
898 pub restart_count: Option<u32>,
899 pub exit_reason: Option<String>,
900 pub daemon_instance: Option<LocalRuntimeUnitStatus>,
901 pub events: Vec<LocalRuntimeEventSnapshot>,
902}
903
904#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
905#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
906#[serde(rename_all = "camelCase")]
907pub struct LocalRuntimeUnitStatus {
908 pub unit_id: String,
909 pub name: String,
910 pub kind: LocalRuntimeUnitKind,
911 pub ready: bool,
912 pub phase: Option<String>,
913 pub pid: Option<u32>,
914 pub restart_count: Option<u32>,
915 pub cpu: Option<MetricSample>,
916 pub memory: Option<MetricSample>,
917}
918
919#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
920#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
921#[serde(rename_all = "kebab-case")]
922pub enum LocalRuntimeUnitKind {
923 Container,
924 Process,
925 Daemon,
926}
927
928#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
929#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
930#[serde(rename_all = "camelCase")]
931pub enum KubernetesWorkloadKind {
932 Deployment,
933 StatefulSet,
934 DaemonSet,
935 ReplicaSet,
936 Pod,
937}
938
939#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
940#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
941#[serde(rename_all = "camelCase")]
942pub struct KubernetesWorkloadStatus {
943 pub desired_replicas: Option<u32>,
944 pub ready_replicas: Option<u32>,
945 pub available_replicas: Option<u32>,
946 pub updated_replicas: Option<u32>,
947 pub observed_generation: Option<i64>,
948 pub desired_generation: Option<i64>,
949 pub rollout_reason: Option<String>,
950 pub conditions: Vec<KubernetesWorkloadCondition>,
951}
952
953#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
954#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
955#[serde(rename_all = "camelCase")]
956pub struct KubernetesWorkloadCondition {
957 #[serde(rename = "type")]
958 pub condition_type: String,
959 pub status: String,
960 pub reason: Option<String>,
961 pub message: Option<String>,
962 pub last_transition_time: Option<DateTime<Utc>>,
963}
964
965#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
966#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
967#[serde(rename_all = "camelCase")]
968pub struct KubernetesPodRuntimeUnitStatus {
969 pub name: String,
970 pub uid: Option<String>,
971 pub phase: Option<String>,
972 pub ready: bool,
973 pub restart_count: u32,
974 pub waiting_reason: Option<String>,
975 pub terminated_reason: Option<String>,
976 pub node_name: Option<String>,
977 pub pod_ip: Option<String>,
978 pub owner_references: Vec<KubernetesOwnerReference>,
979 pub cpu: Option<MetricSample>,
980 pub memory: Option<MetricSample>,
981}
982
983#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
984#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
985#[serde(rename_all = "camelCase")]
986pub struct KubernetesOwnerReference {
987 pub kind: String,
988 pub name: String,
989 pub uid: String,
990 pub controller: bool,
991}
992
993#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
994#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
995#[serde(tag = "backend", rename_all = "camelCase")]
996pub enum ComputeClusterHeartbeatData {
997 Aws(AwsComputeClusterHeartbeatData),
998 Gcp(GcpComputeClusterHeartbeatData),
999 Azure(AzureComputeClusterHeartbeatData),
1000 Machines(MachinesComputeClusterHeartbeatData),
1001 Local(LocalComputeClusterHeartbeatData),
1002}
1003
1004#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1005#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1006#[serde(rename_all = "camelCase")]
1007pub struct ComputeClusterHeartbeatStatus {
1008 pub health: ObservedHealth,
1009 pub lifecycle: ProviderLifecycleState,
1010 pub message: Option<String>,
1011 pub stale: bool,
1012 pub partial: bool,
1013 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1014}
1015
1016#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1017#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1018#[serde(rename_all = "camelCase")]
1019pub struct LocalComputeClusterHeartbeatData {
1020 pub status: ComputeClusterHeartbeatStatus,
1021 pub nodes: ObservedCounts,
1022 pub name: String,
1023 pub host_identifier: Option<String>,
1024 pub docker_available: bool,
1025 pub docker_version: Option<String>,
1026 pub docker_api_version: Option<String>,
1027 pub docker_os: Option<String>,
1028 pub docker_arch: Option<String>,
1029 pub network_name: Option<String>,
1030 pub network_available: bool,
1031 pub tracked_containers: Option<u32>,
1032 pub running_containers: Option<u32>,
1033}
1034
1035#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1036#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1037#[serde(rename_all = "camelCase")]
1038pub struct AwsComputeClusterHeartbeatData {
1039 pub status: ComputeClusterHeartbeatStatus,
1040 pub nodes: ObservedCounts,
1041 pub cpu: Option<MetricSample>,
1042 pub memory: Option<MetricSample>,
1043 pub name: String,
1044 pub region: Option<String>,
1045 pub backend_cluster_id: Option<String>,
1046 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1047 pub provider_fleets: Vec<ProviderFleetStatus>,
1048}
1049
1050#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1051#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1052#[serde(rename_all = "camelCase")]
1053pub struct GcpComputeClusterHeartbeatData {
1054 pub status: ComputeClusterHeartbeatStatus,
1055 pub nodes: ObservedCounts,
1056 pub cpu: Option<MetricSample>,
1057 pub memory: Option<MetricSample>,
1058 pub name: String,
1059 pub region: Option<String>,
1060 pub backend_cluster_id: Option<String>,
1061 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1062 pub provider_fleets: Vec<ProviderFleetStatus>,
1063}
1064
1065#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1066#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1067#[serde(rename_all = "camelCase")]
1068pub struct AzureComputeClusterHeartbeatData {
1069 pub status: ComputeClusterHeartbeatStatus,
1070 pub nodes: ObservedCounts,
1071 pub cpu: Option<MetricSample>,
1072 pub memory: Option<MetricSample>,
1073 pub name: String,
1074 pub region: Option<String>,
1075 pub backend_cluster_id: Option<String>,
1076 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1077 pub provider_fleets: Vec<ProviderFleetStatus>,
1078}
1079
1080#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1081#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1082#[serde(rename_all = "camelCase")]
1083pub struct MachinesComputeClusterHeartbeatData {
1084 pub status: ComputeClusterHeartbeatStatus,
1085 pub nodes: ObservedCounts,
1086 pub cpu: Option<MetricSample>,
1087 pub memory: Option<MetricSample>,
1088 pub name: String,
1089 pub backend_cluster_id: Option<String>,
1090 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1091 pub machines: Vec<MachinesComputeMachineStatus>,
1092}
1093
1094#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1095#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1096#[serde(rename_all = "camelCase")]
1097pub struct MachinesComputeMachineStatus {
1098 pub machine_id: String,
1099 pub status: String,
1100 pub capacity_group: String,
1101 pub zone: String,
1102 pub public_ip: Option<String>,
1103 pub overlay_ip: Option<String>,
1104 pub last_heartbeat: String,
1105 pub horizond_version: Option<String>,
1106 pub replica_count: i64,
1107 pub cpu_cores: Option<f64>,
1108 pub memory_bytes: Option<i64>,
1109 pub drain_force: bool,
1110 pub drain_requested_at: Option<String>,
1111 pub drain_deadline_at: Option<String>,
1112 pub drained_at: Option<String>,
1113 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1114 pub drain_blockers: Vec<ComputeDrainBlocker>,
1115}
1116
1117#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1118#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1119#[serde(rename_all = "camelCase")]
1120pub struct ComputeCapacityGroupStatus {
1121 pub group_id: String,
1122 pub current_machines: u32,
1123 pub desired_machines: u32,
1124 pub min_machines: Option<u32>,
1125 pub max_machines: Option<u32>,
1126 pub instance_type: Option<String>,
1127 pub recommendation: Option<ComputeCapacityRecommendation>,
1128 pub capacity_blocker: Option<ComputeCapacityBlocker>,
1129 #[serde(default, skip_serializing_if = "Option::is_none")]
1130 pub drain_progress: Option<ComputeDrainProgress>,
1131}
1132
1133#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1134#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1135#[serde(rename_all = "camelCase")]
1136pub enum ComputeCapacityBlockerCategory {
1137 Quota,
1138 Capacity,
1139 Allocation,
1140 Other,
1141}
1142
1143#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1144#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1145#[serde(rename_all = "camelCase")]
1146pub struct ComputeCapacityBlocker {
1147 pub category: ComputeCapacityBlockerCategory,
1148 pub provider_code: Option<String>,
1149 pub message: String,
1150 pub provider_reference: Option<String>,
1151 pub observed_at: DateTime<Utc>,
1152}
1153
1154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1155#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1156#[serde(rename_all = "camelCase")]
1157pub struct ComputeCapacityRecommendation {
1158 pub desired_machines: u32,
1159 pub reason: Option<String>,
1160 pub utilization: Option<MetricSample>,
1161 pub unschedulable_replicas: Option<u32>,
1162}
1163
1164#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1165#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1166#[serde(rename_all = "camelCase")]
1167pub enum ComputeDrainProgressStatus {
1168 Draining,
1169 Drained,
1170 Terminating,
1171}
1172
1173#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1174#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1175#[serde(rename_all = "camelCase")]
1176pub struct ComputeDrainBlocker {
1177 pub workload_name: String,
1178 pub replica_id: String,
1179 pub scheduling_mode: String,
1180 pub state: String,
1181 pub reason: String,
1182}
1183
1184#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1185#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1186#[serde(rename_all = "camelCase")]
1187pub struct ComputeDrainProgress {
1188 pub machine_id: String,
1189 pub status: ComputeDrainProgressStatus,
1190 pub replica_count: i64,
1191 pub force: bool,
1192 pub stalled: bool,
1193 pub drain_requested_at: Option<String>,
1194 pub drain_deadline_at: Option<String>,
1195 pub drained_at: Option<String>,
1196 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1197 pub blockers: Vec<ComputeDrainBlocker>,
1198}
1199
1200#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1201#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1202#[serde(rename_all = "camelCase")]
1203pub struct ProviderFleetStatus {
1204 pub group_id: String,
1205 pub provider_id: String,
1206 pub location: Option<String>,
1207 pub current_machines: u32,
1208 pub desired_machines: u32,
1209}
1210
1211#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1212#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1213#[serde(rename_all = "camelCase")]
1214pub struct KubernetesClusterHeartbeatData {
1215 pub status: WorkloadHeartbeatStatus,
1216 pub node_counts: ObservedCounts,
1217 pub pod_counts: ObservedCounts,
1218 pub cpu: Option<MetricSample>,
1219 pub memory: Option<MetricSample>,
1220 pub name: String,
1221 pub region: Option<String>,
1222 pub namespace: Option<String>,
1223 pub version: Option<String>,
1224 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1225 pub node_statuses: Vec<KubernetesClusterNodeStatus>,
1226 pub events: Vec<KubernetesEventSnapshot>,
1227}
1228
1229#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1230#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1231#[serde(rename_all = "camelCase")]
1232pub struct KubernetesClusterNodeStatus {
1233 pub name: String,
1234 pub uid: Option<String>,
1235 pub ready: bool,
1236 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1237 pub conditions: Vec<KubernetesNodeConditionStatus>,
1238 pub roles: Vec<String>,
1239 pub labels: BTreeMap<String, String>,
1240 pub allocatable: KubernetesNodeResources,
1241 pub capacity: KubernetesNodeResources,
1242 pub usage: Option<KubernetesNodeUsage>,
1243 pub kubelet_version: Option<String>,
1244 pub container_runtime_version: Option<String>,
1245}
1246
1247#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1248#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1249#[serde(rename_all = "camelCase")]
1250pub struct KubernetesNodeConditionStatus {
1251 pub type_: String,
1252 pub status: String,
1253 pub reason: Option<String>,
1254 pub message: Option<String>,
1255}
1256
1257#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1258#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1259#[serde(rename_all = "camelCase")]
1260pub struct KubernetesNodeResources {
1261 pub cpu: Option<MetricSample>,
1262 pub memory: Option<MetricSample>,
1263 pub pods: Option<u64>,
1264}
1265
1266#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1267#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1268#[serde(rename_all = "camelCase")]
1269pub struct KubernetesNodeUsage {
1270 pub cpu: Option<MetricSample>,
1271 pub memory: Option<MetricSample>,
1272}
1273
1274#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1275#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1276#[serde(tag = "backend", rename_all = "camelCase")]
1277pub enum QueueHeartbeatData {
1278 AwsSqs(AwsSqsQueueHeartbeatData),
1279 GcpPubSub(GcpPubSubQueueHeartbeatData),
1280 AzureServiceBus(AzureServiceBusQueueHeartbeatData),
1281 Local(LocalQueueHeartbeatData),
1282}
1283
1284#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1285#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1286#[serde(rename_all = "camelCase")]
1287pub struct QueueHeartbeatStatus {
1288 pub health: ObservedHealth,
1289 pub lifecycle: ProviderLifecycleState,
1290 pub message: Option<String>,
1291 pub stale: bool,
1292 pub partial: bool,
1293 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1294}
1295
1296impl Default for QueueHeartbeatStatus {
1297 fn default() -> Self {
1298 Self {
1299 health: ObservedHealth::Unknown,
1300 lifecycle: ProviderLifecycleState::Unknown,
1301 message: None,
1302 stale: false,
1303 partial: false,
1304 collection_issues: vec![],
1305 }
1306 }
1307}
1308
1309#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1310#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1311#[serde(rename_all = "camelCase")]
1312pub struct LocalQueueHeartbeatData {
1313 pub status: QueueHeartbeatStatus,
1314 pub name: String,
1315 pub path: Option<String>,
1316 pub service_status: Option<String>,
1317}
1318
1319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1320#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1321#[serde(rename_all = "camelCase")]
1322pub struct GcpPubSubQueueHeartbeatData {
1323 pub status: QueueHeartbeatStatus,
1324 pub topic_name: String,
1325 pub subscription_name: Option<String>,
1326 pub project_id: Option<String>,
1327 pub topic_full_name: Option<String>,
1328 pub subscription_full_name: Option<String>,
1329 pub endpoint: Option<String>,
1330 pub topic_labels: BTreeMap<String, String>,
1331 pub subscription_labels: BTreeMap<String, String>,
1332 pub message_storage_allowed_persistence_regions: Vec<String>,
1333 pub message_storage_enforce_in_transit: Option<bool>,
1334 pub kms_key_name: Option<String>,
1335 pub schema_name: Option<String>,
1336 pub schema_encoding: Option<String>,
1337 pub schema_first_revision_id: Option<String>,
1338 pub schema_last_revision_id: Option<String>,
1339 pub topic_message_retention_duration: Option<String>,
1340 pub topic_state: Option<String>,
1341 pub subscription_ack_deadline_seconds: Option<u32>,
1342 pub subscription_message_retention_duration: Option<String>,
1343 pub subscription_retain_acked_messages: Option<bool>,
1344 pub subscription_enable_message_ordering: Option<bool>,
1345 pub subscription_filter: Option<String>,
1346 pub subscription_detached: Option<bool>,
1347 pub subscription_state: Option<String>,
1348 pub subscription_push_config_present: Option<bool>,
1349 pub subscription_push_endpoint: Option<String>,
1350 pub subscription_push_attributes: BTreeMap<String, String>,
1351 pub subscription_push_oidc_service_account_email: Option<String>,
1352 pub subscription_push_oidc_audience: Option<String>,
1353 pub subscription_push_pubsub_wrapper_write_metadata: Option<bool>,
1354 pub subscription_push_no_wrapper_write_metadata: Option<bool>,
1355 pub subscription_dead_letter_topic: Option<String>,
1356 pub subscription_dead_letter_max_delivery_attempts: Option<u32>,
1357}
1358
1359#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1360#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1361#[serde(rename_all = "camelCase")]
1362pub struct AzureServiceBusQueueHeartbeatData {
1363 pub status: QueueHeartbeatStatus,
1364 pub name: String,
1365 pub namespace_name: String,
1366 pub resource_group: Option<String>,
1367 pub resource_id: Option<String>,
1368 pub endpoint: Option<String>,
1369 pub queue_status: Option<String>,
1370 pub lock_duration: Option<String>,
1371 pub max_delivery_count: Option<u32>,
1372 pub requires_duplicate_detection: Option<bool>,
1373 pub duplicate_detection_history_time_window: Option<String>,
1374 pub requires_session: Option<bool>,
1375 pub dead_lettering_on_message_expiration: Option<bool>,
1376 pub forward_dead_lettered_messages_to: Option<String>,
1377 pub forward_to: Option<String>,
1378 pub default_message_time_to_live: Option<String>,
1379 pub auto_delete_on_idle: Option<String>,
1380 pub enable_batched_operations: Option<bool>,
1381 pub enable_express: Option<bool>,
1382 pub enable_partitioning: Option<bool>,
1383 pub max_message_size_in_kilobytes: Option<u64>,
1384 pub max_size_in_megabytes: Option<u32>,
1385 pub message_count: Option<u64>,
1386 pub active_message_count: Option<u64>,
1387 pub dead_letter_message_count: Option<u64>,
1388 pub scheduled_message_count: Option<u64>,
1389 pub transfer_message_count: Option<u64>,
1390 pub transfer_dead_letter_message_count: Option<u64>,
1391 pub size_in_bytes: Option<u64>,
1392 pub accessed_at: Option<String>,
1393 pub created_at: Option<String>,
1394 pub updated_at: Option<String>,
1395}
1396
1397#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1398#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1399#[serde(rename_all = "camelCase")]
1400pub struct AwsSqsQueueHeartbeatData {
1401 pub status: QueueHeartbeatStatus,
1402 pub name: String,
1403 pub region: Option<String>,
1404 pub queue_url: Option<String>,
1405 pub queue_arn: Option<String>,
1406 pub visibility_timeout_seconds: Option<u32>,
1407 pub message_retention_period_seconds: Option<u32>,
1408 pub delay_seconds: Option<u32>,
1409 pub receive_message_wait_time_seconds: Option<u32>,
1410 pub maximum_message_size: Option<u32>,
1411 pub redrive_policy: Option<String>,
1412 pub redrive_allow_policy: Option<String>,
1413 pub fifo_queue: Option<bool>,
1414 pub content_based_deduplication: Option<bool>,
1415 pub deduplication_scope: Option<String>,
1416 pub fifo_throughput_limit: Option<String>,
1417 pub sse_enabled: Option<bool>,
1418 pub kms_master_key_id: Option<String>,
1419 pub kms_data_key_reuse_period_seconds: Option<u32>,
1420 pub sqs_managed_sse_enabled: Option<bool>,
1421 pub approximate_visible_messages: Option<u64>,
1422 pub approximate_in_flight_messages: Option<u64>,
1423 pub approximate_delayed_messages: Option<u64>,
1424 pub approximate_counts: bool,
1425}
1426
1427#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1428#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1429#[serde(tag = "backend", rename_all = "camelCase")]
1430pub enum KvHeartbeatData {
1431 AwsDynamoDb(AwsDynamoDbKvHeartbeatData),
1432 GcpFirestore(GcpFirestoreKvHeartbeatData),
1433 AzureTable(AzureTableKvHeartbeatData),
1434 Local(LocalKvHeartbeatData),
1435}
1436
1437#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1438#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1439#[serde(rename_all = "camelCase")]
1440pub struct KvHeartbeatStatus {
1441 pub health: ObservedHealth,
1442 pub lifecycle: ProviderLifecycleState,
1443 pub message: Option<String>,
1444 pub stale: bool,
1445 pub partial: bool,
1446 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1447}
1448
1449impl Default for KvHeartbeatStatus {
1450 fn default() -> Self {
1451 Self {
1452 health: ObservedHealth::Unknown,
1453 lifecycle: ProviderLifecycleState::Unknown,
1454 message: None,
1455 stale: false,
1456 partial: false,
1457 collection_issues: vec![],
1458 }
1459 }
1460}
1461
1462#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1463#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1464#[serde(rename_all = "camelCase")]
1465pub struct AwsDynamoDbKvHeartbeatData {
1466 pub status: KvHeartbeatStatus,
1467 pub name: String,
1468 pub region: Option<String>,
1469 pub table_arn: Option<String>,
1470 pub table_status: Option<String>,
1471 pub billing_mode: Option<String>,
1472 pub key_schema: Vec<AwsDynamoDbKeySchemaElement>,
1473 pub global_secondary_index_count: Option<u32>,
1474 pub local_secondary_index_count: Option<u32>,
1475 pub item_count: Option<u64>,
1476 pub table_size_bytes: Option<u64>,
1477 pub stream_enabled: Option<bool>,
1478 pub stream_view_type: Option<String>,
1479 pub ttl_status: Option<String>,
1480 pub ttl_attribute_name: Option<String>,
1481 pub deletion_protection_enabled: Option<bool>,
1482 pub sse_status: Option<String>,
1483 pub sse_type: Option<String>,
1484 pub table_class: Option<String>,
1485 pub replica_count: Option<u32>,
1486 pub restore_in_progress: Option<bool>,
1487}
1488
1489#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1490#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1491#[serde(rename_all = "camelCase")]
1492pub struct AwsDynamoDbKeySchemaElement {
1493 pub attribute_name: String,
1494 pub key_type: String,
1495}
1496
1497#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1498#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1499#[serde(rename_all = "camelCase")]
1500pub struct GcpFirestoreKvHeartbeatData {
1501 pub status: KvHeartbeatStatus,
1502 pub database_name: String,
1503 pub project_id: Option<String>,
1504 pub endpoint: Option<String>,
1505 pub location_id: Option<String>,
1506 pub database_type: Option<String>,
1507 pub concurrency_mode: Option<String>,
1508 pub app_engine_integration_mode: Option<String>,
1509 pub delete_protection_state: Option<String>,
1510 pub point_in_time_recovery_enablement: Option<String>,
1511 pub version_retention_period: Option<String>,
1512 pub earliest_version_time: Option<String>,
1513 pub create_time: Option<String>,
1514 pub update_time: Option<String>,
1515 pub delete_time: Option<String>,
1516 pub database_edition: Option<String>,
1517 pub cmek_enabled: bool,
1518 pub source_info_present: bool,
1519}
1520
1521#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1522#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1523#[serde(rename_all = "camelCase")]
1524pub struct AzureTableKvHeartbeatData {
1525 pub status: KvHeartbeatStatus,
1526 pub table_name: String,
1527 pub storage_account_name: String,
1528 pub resource_group: Option<String>,
1529 pub endpoint: Option<String>,
1530 pub storage_account_resource_id: Option<String>,
1531 pub storage_account_location: Option<String>,
1532 pub storage_account_kind: Option<String>,
1533 pub storage_account_provisioning_state: Option<String>,
1534 pub storage_account_primary_status: Option<String>,
1535 pub table_exists: bool,
1536 pub signed_identifier_count: Option<u32>,
1537}
1538
1539#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1540#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1541#[serde(rename_all = "camelCase")]
1542pub struct LocalKvHeartbeatData {
1543 pub status: KvHeartbeatStatus,
1544 pub name: String,
1545 pub path: String,
1546 pub path_exists: bool,
1547 pub is_directory: Option<bool>,
1548 pub cloud_metadata_supported: bool,
1549}
1550
1551#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1552#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1553#[serde(tag = "backend", rename_all = "camelCase")]
1554pub enum PostgresHeartbeatData {
1555 Aurora(AuroraPostgresHeartbeatData),
1557 CloudSql(GcpCloudSqlPostgresHeartbeatData),
1559 FlexibleServer(AzureFlexibleServerPostgresHeartbeatData),
1561 Local(LocalPostgresHeartbeatData),
1563}
1564
1565#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1566#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1567#[serde(rename_all = "camelCase")]
1568pub struct PostgresHeartbeatStatus {
1569 pub health: ObservedHealth,
1570 pub lifecycle: ProviderLifecycleState,
1571 pub message: Option<String>,
1572 pub stale: bool,
1573 pub partial: bool,
1574 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1575}
1576
1577impl Default for PostgresHeartbeatStatus {
1578 fn default() -> Self {
1579 Self {
1580 health: ObservedHealth::Unknown,
1581 lifecycle: ProviderLifecycleState::Unknown,
1582 message: None,
1583 stale: false,
1584 partial: false,
1585 collection_issues: vec![],
1586 }
1587 }
1588}
1589
1590#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1595#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1596#[serde(tag = "backend", rename_all = "camelCase")]
1597pub enum SandboxHeartbeatData {
1598 AwsMicrovm(AwsMicrovmSandboxHeartbeatData),
1599 AzureSandboxGroup(AzureSandboxGroupHeartbeatData),
1600 KubernetesPods(KubernetesSandboxHeartbeatData),
1601 Local(LocalSandboxHeartbeatData),
1602}
1603
1604#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1605#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1606#[serde(rename_all = "camelCase")]
1607pub struct SandboxHeartbeatStatus {
1608 pub health: ObservedHealth,
1609 pub lifecycle: ProviderLifecycleState,
1610 pub message: Option<String>,
1611 pub stale: bool,
1612 pub partial: bool,
1613 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1614}
1615
1616impl Default for SandboxHeartbeatStatus {
1617 fn default() -> Self {
1618 Self {
1619 health: ObservedHealth::Healthy,
1620 lifecycle: ProviderLifecycleState::Running,
1621 message: None,
1622 stale: false,
1623 partial: false,
1624 collection_issues: Vec::new(),
1625 }
1626 }
1627}
1628
1629#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1631#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1632#[serde(rename_all = "camelCase")]
1633pub struct AwsMicrovmSandboxHeartbeatData {
1634 pub status: SandboxHeartbeatStatus,
1635 pub image_identifier: String,
1637 pub image_state: Option<String>,
1644}
1645
1646#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1649#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1650#[serde(rename_all = "camelCase")]
1651pub struct AzureSandboxGroupHeartbeatData {
1652 pub status: SandboxHeartbeatStatus,
1653 pub sandbox_group: String,
1654 pub provisioning_state: Option<String>,
1655}
1656
1657#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1659#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1660#[serde(rename_all = "camelCase")]
1661pub struct KubernetesSandboxHeartbeatData {
1662 pub status: SandboxHeartbeatStatus,
1663 pub namespace: String,
1664 pub active_sessions: u32,
1665 pub idle_pods: u32,
1667}
1668
1669#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1671#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1672#[serde(rename_all = "camelCase")]
1673pub struct LocalSandboxHeartbeatData {
1674 pub status: SandboxHeartbeatStatus,
1675 pub active_sessions: u32,
1676 pub route_serving: bool,
1679}
1680
1681#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1682#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1683#[serde(tag = "backend", rename_all = "camelCase")]
1684pub enum AiHeartbeatData {
1685 AwsBedrock(AwsBedrockAiHeartbeatData),
1686 GcpVertex(GcpVertexAiHeartbeatData),
1687 AzureFoundry(AzureFoundryAiHeartbeatData),
1688 External(ExternalAiHeartbeatData),
1689}
1690
1691#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1692#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1693#[serde(rename_all = "camelCase")]
1694pub struct AiHeartbeatStatus {
1695 pub health: ObservedHealth,
1696 pub lifecycle: ProviderLifecycleState,
1697 pub message: Option<String>,
1698 pub stale: bool,
1699 pub partial: bool,
1700 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1701}
1702
1703impl Default for AiHeartbeatStatus {
1704 fn default() -> Self {
1705 Self {
1707 health: ObservedHealth::Unknown,
1708 lifecycle: ProviderLifecycleState::Unknown,
1709 message: None,
1710 stale: false,
1711 partial: false,
1712 collection_issues: vec![],
1713 }
1714 }
1715}
1716
1717#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1720#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1721#[serde(rename_all = "kebab-case")]
1722pub enum AiAvailabilitySource {
1723 AwsBedrock,
1724 GcpVertex,
1725 AzureFoundry,
1726 Anthropic,
1727}
1728
1729#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1730#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1731#[serde(rename_all = "kebab-case")]
1732pub enum AiModelAvailability {
1733 Available,
1734 Blocked,
1735 Unknown,
1736}
1737
1738#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1739#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1740#[serde(rename_all = "kebab-case")]
1741pub enum AiAvailabilityBlocker {
1742 AgreementRequired,
1743 EntitlementRequired,
1744 ModelActivationRequired,
1745 DeploymentRequired,
1746 QuotaConfigurationRequired,
1747 RegionUnavailable,
1748 AccessDenied,
1749 ObservationFailed,
1750}
1751
1752#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1753#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1754#[serde(rename_all = "kebab-case")]
1755pub enum AiAccessTest {
1756 Verified,
1757 Failed,
1758 NotChecked,
1759}
1760
1761#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1762#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1763#[serde(rename_all = "camelCase")]
1764pub struct AiModelAvailabilityObservation {
1765 pub public_model_id: String,
1766 pub client_apis: Vec<ClientApi>,
1767 pub availability: AiModelAvailability,
1768 pub blockers: Vec<AiAvailabilityBlocker>,
1769 pub access_test: AiAccessTest,
1770 #[serde(skip_serializing_if = "Option::is_none")]
1771 pub tested_at: Option<DateTime<Utc>>,
1772 #[serde(skip_serializing_if = "Option::is_none")]
1773 pub error_code: Option<String>,
1774}
1775
1776#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1777#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1778#[serde(rename_all = "camelCase")]
1779pub struct AiAvailabilityObservation {
1780 pub source: AiAvailabilitySource,
1781 pub catalog_revision: String,
1782 #[serde(skip_serializing_if = "Option::is_none")]
1783 pub location: Option<String>,
1784 pub models: Vec<AiModelAvailabilityObservation>,
1785}
1786
1787impl AiAvailabilityObservation {
1788 pub fn unobserved(
1791 source: AiAvailabilitySource,
1792 platform: Platform,
1793 location: Option<String>,
1794 ) -> Self {
1795 Self {
1796 source,
1797 catalog_revision: crate::ai_catalog::AI_CATALOG_REVISION.to_string(),
1798 location,
1799 models: crate::ai_catalog::models_for(platform)
1800 .into_iter()
1801 .map(|model| AiModelAvailabilityObservation {
1802 public_model_id: model.public_id.to_string(),
1803 client_apis: ClientApi::ALL.to_vec(),
1804 availability: AiModelAvailability::Unknown,
1805 blockers: vec![AiAvailabilityBlocker::ObservationFailed],
1806 access_test: AiAccessTest::NotChecked,
1807 tested_at: None,
1808 error_code: None,
1809 })
1810 .collect(),
1811 }
1812 }
1813}
1814
1815#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1816#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1817#[serde(rename_all = "camelCase")]
1818pub struct LocalPostgresHeartbeatData {
1819 pub status: PostgresHeartbeatStatus,
1820 pub name: String,
1821 pub port: Option<u16>,
1822 pub version: String,
1823 pub process_running: bool,
1824}
1825
1826#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1827#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1828#[serde(rename_all = "camelCase")]
1829pub struct AuroraPostgresHeartbeatData {
1830 pub status: PostgresHeartbeatStatus,
1831 pub cluster_identifier: String,
1832 #[serde(skip_serializing_if = "Option::is_none")]
1833 pub engine_version: Option<String>,
1834 #[serde(skip_serializing_if = "Option::is_none")]
1835 pub endpoint: Option<String>,
1836 #[serde(skip_serializing_if = "Option::is_none")]
1838 pub serverless_capacity: Option<f64>,
1839 pub never_pauses: bool,
1842}
1843
1844#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1845#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1846#[serde(rename_all = "camelCase")]
1847pub struct GcpCloudSqlPostgresHeartbeatData {
1848 pub status: PostgresHeartbeatStatus,
1849 pub instance_name: String,
1850 #[serde(skip_serializing_if = "Option::is_none")]
1851 pub state: Option<String>,
1852 #[serde(skip_serializing_if = "Option::is_none")]
1853 pub database_version: Option<String>,
1854}
1855
1856#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1857#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1858#[serde(rename_all = "camelCase")]
1859pub struct AzureFlexibleServerPostgresHeartbeatData {
1860 pub status: PostgresHeartbeatStatus,
1861 pub server_name: String,
1862 #[serde(skip_serializing_if = "Option::is_none")]
1863 pub state: Option<String>,
1864 #[serde(skip_serializing_if = "Option::is_none")]
1865 pub version: Option<String>,
1866}
1867
1868#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1869#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1870#[serde(rename_all = "camelCase")]
1871pub struct AwsBedrockAiHeartbeatData {
1872 pub status: AiHeartbeatStatus,
1873 pub region: String,
1874 pub availability: AiAvailabilityObservation,
1875}
1876
1877#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1878#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1879#[serde(rename_all = "camelCase")]
1880pub struct GcpVertexAiHeartbeatData {
1881 pub status: AiHeartbeatStatus,
1882 pub project: String,
1883 pub location: String,
1884 pub availability: AiAvailabilityObservation,
1885}
1886
1887#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1888#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1889#[serde(rename_all = "camelCase")]
1890pub struct AzureFoundryAiHeartbeatData {
1891 pub status: AiHeartbeatStatus,
1892 pub account_name: String,
1893 pub endpoint: Option<String>,
1894 pub resource_group: Option<String>,
1895 pub location: Option<String>,
1896 pub availability: AiAvailabilityObservation,
1897}
1898
1899#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1900#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1901#[serde(rename_all = "camelCase")]
1902pub struct ExternalAiHeartbeatData {
1903 pub status: AiHeartbeatStatus,
1904 pub provider: String,
1907 #[serde(skip_serializing_if = "Option::is_none")]
1908 pub availability: Option<AiAvailabilityObservation>,
1909}
1910
1911#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1912#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1913#[serde(tag = "backend", rename_all = "camelCase")]
1914pub enum VaultHeartbeatData {
1915 AwsParameterStore(AwsParameterStoreVaultHeartbeatData),
1916 GcpSecretManager(GcpSecretManagerVaultHeartbeatData),
1917 AzureKeyVault(AzureKeyVaultHeartbeatData),
1918 KubernetesSecret(KubernetesSecretVaultHeartbeatData),
1919 Local(LocalVaultHeartbeatData),
1920}
1921
1922#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1923#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1924#[serde(rename_all = "camelCase")]
1925pub struct VaultHeartbeatStatus {
1926 pub health: ObservedHealth,
1927 pub lifecycle: ProviderLifecycleState,
1928 pub message: Option<String>,
1929 pub stale: bool,
1930 pub partial: bool,
1931 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1932}
1933
1934impl Default for VaultHeartbeatStatus {
1935 fn default() -> Self {
1936 Self {
1937 health: ObservedHealth::Healthy,
1938 lifecycle: ProviderLifecycleState::Running,
1939 message: None,
1940 stale: false,
1941 partial: false,
1942 collection_issues: vec![],
1943 }
1944 }
1945}
1946
1947#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1948#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1949#[serde(rename_all = "camelCase")]
1950pub struct AwsParameterStoreVaultHeartbeatData {
1951 pub status: VaultHeartbeatStatus,
1952 pub account_id: String,
1953 pub region: String,
1954 pub prefix: String,
1955 pub parameter_metadata_sampled: bool,
1956 pub sampled_parameter_count: Option<u32>,
1957 pub sampled_secure_string_count: Option<u32>,
1958 pub sampled_string_count: Option<u32>,
1959 pub sampled_string_list_count: Option<u32>,
1960 pub sampled_advanced_tier_count: Option<u32>,
1961 pub sampled_kms_key_metadata_present_count: Option<u32>,
1962 pub latest_modified_at: Option<DateTime<Utc>>,
1963 pub has_more_parameters: Option<bool>,
1964}
1965
1966#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1967#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1968#[serde(rename_all = "camelCase")]
1969pub struct GcpSecretManagerVaultHeartbeatData {
1970 pub status: VaultHeartbeatStatus,
1971 pub project_id: String,
1972 pub location: String,
1973 pub prefix: String,
1974 pub secret_metadata_listed: bool,
1975}
1976
1977#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1978#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1979#[serde(rename_all = "camelCase")]
1980pub struct AzureKeyVaultHeartbeatData {
1981 pub status: VaultHeartbeatStatus,
1982 pub name: String,
1983 pub resource_group: Option<String>,
1984 pub resource_id: Option<String>,
1985 pub location: Option<String>,
1986 pub vault_uri: Option<String>,
1987 pub provisioning_state: Option<String>,
1988 pub sku_family: Option<String>,
1989 pub sku_name: Option<String>,
1990 pub soft_delete_enabled: bool,
1991 pub soft_delete_retention_days: i32,
1992 pub purge_protection_enabled: Option<bool>,
1993 pub rbac_authorization_enabled: bool,
1994 pub public_network_access: String,
1995 pub access_policy_count: u32,
1996 pub private_endpoint_connection_count: u32,
1997 pub secret_metadata_listed: bool,
1998}
1999
2000#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2001#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2002#[serde(rename_all = "camelCase")]
2003pub struct KubernetesSecretVaultHeartbeatData {
2004 pub status: VaultHeartbeatStatus,
2005 pub namespace: String,
2006 pub prefix: String,
2007 pub secret_metadata_listed: bool,
2008}
2009
2010#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2011#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2012#[serde(rename_all = "camelCase")]
2013pub struct LocalVaultHeartbeatData {
2014 pub status: VaultHeartbeatStatus,
2015 pub path: String,
2016 pub path_exists: bool,
2017 pub is_directory: Option<bool>,
2018 pub readonly: Option<bool>,
2019 pub modified_at: Option<DateTime<Utc>>,
2020 pub secret_metadata_listed: bool,
2021}
2022
2023#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2024#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2025#[serde(tag = "backend", rename_all = "camelCase")]
2026pub enum ServiceAccountHeartbeatData {
2027 AwsIamRole(AwsIamRoleServiceAccountHeartbeatData),
2028 GcpServiceAccount(GcpServiceAccountHeartbeatData),
2029 AzureManagedIdentity(AzureManagedIdentityServiceAccountHeartbeatData),
2030 Local(LocalServiceAccountHeartbeatData),
2031}
2032
2033#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2034#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2035#[serde(rename_all = "camelCase")]
2036pub struct ServiceAccountHeartbeatStatus {
2037 pub health: ObservedHealth,
2038 pub lifecycle: ProviderLifecycleState,
2039 pub message: Option<String>,
2040 pub stale: bool,
2041 pub partial: bool,
2042 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2043}
2044
2045#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2046#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2047#[serde(rename_all = "camelCase")]
2048pub struct AwsIamRoleServiceAccountHeartbeatData {
2049 pub status: ServiceAccountHeartbeatStatus,
2050 pub role_name: String,
2051 pub role_arn: String,
2052 pub role_id: String,
2053 pub path: String,
2054 pub create_date: String,
2055 pub description: Option<String>,
2056 pub max_session_duration: Option<i32>,
2057 pub assume_role_policy_present: bool,
2058 pub permissions_boundary_type: Option<String>,
2059 pub permissions_boundary_arn: Option<String>,
2060 pub tag_count: u32,
2061 pub managed_tag_count: u32,
2062 pub attached_policy_count: u32,
2063 pub attached_policy_names: Vec<String>,
2064 pub inline_policy_count: u32,
2065 pub inline_policy_names: Vec<String>,
2066 pub stack_permissions_applied: bool,
2067 pub last_used_date: Option<String>,
2068 pub last_used_region: Option<String>,
2069}
2070
2071#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2072#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2073#[serde(rename_all = "camelCase")]
2074pub struct GcpServiceAccountHeartbeatData {
2075 pub status: ServiceAccountHeartbeatStatus,
2076 pub name: Option<String>,
2077 pub project_id: Option<String>,
2078 pub unique_id: Option<String>,
2079 pub email: String,
2080 pub display_name: Option<String>,
2081 pub description: Option<String>,
2082 pub oauth2_client_id: Option<String>,
2083 pub disabled: Option<bool>,
2084 pub etag: Option<String>,
2085 pub project_binding_count: u32,
2086 pub project_roles: Vec<String>,
2087 pub service_account_binding_count: u32,
2088 pub service_account_roles: Vec<String>,
2089}
2090
2091#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2092#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2093#[serde(rename_all = "camelCase")]
2094pub struct AzureManagedIdentityServiceAccountHeartbeatData {
2095 pub status: ServiceAccountHeartbeatStatus,
2096 pub name: String,
2097 pub resource_id: String,
2098 pub resource_group: String,
2099 pub location: String,
2100 pub type_: Option<String>,
2101 pub client_id: Option<String>,
2102 pub principal_id: Option<String>,
2103 pub tenant_id: Option<String>,
2104 pub isolation_scope: Option<String>,
2105 pub managed_tag_count: u32,
2106 pub role_assignment_count: u32,
2107 pub role_assignment_ids: Vec<String>,
2108 pub custom_role_definition_count: u32,
2109 pub custom_role_definition_ids: Vec<String>,
2110 pub stack_permissions_applied: bool,
2111}
2112
2113#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2114#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2115#[serde(rename_all = "camelCase")]
2116pub struct LocalServiceAccountHeartbeatData {
2117 pub status: ServiceAccountHeartbeatStatus,
2118 pub identity: String,
2119 pub configured: bool,
2120}
2121
2122#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2123#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2124#[serde(tag = "backend", rename_all = "camelCase")]
2125pub enum NetworkHeartbeatData {
2126 AwsVpc(AwsVpcNetworkHeartbeatData),
2127 GcpVpc(GcpVpcNetworkHeartbeatData),
2128 AzureVnet(AzureVnetNetworkHeartbeatData),
2129}
2130
2131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2132#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2133#[serde(rename_all = "camelCase")]
2134pub struct NetworkHeartbeatStatus {
2135 pub health: ObservedHealth,
2136 pub lifecycle: ProviderLifecycleState,
2137 pub message: Option<String>,
2138 pub stale: bool,
2139 pub partial: bool,
2140 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2141}
2142
2143#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2144#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2145#[serde(rename_all = "camelCase")]
2146pub struct AwsVpcNetworkHeartbeatData {
2147 pub status: NetworkHeartbeatStatus,
2148 pub vpc_id: Option<String>,
2149 pub vpc_state: Option<String>,
2150 pub cidr_block: Option<String>,
2151 pub public_subnet_ids: Vec<String>,
2152 pub private_subnet_ids: Vec<String>,
2153 pub availability_zones: Vec<String>,
2154 pub internet_gateway_id: Option<String>,
2155 pub nat_gateway_id: Option<String>,
2156 pub route_table_count: u32,
2157 pub security_group_id: Option<String>,
2158 pub is_byo_vpc: bool,
2159}
2160
2161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2162#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2163#[serde(rename_all = "camelCase")]
2164pub struct GcpVpcNetworkHeartbeatData {
2165 pub status: NetworkHeartbeatStatus,
2166 pub network_name: Option<String>,
2167 pub network_self_link: Option<String>,
2168 pub subnetwork_name: Option<String>,
2169 pub subnetwork_self_link: Option<String>,
2170 pub region: Option<String>,
2171 pub cidr_block: Option<String>,
2172 pub router_name: Option<String>,
2173 pub cloud_nat_name: Option<String>,
2174 pub firewall_name: Option<String>,
2175 pub is_byo_vpc: bool,
2176}
2177
2178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2179#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2180#[serde(rename_all = "camelCase")]
2181pub struct AzureVnetNetworkHeartbeatData {
2182 pub status: NetworkHeartbeatStatus,
2183 pub vnet_name: Option<String>,
2184 pub vnet_resource_id: Option<String>,
2185 pub resource_group: Option<String>,
2186 pub location: Option<String>,
2187 pub cidr_block: Option<String>,
2188 pub public_subnet_name: Option<String>,
2189 pub private_subnet_name: Option<String>,
2190 pub application_gateway_subnet_name: Option<String>,
2191 pub private_endpoint_subnet_name: Option<String>,
2192 pub nat_gateway_id: Option<String>,
2193 pub public_ip_id: Option<String>,
2194 pub nsg_id: Option<String>,
2195 pub is_byo_vnet: bool,
2196 pub last_byo_vnet_verification_error_code: Option<String>,
2197}
2198
2199#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2200#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2201#[serde(tag = "backend", rename_all = "camelCase")]
2202pub enum RemoteStackManagementHeartbeatData {
2203 AwsIamRole(AwsRemoteStackManagementHeartbeatData),
2204 GcpServiceAccount(GcpRemoteStackManagementHeartbeatData),
2205 AzureManagedIdentity(AzureRemoteStackManagementHeartbeatData),
2206}
2207
2208#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2209#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2210#[serde(rename_all = "camelCase")]
2211pub struct RemoteStackManagementHeartbeatStatus {
2212 pub health: ObservedHealth,
2213 pub lifecycle: ProviderLifecycleState,
2214 pub message: Option<String>,
2215 pub stale: bool,
2216 pub partial: bool,
2217 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2218}
2219
2220#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2221#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2222#[serde(rename_all = "camelCase")]
2223pub struct AwsRemoteStackManagementHeartbeatData {
2224 pub status: RemoteStackManagementHeartbeatStatus,
2225 pub role_name: Option<String>,
2226 pub role_arn: Option<String>,
2227 pub management_permissions_applied: bool,
2228}
2229
2230#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2231#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2232#[serde(rename_all = "camelCase")]
2233pub struct GcpRemoteStackManagementHeartbeatData {
2234 pub status: RemoteStackManagementHeartbeatStatus,
2235 pub service_account_email: Option<String>,
2236 pub service_account_unique_id: Option<String>,
2237 pub role_bound: bool,
2238 pub impersonation_granted: bool,
2239}
2240
2241#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2242#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2243#[serde(rename_all = "camelCase")]
2244pub struct AzureRemoteStackManagementHeartbeatData {
2245 pub status: RemoteStackManagementHeartbeatStatus,
2246 pub uami_resource_id: Option<String>,
2247 pub uami_client_id: Option<String>,
2248 pub uami_principal_id: Option<String>,
2249 pub tenant_id: Option<String>,
2250 pub fic_name: Option<String>,
2251 pub role_definition_id: Option<String>,
2252 pub role_assignment_ids: Vec<String>,
2253}
2254
2255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2256#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2257#[serde(tag = "backend", rename_all = "camelCase")]
2258pub enum ArtifactRegistryHeartbeatData {
2259 AwsEcr(AwsEcrArtifactRegistryHeartbeatData),
2260 GcpArtifactRegistry(GcpArtifactRegistryHeartbeatData),
2261 AzureContainerRegistry(AzureContainerRegistryHeartbeatData),
2262 Local(LocalArtifactRegistryHeartbeatData),
2263}
2264
2265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2266#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2267#[serde(rename_all = "camelCase")]
2268pub struct ArtifactRegistryHeartbeatStatus {
2269 pub health: ObservedHealth,
2270 pub lifecycle: ProviderLifecycleState,
2271 pub message: Option<String>,
2272 pub stale: bool,
2273 pub partial: bool,
2274 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2275}
2276
2277#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2278#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2279#[serde(rename_all = "camelCase")]
2280pub struct AwsEcrArtifactRegistryHeartbeatData {
2281 pub status: ArtifactRegistryHeartbeatStatus,
2282 pub registry_id: String,
2283 pub region: String,
2284 pub registry_uri: String,
2285 pub repository_prefix: String,
2286 pub pull_role_arn: Option<String>,
2287 pub push_role_arn: Option<String>,
2288 pub repository_count: u32,
2289 pub repositories_truncated: bool,
2290 pub repositories: Vec<AwsEcrRepositoryHeartbeatData>,
2291}
2292
2293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2294#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2295#[serde(rename_all = "camelCase")]
2296pub struct AwsEcrRepositoryHeartbeatData {
2297 pub repository_arn: String,
2298 pub registry_id: String,
2299 pub repository_name: String,
2300 pub repository_uri: String,
2301 pub created_at: f64,
2302 pub image_tag_mutability: Option<String>,
2303 pub scan_on_push: Option<bool>,
2304 pub encryption_type: Option<String>,
2305 pub kms_key_present: bool,
2306}
2307
2308#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2309#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2310#[serde(rename_all = "camelCase")]
2311pub struct GcpArtifactRegistryHeartbeatData {
2312 pub status: ArtifactRegistryHeartbeatStatus,
2313 pub project_id: String,
2314 pub location: String,
2315 pub repository_id: String,
2316 pub name: Option<String>,
2317 pub format: Option<String>,
2318 pub mode: Option<String>,
2319 pub description: Option<String>,
2320 pub label_count: u32,
2321 pub cleanup_policy_count: u32,
2322 pub cleanup_policy_dry_run: Option<bool>,
2323 pub kms_key_name_present: bool,
2324 pub size_bytes: Option<String>,
2325 pub satisfies_pzs: Option<bool>,
2326 pub create_time: Option<String>,
2327 pub update_time: Option<String>,
2328 pub iam_policy_etag_present: bool,
2329 pub iam_binding_count: u32,
2330 pub iam_roles: Vec<String>,
2331 pub pull_service_account_email: Option<String>,
2332 pub push_service_account_email: Option<String>,
2333}
2334
2335#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2336#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2337#[serde(rename_all = "camelCase")]
2338pub struct AzureContainerRegistryHeartbeatData {
2339 pub status: ArtifactRegistryHeartbeatStatus,
2340 pub name: String,
2341 pub resource_id: Option<String>,
2342 pub resource_group: String,
2343 pub location: String,
2344 pub type_: Option<String>,
2345 pub login_server: Option<String>,
2346 pub sku_name: String,
2347 pub sku_tier: Option<String>,
2348 pub provisioning_state: Option<String>,
2349 pub admin_user_enabled: bool,
2350 pub anonymous_pull_enabled: bool,
2351 pub public_network_access: String,
2352 pub network_rule_bypass_options: String,
2353 pub network_rule_default_action: Option<String>,
2354 pub ip_rule_count: u32,
2355 pub encryption_status: Option<String>,
2356 pub encryption_key_vault_uri_present: bool,
2357 pub encryption_key_identifier_present: bool,
2358 pub policies_present: bool,
2359 pub policy_count: u32,
2360 pub private_endpoint_connection_count: u32,
2361 pub data_endpoint_enabled: Option<bool>,
2362 pub data_endpoint_host_names: Vec<String>,
2363 pub zone_redundancy: String,
2364 pub creation_date: Option<String>,
2365 pub managed_tag_count: u32,
2366}
2367
2368#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2369#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2370#[serde(rename_all = "camelCase")]
2371pub struct LocalArtifactRegistryHeartbeatData {
2372 pub status: ArtifactRegistryHeartbeatStatus,
2373 pub registry_url: String,
2374 pub reachable: bool,
2375}
2376
2377#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2378#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2379#[serde(tag = "backend", rename_all = "camelCase")]
2380pub enum BuildHeartbeatData {
2381 AwsCodeBuild(AwsCodeBuildHeartbeatData),
2382 GcpCloudBuild(GcpCloudBuildHeartbeatData),
2383 AzureContainerApps(AzureContainerAppsBuildHeartbeatData),
2384 KubernetesJob(KubernetesBuildHeartbeatData),
2385}
2386
2387#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2388#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2389#[serde(rename_all = "camelCase")]
2390pub struct BuildHeartbeatStatus {
2391 pub health: ObservedHealth,
2392 pub lifecycle: ProviderLifecycleState,
2393 pub message: Option<String>,
2394 pub stale: bool,
2395 pub partial: bool,
2396 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2397}
2398
2399#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2400#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2401#[serde(rename_all = "camelCase")]
2402pub struct AwsCodeBuildHeartbeatData {
2403 pub status: BuildHeartbeatStatus,
2404 pub project_name: String,
2405 pub project_arn: Option<String>,
2406 pub description: Option<String>,
2407 pub source_type: Option<String>,
2408 pub artifacts_type: Option<String>,
2409 pub artifacts_encryption_disabled: Option<bool>,
2410 pub environment_type: Option<String>,
2411 pub environment_image: Option<String>,
2412 pub compute_type: Option<String>,
2413 pub image_pull_credentials_type: Option<String>,
2414 pub privileged_mode: Option<bool>,
2415 pub environment_variable_count: u32,
2416 pub service_role_present: bool,
2417 pub encryption_key_present: bool,
2418 pub cloud_watch_logs_status: Option<String>,
2419 pub s3_logs_status: Option<String>,
2420 pub timeout_in_minutes: Option<i32>,
2421 pub queued_timeout_in_minutes: Option<i32>,
2422 pub created: Option<f64>,
2423 pub last_modified: Option<f64>,
2424}
2425
2426#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2427#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2428#[serde(rename_all = "camelCase")]
2429pub struct GcpCloudBuildHeartbeatData {
2430 pub status: BuildHeartbeatStatus,
2431 pub project_id: String,
2432 pub location: String,
2433 pub build_config_id: String,
2434 pub service_account: Option<String>,
2435 pub environment_variable_count: u32,
2436}
2437
2438#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2439#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2440#[serde(rename_all = "camelCase")]
2441pub struct AzureContainerAppsBuildHeartbeatData {
2442 pub status: BuildHeartbeatStatus,
2443 pub managed_environment_id: String,
2444 pub resource_group_name: String,
2445 pub managed_identity_id: Option<String>,
2446 pub resource_prefix: Option<String>,
2447 pub environment_variable_count: u32,
2448}
2449
2450#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2451#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2452#[serde(rename_all = "camelCase")]
2453pub struct KubernetesBuildHeartbeatData {
2454 pub status: BuildHeartbeatStatus,
2455 pub job_name: String,
2456 pub namespace: String,
2457 pub active: Option<i32>,
2458 pub succeeded: Option<i32>,
2459 pub failed: Option<i32>,
2460 pub start_time: Option<DateTime<Utc>>,
2461 pub completion_time: Option<DateTime<Utc>>,
2462 pub condition_count: u32,
2463 pub image_digest: Option<String>,
2464 pub events: Vec<KubernetesEventSnapshot>,
2465}
2466
2467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2468#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2469#[serde(tag = "backend", rename_all = "camelCase")]
2470pub enum ServiceActivationHeartbeatData {
2471 GcpServiceUsage(GcpServiceUsageActivationHeartbeatData),
2472 AzureResourceProvider(AzureResourceProviderActivationHeartbeatData),
2473}
2474
2475#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2476#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2477#[serde(rename_all = "camelCase")]
2478pub struct ServiceActivationHeartbeatStatus {
2479 pub health: ObservedHealth,
2480 pub lifecycle: ProviderLifecycleState,
2481 pub message: Option<String>,
2482 pub stale: bool,
2483 pub partial: bool,
2484 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2485}
2486
2487impl Default for ServiceActivationHeartbeatStatus {
2488 fn default() -> Self {
2489 Self {
2490 health: ObservedHealth::Healthy,
2491 lifecycle: ProviderLifecycleState::Running,
2492 message: None,
2493 stale: false,
2494 partial: false,
2495 collection_issues: vec![],
2496 }
2497 }
2498}
2499
2500#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2501#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2502#[serde(rename_all = "camelCase")]
2503pub struct GcpServiceUsageActivationHeartbeatData {
2504 pub status: ServiceActivationHeartbeatStatus,
2505 pub project_id: String,
2506 pub service_name: String,
2507 pub service_resource_name: Option<String>,
2508 pub title: Option<String>,
2509 pub state: Option<String>,
2510 pub enabled: bool,
2511 pub last_operation_name: Option<String>,
2512}
2513
2514#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2515#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2516#[serde(rename_all = "camelCase")]
2517pub struct AzureResourceProviderActivationHeartbeatData {
2518 pub status: ServiceActivationHeartbeatStatus,
2519 pub namespace: String,
2520 pub provider_id: Option<String>,
2521 pub registration_state: Option<String>,
2522 pub registration_policy: Option<String>,
2523 pub resource_type_count: u32,
2524 pub registered: bool,
2525}
2526
2527#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2528#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2529#[serde(rename_all = "camelCase")]
2530pub struct AzureResourceGroupHeartbeatData {
2531 pub status: AzureResourceGroupHeartbeatStatus,
2532 pub name: String,
2533 pub resource_id: Option<String>,
2534 pub location: Option<String>,
2535 pub provisioning_state: Option<String>,
2536 pub managed_tags: BTreeMap<String, String>,
2537}
2538
2539#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2540#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2541#[serde(rename_all = "camelCase")]
2542pub struct AzureResourceGroupHeartbeatStatus {
2543 pub health: ObservedHealth,
2544 pub lifecycle: ProviderLifecycleState,
2545 pub message: Option<String>,
2546 pub stale: bool,
2547 pub partial: bool,
2548 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2549}
2550
2551impl Default for AzureResourceGroupHeartbeatStatus {
2552 fn default() -> Self {
2553 Self {
2554 health: ObservedHealth::Healthy,
2555 lifecycle: ProviderLifecycleState::Running,
2556 message: None,
2557 stale: false,
2558 partial: false,
2559 collection_issues: vec![],
2560 }
2561 }
2562}
2563
2564#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2565#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2566#[serde(rename_all = "camelCase")]
2567pub struct AzureStorageAccountHeartbeatData {
2568 pub status: StorageHeartbeatStatus,
2569 pub name: String,
2570 pub resource_id: Option<String>,
2571 pub resource_group: Option<String>,
2572 pub location: Option<String>,
2573 pub kind: Option<String>,
2574 pub sku_name: Option<String>,
2575 pub sku_tier: Option<String>,
2576 pub provisioning_state: Option<String>,
2577 pub primary_endpoints: AzureStorageAccountEndpoints,
2578 pub secondary_endpoints: AzureStorageAccountEndpoints,
2579 pub public_network_access: Option<String>,
2580 pub allow_blob_public_access: Option<bool>,
2581 pub allow_shared_key_access: Option<bool>,
2582 pub minimum_tls_version: Option<String>,
2583 pub supports_https_traffic_only: Option<bool>,
2584 pub encryption_key_source: Option<String>,
2585 pub require_infrastructure_encryption: Option<bool>,
2586 pub network_default_action: Option<String>,
2587 pub network_bypass: Option<String>,
2588 pub network_ip_rule_count: Option<u32>,
2589 pub network_virtual_network_rule_count: Option<u32>,
2590 pub network_resource_access_rule_count: Option<u32>,
2591}
2592
2593#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
2594#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2595#[serde(rename_all = "camelCase")]
2596pub struct AzureStorageAccountEndpoints {
2597 pub blob: Option<String>,
2598 pub dfs: Option<String>,
2599 pub file: Option<String>,
2600 pub queue: Option<String>,
2601 pub table: Option<String>,
2602 pub web: Option<String>,
2603}
2604
2605#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2606#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2607#[serde(rename_all = "camelCase")]
2608pub struct AzureContainerAppsEnvironmentHeartbeatData {
2609 pub status: AzureContainerAppsEnvironmentHeartbeatStatus,
2610 pub name: String,
2611 pub resource_id: Option<String>,
2612 pub resource_group: Option<String>,
2613 pub location: Option<String>,
2614 pub kind: Option<String>,
2615 pub provisioning_state: Option<String>,
2616 pub default_domain: Option<String>,
2617 pub static_ip: Option<String>,
2618 pub custom_domain_verification_id: Option<String>,
2619 pub infrastructure_resource_group: Option<String>,
2620 pub event_stream_endpoint: Option<String>,
2621 pub zone_redundant: Option<bool>,
2622 pub workload_profile_count: u32,
2623 pub workload_profiles: Vec<AzureContainerAppsEnvironmentWorkloadProfile>,
2624}
2625
2626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2627#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2628#[serde(rename_all = "camelCase")]
2629pub struct AzureContainerAppsEnvironmentHeartbeatStatus {
2630 pub health: ObservedHealth,
2631 pub lifecycle: ProviderLifecycleState,
2632 pub message: Option<String>,
2633 pub stale: bool,
2634 pub partial: bool,
2635 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2636}
2637
2638#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2639#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2640#[serde(rename_all = "camelCase")]
2641pub struct AzureContainerAppsEnvironmentWorkloadProfile {
2642 pub name: String,
2643 pub workload_profile_type: String,
2644 pub minimum_count: Option<i32>,
2645 pub maximum_count: Option<i32>,
2646}
2647
2648#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2649#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2650#[serde(rename_all = "camelCase")]
2651pub struct AzureServiceBusNamespaceHeartbeatData {
2652 pub status: QueueHeartbeatStatus,
2653 pub name: String,
2654 pub resource_id: Option<String>,
2655 pub resource_group: Option<String>,
2656 pub location: Option<String>,
2657 pub sku_name: Option<String>,
2658 pub sku_tier: Option<String>,
2659 pub sku_capacity: Option<i32>,
2660 pub namespace_status: Option<String>,
2661 pub provisioning_state: Option<String>,
2662 pub service_bus_endpoint: Option<String>,
2663 pub metric_id: Option<String>,
2664 pub public_network_access: Option<String>,
2665 pub disable_local_auth: Option<bool>,
2666 pub minimum_tls_version: Option<String>,
2667 pub premium_messaging_partitions: Option<i32>,
2668 pub private_endpoint_connection_count: u32,
2669 pub zone_redundant: Option<bool>,
2670 pub created_at: Option<String>,
2671 pub updated_at: Option<String>,
2672}
2673
2674#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2675#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2676#[serde(rename_all = "camelCase")]
2677pub struct NamedResourceDetail {
2678 pub name: String,
2679 pub region: Option<String>,
2680}
2681
2682#[cfg(test)]
2683mod tests {
2684 use super::*;
2685 use chrono::TimeZone as _;
2686 use serde_json::json;
2687
2688 fn observed_at() -> DateTime<Utc> {
2689 Utc.with_ymd_and_hms(2026, 5, 28, 10, 30, 0).unwrap()
2690 }
2691
2692 fn workload_status() -> WorkloadHeartbeatStatus {
2693 WorkloadHeartbeatStatus {
2694 health: ObservedHealth::Healthy,
2695 lifecycle: ProviderLifecycleState::Running,
2696 message: None,
2697 stale: false,
2698 partial: false,
2699 collection_issues: vec![],
2700 }
2701 }
2702
2703 fn workload_replicas() -> WorkloadReplicaStatus {
2704 WorkloadReplicaStatus {
2705 desired: Some(2),
2706 current: Some(2),
2707 ready: Some(1),
2708 available: Some(1),
2709 updated: Some(2),
2710 misscheduled: None,
2711 }
2712 }
2713
2714 fn heartbeat(data: ResourceHeartbeatData, resource_type: &str) -> ResourceHeartbeat {
2715 ResourceHeartbeat {
2716 deployment_id: Some("dep_123".to_string()),
2717 resource_id: "api".to_string(),
2718 resource_type: ResourceType::from(resource_type),
2719 controller_platform: Platform::Kubernetes,
2720 backend: HeartbeatBackend::Kubernetes,
2721 observed_at: observed_at(),
2722 data,
2723 raw: vec![RawHeartbeatSnippet {
2724 source: "kubernetes/apps/v1/deployments/api".to_string(),
2725 format: RawHeartbeatSnippetFormat::Json,
2726 collected_at: observed_at(),
2727 body: r#"{"readyReplicas":1}"#.to_string(),
2728 truncated: false,
2729 }],
2730 }
2731 }
2732
2733 #[test]
2734 fn resource_heartbeat_roundtrips_managed_resource_data() {
2735 let heartbeat_json = serde_json::to_value(heartbeat(
2736 ResourceHeartbeatData::Container(ContainerHeartbeatData::Kubernetes(
2737 KubernetesContainerHeartbeatData {
2738 status: workload_status(),
2739 namespace: "default".to_string(),
2740 name: "api".to_string(),
2741 workload_kind: KubernetesWorkloadKind::Deployment,
2742 replicas: workload_replicas(),
2743 restarts: None,
2744 cpu: None,
2745 memory: None,
2746 workload: None,
2747 pods: vec![],
2748 events: vec![],
2749 },
2750 )),
2751 "container",
2752 ))
2753 .unwrap();
2754
2755 let parsed: ResourceHeartbeat = serde_json::from_value(heartbeat_json).unwrap();
2756 assert_eq!(parsed.resource_id, "api");
2757 assert!(matches!(
2758 parsed.data,
2759 ResourceHeartbeatData::Container(ContainerHeartbeatData::Kubernetes(_))
2760 ));
2761 }
2762
2763 #[test]
2764 fn local_daemon_heartbeat_defaults_missing_daemon_name() {
2765 let mut value =
2766 serde_json::to_value(DaemonHeartbeatData::Local(LocalDaemonHeartbeatData {
2767 status: workload_status(),
2768 daemon_name: "agent".to_string(),
2769 runtime_id: "local-agent".to_string(),
2770 pid: None,
2771 command_supported: false,
2772 image_path_present: true,
2773 restart_count: None,
2774 exit_reason: None,
2775 daemon_instance: None,
2776 events: vec![],
2777 }))
2778 .unwrap();
2779
2780 value.as_object_mut().unwrap().remove("daemonName");
2781
2782 let parsed: DaemonHeartbeatData = serde_json::from_value(value).unwrap();
2783 match parsed {
2784 DaemonHeartbeatData::Local(data) => assert_eq!(data.daemon_name, ""),
2785 other => panic!("expected local daemon heartbeat, got {other:?}"),
2786 }
2787 }
2788
2789 #[test]
2790 fn container_heartbeat_serializes_resource_first_data() {
2791 let heartbeat = heartbeat(
2792 ResourceHeartbeatData::Container(ContainerHeartbeatData::Kubernetes(
2793 KubernetesContainerHeartbeatData {
2794 status: workload_status(),
2795 namespace: "default".to_string(),
2796 name: "api".to_string(),
2797 workload_kind: KubernetesWorkloadKind::Deployment,
2798 replicas: workload_replicas(),
2799 restarts: Some(1),
2800 cpu: Some(MetricSample {
2801 value: 0.5,
2802 unit: MetricUnit::Cores,
2803 }),
2804 memory: None,
2805 workload: None,
2806 pods: vec![],
2807 events: vec![],
2808 },
2809 )),
2810 "container",
2811 );
2812
2813 let value = serde_json::to_value(&heartbeat).unwrap();
2814
2815 assert_eq!(value["resourceType"], "container");
2816 assert_eq!(value["data"]["resourceType"], "container");
2817 assert_eq!(value["data"]["data"]["backend"], "kubernetes");
2818 assert_eq!(value["raw"][0]["body"], r#"{"readyReplicas":1}"#);
2819 assert!(value.get("collection").is_none());
2820 assert!(value["data"]["data"].get("summary").is_none());
2821 assert!(value["data"]["data"].get("detail").is_none());
2822 }
2823
2824 #[test]
2825 fn representative_workload_data_has_stable_tags() {
2826 let daemon = serde_json::to_value(ResourceHeartbeatData::Daemon(
2827 DaemonHeartbeatData::Kubernetes(KubernetesDaemonHeartbeatData {
2828 status: workload_status(),
2829 namespace: "default".to_string(),
2830 name: "agent".to_string(),
2831 replicas: workload_replicas(),
2832 restarts: Some(0),
2833 command_supported: true,
2834 cpu: None,
2835 memory: None,
2836 workload: None,
2837 pods: vec![],
2838 events: vec![],
2839 }),
2840 ))
2841 .unwrap();
2842 let worker = serde_json::to_value(ResourceHeartbeatData::Worker(
2843 WorkerHeartbeatData::AwsLambda(AwsLambdaWorkerHeartbeatData {
2844 status: workload_status(),
2845 function_name: "handler".to_string(),
2846 runtime: Some("nodejs22.x".to_string()),
2847 package_type: None,
2848 memory_size_mb: None,
2849 timeout_seconds: None,
2850 version: None,
2851 revision_id: None,
2852 last_modified: None,
2853 state: None,
2854 state_reason: None,
2855 state_reason_code: None,
2856 last_update_status: None,
2857 last_update_status_reason: None,
2858 last_update_status_reason_code: None,
2859 code_sha256: None,
2860 layer_count: 0,
2861 function_url_auth_type: None,
2862 function_url_cors_present: false,
2863 trigger_count: 0,
2864 }),
2865 ))
2866 .unwrap();
2867
2868 assert_eq!(daemon["resourceType"], "daemon");
2869 assert_eq!(daemon["data"]["backend"], "kubernetes");
2870 assert_eq!(worker["resourceType"], "worker");
2871 assert_eq!(worker["data"]["backend"], "awsLambda");
2872 }
2873
2874 #[test]
2875 fn representative_cluster_and_data_variants_have_optional_counts() {
2876 let cluster = serde_json::to_value(ResourceHeartbeatData::KubernetesCluster(
2877 KubernetesClusterHeartbeatData {
2878 status: WorkloadHeartbeatStatus {
2879 health: ObservedHealth::Healthy,
2880 lifecycle: ProviderLifecycleState::Running,
2881 message: None,
2882 stale: false,
2883 partial: false,
2884 collection_issues: vec![],
2885 },
2886 node_counts: ObservedCounts {
2887 desired: Some(3),
2888 current: Some(3),
2889 ready: None,
2890 },
2891 pod_counts: ObservedCounts {
2892 desired: None,
2893 current: Some(12),
2894 ready: Some(11),
2895 },
2896 cpu: None,
2897 memory: None,
2898 name: "prod".to_string(),
2899 region: Some("us-east-1".to_string()),
2900 namespace: None,
2901 version: Some("1.33".to_string()),
2902 node_statuses: vec![],
2903 events: vec![],
2904 },
2905 ))
2906 .unwrap();
2907 let queue = serde_json::to_value(ResourceHeartbeatData::Queue(QueueHeartbeatData::AwsSqs(
2908 AwsSqsQueueHeartbeatData {
2909 status: QueueHeartbeatStatus {
2910 health: ObservedHealth::Healthy,
2911 lifecycle: ProviderLifecycleState::Running,
2912 message: None,
2913 stale: false,
2914 partial: false,
2915 collection_issues: vec![],
2916 },
2917 name: "jobs".to_string(),
2918 region: Some("us-east-1".to_string()),
2919 queue_url: Some("https://sqs.us-east-1.amazonaws.com/123/jobs".to_string()),
2920 queue_arn: Some("arn:aws:sqs:us-east-1:123:jobs".to_string()),
2921 visibility_timeout_seconds: Some(30),
2922 message_retention_period_seconds: Some(345600),
2923 delay_seconds: Some(0),
2924 receive_message_wait_time_seconds: Some(0),
2925 maximum_message_size: Some(262144),
2926 redrive_policy: None,
2927 redrive_allow_policy: None,
2928 fifo_queue: Some(false),
2929 content_based_deduplication: None,
2930 deduplication_scope: None,
2931 fifo_throughput_limit: None,
2932 sse_enabled: Some(false),
2933 kms_master_key_id: None,
2934 kms_data_key_reuse_period_seconds: None,
2935 sqs_managed_sse_enabled: Some(false),
2936 approximate_visible_messages: Some(42),
2937 approximate_in_flight_messages: Some(1),
2938 approximate_delayed_messages: Some(0),
2939 approximate_counts: true,
2940 },
2941 )))
2942 .unwrap();
2943 let storage = serde_json::to_value(ResourceHeartbeatData::Storage(
2944 StorageHeartbeatData::AwsS3(AwsS3StorageHeartbeatData {
2945 status: StorageHeartbeatStatus {
2946 health: ObservedHealth::Healthy,
2947 lifecycle: ProviderLifecycleState::Running,
2948 message: None,
2949 stale: false,
2950 partial: false,
2951 collection_issues: vec![],
2952 },
2953 name: "assets".to_string(),
2954 region: Some("us-east-1".to_string()),
2955 bucket_location: Some("us-east-1".to_string()),
2956 versioning_status: Some("Enabled".to_string()),
2957 versioning_enabled: Some(true),
2958 lifecycle_present: false,
2959 lifecycle_rule_count: Some(0),
2960 encryption_config_present: true,
2961 encryption_enabled: Some(true),
2962 public_access_block_present: true,
2963 block_public_acls: Some(true),
2964 ignore_public_acls: Some(true),
2965 block_public_policy: Some(true),
2966 restrict_public_buckets: Some(true),
2967 bucket_policy_present: Some(false),
2968 bucket_acl_present: Some(true),
2969 }),
2970 ))
2971 .unwrap();
2972 let gcp_storage = serde_json::to_value(ResourceHeartbeatData::Storage(
2973 StorageHeartbeatData::GcpCloudStorage(GcpCloudStorageHeartbeatData {
2974 status: StorageHeartbeatStatus {
2975 health: ObservedHealth::Healthy,
2976 lifecycle: ProviderLifecycleState::Running,
2977 message: None,
2978 stale: false,
2979 partial: false,
2980 collection_issues: vec![],
2981 },
2982 name: "assets".to_string(),
2983 bucket_id: Some("project/assets".to_string()),
2984 location: Some("US".to_string()),
2985 location_type: Some("multi-region".to_string()),
2986 storage_class: Some("STANDARD".to_string()),
2987 versioning_enabled: Some(true),
2988 lifecycle_present: false,
2989 lifecycle_rule_count: Some(0),
2990 retention_policy_effective_time: None,
2991 retention_policy_is_locked: None,
2992 retention_period: None,
2993 soft_delete_retention_duration_seconds: None,
2994 soft_delete_effective_time: None,
2995 uniform_bucket_level_access_enabled: Some(true),
2996 uniform_bucket_level_access_locked_time: None,
2997 public_access_prevention: Some("enforced".to_string()),
2998 encryption_config_present: true,
2999 default_kms_key_name: Some(
3000 "projects/p/locations/l/keyRings/r/cryptoKeys/k".to_string(),
3001 ),
3002 }),
3003 ))
3004 .unwrap();
3005 let kv = serde_json::to_value(ResourceHeartbeatData::Kv(KvHeartbeatData::AwsDynamoDb(
3006 AwsDynamoDbKvHeartbeatData {
3007 status: KvHeartbeatStatus {
3008 health: ObservedHealth::Healthy,
3009 lifecycle: ProviderLifecycleState::Running,
3010 message: None,
3011 stale: false,
3012 partial: false,
3013 collection_issues: vec![],
3014 },
3015 name: "state".to_string(),
3016 region: Some("us-east-1".to_string()),
3017 table_arn: None,
3018 table_status: Some("ACTIVE".to_string()),
3019 billing_mode: Some("PAY_PER_REQUEST".to_string()),
3020 key_schema: vec![AwsDynamoDbKeySchemaElement {
3021 attribute_name: "pk".to_string(),
3022 key_type: "HASH".to_string(),
3023 }],
3024 global_secondary_index_count: Some(0),
3025 local_secondary_index_count: Some(0),
3026 item_count: None,
3027 table_size_bytes: None,
3028 stream_enabled: Some(false),
3029 stream_view_type: None,
3030 ttl_status: Some("ENABLED".to_string()),
3031 ttl_attribute_name: Some("ttl".to_string()),
3032 deletion_protection_enabled: Some(false),
3033 sse_status: Some("ENABLED".to_string()),
3034 sse_type: Some("KMS".to_string()),
3035 table_class: None,
3036 replica_count: Some(0),
3037 restore_in_progress: None,
3038 },
3039 )))
3040 .unwrap();
3041
3042 assert_eq!(cluster["resourceType"], "kubernetes-cluster");
3043 assert!(cluster["data"].get("summary").is_none());
3044 assert!(cluster["data"].get("detail").is_none());
3045 assert_eq!(cluster["data"]["name"], "prod");
3046 assert_eq!(queue["data"]["backend"], "awsSqs");
3047 assert_eq!(queue["data"]["approximateVisibleMessages"], 42);
3048 assert!(queue["data"].get("summary").is_none());
3049 assert_eq!(storage["data"]["backend"], "awsS3");
3050 assert!(storage["data"].get("summary").is_none());
3051 assert_eq!(gcp_storage["data"]["backend"], "gcpCloudStorage");
3052 assert_eq!(gcp_storage["data"]["publicAccessPrevention"], "enforced");
3053 assert_eq!(kv["data"]["backend"], "awsDynamoDb");
3054 assert!(kv["data"].get("summary").is_none());
3055 assert_eq!(kv["data"]["itemCount"], json!(null));
3056 }
3057
3058 #[test]
3059 fn ai_heartbeat_serializes_stable_tags() {
3060 let aws = serde_json::to_value(ResourceHeartbeatData::Ai(AiHeartbeatData::AwsBedrock(
3061 AwsBedrockAiHeartbeatData {
3062 status: AiHeartbeatStatus::default(),
3063 region: "us-east-1".to_string(),
3064 availability: AiAvailabilityObservation::unobserved(
3065 AiAvailabilitySource::AwsBedrock,
3066 Platform::Aws,
3067 Some("us-east-1".to_string()),
3068 ),
3069 },
3070 )))
3071 .unwrap();
3072 let gcp = serde_json::to_value(ResourceHeartbeatData::Ai(AiHeartbeatData::GcpVertex(
3073 GcpVertexAiHeartbeatData {
3074 status: AiHeartbeatStatus::default(),
3075 project: "my-project".to_string(),
3076 location: "us-central1".to_string(),
3077 availability: AiAvailabilityObservation::unobserved(
3078 AiAvailabilitySource::GcpVertex,
3079 Platform::Gcp,
3080 Some("us-central1".to_string()),
3081 ),
3082 },
3083 )))
3084 .unwrap();
3085 let azure = serde_json::to_value(ResourceHeartbeatData::Ai(AiHeartbeatData::AzureFoundry(
3086 AzureFoundryAiHeartbeatData {
3087 status: AiHeartbeatStatus::default(),
3088 account_name: "my-ai-account".to_string(),
3089 endpoint: Some("https://my-ai-account.openai.azure.com/".to_string()),
3090 resource_group: Some("my-rg".to_string()),
3091 location: Some("eastus".to_string()),
3092 availability: AiAvailabilityObservation::unobserved(
3093 AiAvailabilitySource::AzureFoundry,
3094 Platform::Azure,
3095 Some("eastus".to_string()),
3096 ),
3097 },
3098 )))
3099 .unwrap();
3100
3101 assert_eq!(aws["resourceType"], "ai");
3102 assert_eq!(aws["data"]["backend"], "awsBedrock");
3103 assert_eq!(aws["data"]["region"], "us-east-1");
3104 assert!(aws["data"].get("summary").is_none());
3105
3106 assert_eq!(gcp["resourceType"], "ai");
3107 assert_eq!(gcp["data"]["backend"], "gcpVertex");
3108 assert_eq!(gcp["data"]["project"], "my-project");
3109 assert_eq!(gcp["data"]["location"], "us-central1");
3110
3111 assert_eq!(azure["resourceType"], "ai");
3112 assert_eq!(azure["data"]["backend"], "azureFoundry");
3113 assert_eq!(azure["data"]["accountName"], "my-ai-account");
3114 assert_eq!(
3115 azure["data"]["endpoint"],
3116 "https://my-ai-account.openai.azure.com/"
3117 );
3118 }
3119}