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