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 #[serde(default)]
889 pub image: Option<String>,
890}
891
892#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
893#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
894#[serde(rename_all = "camelCase")]
895pub struct KubernetesDaemonHeartbeatData {
896 pub status: WorkloadHeartbeatStatus,
897 pub namespace: String,
898 pub name: String,
899 pub replicas: WorkloadReplicaStatus,
900 pub restarts: Option<u32>,
901 pub command_supported: bool,
902 pub cpu: Option<MetricSample>,
903 pub memory: Option<MetricSample>,
904 pub workload: Option<KubernetesWorkloadStatus>,
905 pub pods: Vec<KubernetesPodRuntimeUnitStatus>,
906 pub events: Vec<KubernetesEventSnapshot>,
907}
908
909#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
910#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
911#[serde(rename_all = "camelCase")]
912pub struct LocalDaemonHeartbeatData {
913 pub status: WorkloadHeartbeatStatus,
914 #[serde(default)]
915 pub daemon_name: String,
916 pub runtime_id: String,
917 pub pid: Option<u32>,
918 pub command_supported: bool,
919 pub image_path_present: bool,
920 pub restart_count: Option<u32>,
921 pub exit_reason: Option<String>,
922 pub daemon_instance: Option<LocalRuntimeUnitStatus>,
923 pub events: Vec<LocalRuntimeEventSnapshot>,
924}
925
926#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
927#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
928#[serde(rename_all = "camelCase")]
929pub struct LocalRuntimeUnitStatus {
930 pub unit_id: String,
931 pub name: String,
932 pub kind: LocalRuntimeUnitKind,
933 pub ready: bool,
934 pub phase: Option<String>,
935 pub pid: Option<u32>,
936 pub restart_count: Option<u32>,
937 pub cpu: Option<MetricSample>,
938 pub memory: Option<MetricSample>,
939}
940
941#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
942#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
943#[serde(rename_all = "kebab-case")]
944pub enum LocalRuntimeUnitKind {
945 Container,
946 Process,
947 Daemon,
948}
949
950#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
951#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
952#[serde(rename_all = "camelCase")]
953pub enum KubernetesWorkloadKind {
954 Deployment,
955 StatefulSet,
956 DaemonSet,
957 ReplicaSet,
958 Pod,
959}
960
961#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
962#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
963#[serde(rename_all = "camelCase")]
964pub struct KubernetesWorkloadStatus {
965 pub desired_replicas: Option<u32>,
966 pub ready_replicas: Option<u32>,
967 pub available_replicas: Option<u32>,
968 pub updated_replicas: Option<u32>,
969 pub observed_generation: Option<i64>,
970 pub desired_generation: Option<i64>,
971 pub rollout_reason: Option<String>,
972 pub conditions: Vec<KubernetesWorkloadCondition>,
973}
974
975#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
976#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
977#[serde(rename_all = "camelCase")]
978pub struct KubernetesWorkloadCondition {
979 #[serde(rename = "type")]
980 pub condition_type: String,
981 pub status: String,
982 pub reason: Option<String>,
983 pub message: Option<String>,
984 pub last_transition_time: Option<DateTime<Utc>>,
985}
986
987#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
988#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
989#[serde(rename_all = "camelCase")]
990pub struct KubernetesPodRuntimeUnitStatus {
991 pub name: String,
992 pub uid: Option<String>,
993 pub phase: Option<String>,
994 pub ready: bool,
995 pub restart_count: u32,
996 pub waiting_reason: Option<String>,
997 pub terminated_reason: Option<String>,
998 pub node_name: Option<String>,
999 pub pod_ip: Option<String>,
1000 pub owner_references: Vec<KubernetesOwnerReference>,
1001 pub cpu: Option<MetricSample>,
1002 pub memory: Option<MetricSample>,
1003 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1004 pub containers: Vec<ContainerImageIdentity>,
1005}
1006
1007#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1008#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1009#[serde(rename_all = "camelCase")]
1010pub struct KubernetesOwnerReference {
1011 pub kind: String,
1012 pub name: String,
1013 pub uid: String,
1014 pub controller: bool,
1015}
1016
1017#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1018#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1019#[serde(tag = "backend", rename_all = "camelCase")]
1020pub enum ComputeClusterHeartbeatData {
1021 Aws(AwsComputeClusterHeartbeatData),
1022 Gcp(GcpComputeClusterHeartbeatData),
1023 Azure(AzureComputeClusterHeartbeatData),
1024 Machines(MachinesComputeClusterHeartbeatData),
1025 Local(LocalComputeClusterHeartbeatData),
1026}
1027
1028#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1029#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1030#[serde(rename_all = "camelCase")]
1031pub struct ComputeClusterHeartbeatStatus {
1032 pub health: ObservedHealth,
1033 pub lifecycle: ProviderLifecycleState,
1034 pub message: Option<String>,
1035 pub stale: bool,
1036 pub partial: bool,
1037 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1038}
1039
1040#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1041#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1042#[serde(rename_all = "camelCase")]
1043pub struct LocalComputeClusterHeartbeatData {
1044 pub status: ComputeClusterHeartbeatStatus,
1045 pub nodes: ObservedCounts,
1046 pub name: String,
1047 pub host_identifier: Option<String>,
1048 pub docker_available: bool,
1049 pub docker_version: Option<String>,
1050 pub docker_api_version: Option<String>,
1051 pub docker_os: Option<String>,
1052 pub docker_arch: Option<String>,
1053 pub network_name: Option<String>,
1054 pub network_available: bool,
1055 pub tracked_containers: Option<u32>,
1056 pub running_containers: Option<u32>,
1057}
1058
1059#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1060#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1061#[serde(rename_all = "camelCase")]
1062pub struct AwsComputeClusterHeartbeatData {
1063 pub status: ComputeClusterHeartbeatStatus,
1064 pub nodes: ObservedCounts,
1065 pub cpu: Option<MetricSample>,
1066 pub memory: Option<MetricSample>,
1067 pub name: String,
1068 pub region: Option<String>,
1069 pub backend_cluster_id: Option<String>,
1070 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1071 pub provider_fleets: Vec<ProviderFleetStatus>,
1072}
1073
1074#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1075#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1076#[serde(rename_all = "camelCase")]
1077pub struct GcpComputeClusterHeartbeatData {
1078 pub status: ComputeClusterHeartbeatStatus,
1079 pub nodes: ObservedCounts,
1080 pub cpu: Option<MetricSample>,
1081 pub memory: Option<MetricSample>,
1082 pub name: String,
1083 pub region: Option<String>,
1084 pub backend_cluster_id: Option<String>,
1085 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1086 pub provider_fleets: Vec<ProviderFleetStatus>,
1087}
1088
1089#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1090#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1091#[serde(rename_all = "camelCase")]
1092pub struct AzureComputeClusterHeartbeatData {
1093 pub status: ComputeClusterHeartbeatStatus,
1094 pub nodes: ObservedCounts,
1095 pub cpu: Option<MetricSample>,
1096 pub memory: Option<MetricSample>,
1097 pub name: String,
1098 pub region: Option<String>,
1099 pub backend_cluster_id: Option<String>,
1100 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1101 pub provider_fleets: Vec<ProviderFleetStatus>,
1102}
1103
1104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1105#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1106#[serde(rename_all = "camelCase")]
1107pub struct MachinesComputeClusterHeartbeatData {
1108 pub status: ComputeClusterHeartbeatStatus,
1109 pub nodes: ObservedCounts,
1110 pub cpu: Option<MetricSample>,
1111 pub memory: Option<MetricSample>,
1112 pub name: String,
1113 pub backend_cluster_id: Option<String>,
1114 pub capacity_groups: Vec<ComputeCapacityGroupStatus>,
1115 pub machines: Vec<MachinesComputeMachineStatus>,
1116}
1117
1118#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1119#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1120#[serde(rename_all = "camelCase")]
1121pub struct MachinesComputeMachineStatus {
1122 pub machine_id: String,
1123 pub status: String,
1124 pub capacity_group: String,
1125 pub zone: String,
1126 pub public_ip: Option<String>,
1127 pub overlay_ip: Option<String>,
1128 pub last_heartbeat: String,
1129 pub horizond_version: Option<String>,
1130 pub replica_count: i64,
1131 pub cpu_cores: Option<f64>,
1132 pub memory_bytes: Option<i64>,
1133 pub drain_force: bool,
1134 pub drain_requested_at: Option<String>,
1135 pub drain_deadline_at: Option<String>,
1136 pub drained_at: Option<String>,
1137 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1138 pub drain_blockers: Vec<ComputeDrainBlocker>,
1139}
1140
1141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1142#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1143#[serde(rename_all = "camelCase")]
1144pub struct ComputeCapacityGroupStatus {
1145 pub group_id: String,
1146 pub current_machines: u32,
1147 pub desired_machines: u32,
1148 pub min_machines: Option<u32>,
1149 pub max_machines: Option<u32>,
1150 pub instance_type: Option<String>,
1151 pub recommendation: Option<ComputeCapacityRecommendation>,
1152 pub capacity_blocker: Option<ComputeCapacityBlocker>,
1153 #[serde(default, skip_serializing_if = "Option::is_none")]
1154 pub drain_progress: Option<ComputeDrainProgress>,
1155}
1156
1157#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1158#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1159#[serde(rename_all = "camelCase")]
1160pub enum ComputeCapacityBlockerCategory {
1161 Quota,
1162 Capacity,
1163 Allocation,
1164 Other,
1165}
1166
1167#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1168#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1169#[serde(rename_all = "camelCase")]
1170pub struct ComputeCapacityBlocker {
1171 pub category: ComputeCapacityBlockerCategory,
1172 pub provider_code: Option<String>,
1173 pub message: String,
1174 pub provider_reference: Option<String>,
1175 pub observed_at: DateTime<Utc>,
1176}
1177
1178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1179#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1180#[serde(rename_all = "camelCase")]
1181pub struct ComputeCapacityRecommendation {
1182 pub desired_machines: u32,
1183 pub reason: Option<String>,
1184 pub utilization: Option<MetricSample>,
1185 pub unschedulable_replicas: Option<u32>,
1186}
1187
1188#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1189#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1190#[serde(rename_all = "camelCase")]
1191pub enum ComputeDrainProgressStatus {
1192 Draining,
1193 Drained,
1194 Terminating,
1195}
1196
1197#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1198#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1199#[serde(rename_all = "camelCase")]
1200pub struct ComputeDrainBlocker {
1201 pub workload_name: String,
1202 pub replica_id: String,
1203 pub scheduling_mode: String,
1204 pub state: String,
1205 pub reason: String,
1206}
1207
1208#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1209#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1210#[serde(rename_all = "camelCase")]
1211pub struct ComputeDrainProgress {
1212 pub machine_id: String,
1213 pub status: ComputeDrainProgressStatus,
1214 pub replica_count: i64,
1215 pub force: bool,
1216 pub stalled: bool,
1217 pub drain_requested_at: Option<String>,
1218 pub drain_deadline_at: Option<String>,
1219 pub drained_at: Option<String>,
1220 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1221 pub blockers: Vec<ComputeDrainBlocker>,
1222}
1223
1224#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1225#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1226#[serde(rename_all = "camelCase")]
1227pub struct ProviderFleetStatus {
1228 pub group_id: String,
1229 pub provider_id: String,
1230 pub location: Option<String>,
1231 pub current_machines: u32,
1232 pub desired_machines: u32,
1233}
1234
1235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1236#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1237#[serde(rename_all = "camelCase")]
1238pub struct KubernetesClusterHeartbeatData {
1239 pub status: WorkloadHeartbeatStatus,
1240 pub node_counts: ObservedCounts,
1241 pub pod_counts: ObservedCounts,
1242 pub cpu: Option<MetricSample>,
1243 pub memory: Option<MetricSample>,
1244 pub name: String,
1245 pub region: Option<String>,
1246 pub namespace: Option<String>,
1247 pub version: Option<String>,
1248 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1249 pub node_statuses: Vec<KubernetesClusterNodeStatus>,
1250 pub events: Vec<KubernetesEventSnapshot>,
1251}
1252
1253#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1254#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1255#[serde(rename_all = "camelCase")]
1256pub struct KubernetesClusterNodeStatus {
1257 pub name: String,
1258 pub uid: Option<String>,
1259 pub ready: bool,
1260 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1261 pub conditions: Vec<KubernetesNodeConditionStatus>,
1262 pub roles: Vec<String>,
1263 pub labels: BTreeMap<String, String>,
1264 pub allocatable: KubernetesNodeResources,
1265 pub capacity: KubernetesNodeResources,
1266 pub usage: Option<KubernetesNodeUsage>,
1267 pub kubelet_version: Option<String>,
1268 pub container_runtime_version: Option<String>,
1269}
1270
1271#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1272#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1273#[serde(rename_all = "camelCase")]
1274pub struct KubernetesNodeConditionStatus {
1275 pub type_: String,
1276 pub status: String,
1277 pub reason: Option<String>,
1278 pub message: Option<String>,
1279}
1280
1281#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1282#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1283#[serde(rename_all = "camelCase")]
1284pub struct KubernetesNodeResources {
1285 pub cpu: Option<MetricSample>,
1286 pub memory: Option<MetricSample>,
1287 pub pods: Option<u64>,
1288}
1289
1290#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1291#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1292#[serde(rename_all = "camelCase")]
1293pub struct KubernetesNodeUsage {
1294 pub cpu: Option<MetricSample>,
1295 pub memory: Option<MetricSample>,
1296}
1297
1298#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1299#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1300#[serde(tag = "backend", rename_all = "camelCase")]
1301pub enum QueueHeartbeatData {
1302 AwsSqs(AwsSqsQueueHeartbeatData),
1303 GcpPubSub(GcpPubSubQueueHeartbeatData),
1304 AzureServiceBus(AzureServiceBusQueueHeartbeatData),
1305 Local(LocalQueueHeartbeatData),
1306}
1307
1308#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1309#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1310#[serde(rename_all = "camelCase")]
1311pub struct QueueHeartbeatStatus {
1312 pub health: ObservedHealth,
1313 pub lifecycle: ProviderLifecycleState,
1314 pub message: Option<String>,
1315 pub stale: bool,
1316 pub partial: bool,
1317 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1318}
1319
1320impl Default for QueueHeartbeatStatus {
1321 fn default() -> Self {
1322 Self {
1323 health: ObservedHealth::Unknown,
1324 lifecycle: ProviderLifecycleState::Unknown,
1325 message: None,
1326 stale: false,
1327 partial: false,
1328 collection_issues: vec![],
1329 }
1330 }
1331}
1332
1333#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1334#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1335#[serde(rename_all = "camelCase")]
1336pub struct LocalQueueHeartbeatData {
1337 pub status: QueueHeartbeatStatus,
1338 pub name: String,
1339 pub path: Option<String>,
1340 pub service_status: Option<String>,
1341}
1342
1343#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1344#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1345#[serde(rename_all = "camelCase")]
1346pub struct GcpPubSubQueueHeartbeatData {
1347 pub status: QueueHeartbeatStatus,
1348 pub topic_name: String,
1349 pub subscription_name: Option<String>,
1350 pub project_id: Option<String>,
1351 pub topic_full_name: Option<String>,
1352 pub subscription_full_name: Option<String>,
1353 pub endpoint: Option<String>,
1354 pub topic_labels: BTreeMap<String, String>,
1355 pub subscription_labels: BTreeMap<String, String>,
1356 pub message_storage_allowed_persistence_regions: Vec<String>,
1357 pub message_storage_enforce_in_transit: Option<bool>,
1358 pub kms_key_name: Option<String>,
1359 pub schema_name: Option<String>,
1360 pub schema_encoding: Option<String>,
1361 pub schema_first_revision_id: Option<String>,
1362 pub schema_last_revision_id: Option<String>,
1363 pub topic_message_retention_duration: Option<String>,
1364 pub topic_state: Option<String>,
1365 pub subscription_ack_deadline_seconds: Option<u32>,
1366 pub subscription_message_retention_duration: Option<String>,
1367 pub subscription_retain_acked_messages: Option<bool>,
1368 pub subscription_enable_message_ordering: Option<bool>,
1369 pub subscription_filter: Option<String>,
1370 pub subscription_detached: Option<bool>,
1371 pub subscription_state: Option<String>,
1372 pub subscription_push_config_present: Option<bool>,
1373 pub subscription_push_endpoint: Option<String>,
1374 pub subscription_push_attributes: BTreeMap<String, String>,
1375 pub subscription_push_oidc_service_account_email: Option<String>,
1376 pub subscription_push_oidc_audience: Option<String>,
1377 pub subscription_push_pubsub_wrapper_write_metadata: Option<bool>,
1378 pub subscription_push_no_wrapper_write_metadata: Option<bool>,
1379 pub subscription_dead_letter_topic: Option<String>,
1380 pub subscription_dead_letter_max_delivery_attempts: Option<u32>,
1381}
1382
1383#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1384#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1385#[serde(rename_all = "camelCase")]
1386pub struct AzureServiceBusQueueHeartbeatData {
1387 pub status: QueueHeartbeatStatus,
1388 pub name: String,
1389 pub namespace_name: String,
1390 pub resource_group: Option<String>,
1391 pub resource_id: Option<String>,
1392 pub endpoint: Option<String>,
1393 pub queue_status: Option<String>,
1394 pub lock_duration: Option<String>,
1395 pub max_delivery_count: Option<u32>,
1396 pub requires_duplicate_detection: Option<bool>,
1397 pub duplicate_detection_history_time_window: Option<String>,
1398 pub requires_session: Option<bool>,
1399 pub dead_lettering_on_message_expiration: Option<bool>,
1400 pub forward_dead_lettered_messages_to: Option<String>,
1401 pub forward_to: Option<String>,
1402 pub default_message_time_to_live: Option<String>,
1403 pub auto_delete_on_idle: Option<String>,
1404 pub enable_batched_operations: Option<bool>,
1405 pub enable_express: Option<bool>,
1406 pub enable_partitioning: Option<bool>,
1407 pub max_message_size_in_kilobytes: Option<u64>,
1408 pub max_size_in_megabytes: Option<u32>,
1409 pub message_count: Option<u64>,
1410 pub active_message_count: Option<u64>,
1411 pub dead_letter_message_count: Option<u64>,
1412 pub scheduled_message_count: Option<u64>,
1413 pub transfer_message_count: Option<u64>,
1414 pub transfer_dead_letter_message_count: Option<u64>,
1415 pub size_in_bytes: Option<u64>,
1416 pub accessed_at: Option<String>,
1417 pub created_at: Option<String>,
1418 pub updated_at: Option<String>,
1419}
1420
1421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1422#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1423#[serde(rename_all = "camelCase")]
1424pub struct AwsSqsQueueHeartbeatData {
1425 pub status: QueueHeartbeatStatus,
1426 pub name: String,
1427 pub region: Option<String>,
1428 pub queue_url: Option<String>,
1429 pub queue_arn: Option<String>,
1430 pub visibility_timeout_seconds: Option<u32>,
1431 pub message_retention_period_seconds: Option<u32>,
1432 pub delay_seconds: Option<u32>,
1433 pub receive_message_wait_time_seconds: Option<u32>,
1434 pub maximum_message_size: Option<u32>,
1435 pub redrive_policy: Option<String>,
1436 pub redrive_allow_policy: Option<String>,
1437 pub fifo_queue: Option<bool>,
1438 pub content_based_deduplication: Option<bool>,
1439 pub deduplication_scope: Option<String>,
1440 pub fifo_throughput_limit: Option<String>,
1441 pub sse_enabled: Option<bool>,
1442 pub kms_master_key_id: Option<String>,
1443 pub kms_data_key_reuse_period_seconds: Option<u32>,
1444 pub sqs_managed_sse_enabled: Option<bool>,
1445 pub approximate_visible_messages: Option<u64>,
1446 pub approximate_in_flight_messages: Option<u64>,
1447 pub approximate_delayed_messages: Option<u64>,
1448 pub approximate_counts: bool,
1449}
1450
1451#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1452#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1453#[serde(tag = "backend", rename_all = "camelCase")]
1454pub enum KvHeartbeatData {
1455 AwsDynamoDb(AwsDynamoDbKvHeartbeatData),
1456 GcpFirestore(GcpFirestoreKvHeartbeatData),
1457 AzureTable(AzureTableKvHeartbeatData),
1458 Local(LocalKvHeartbeatData),
1459}
1460
1461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1462#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1463#[serde(rename_all = "camelCase")]
1464pub struct KvHeartbeatStatus {
1465 pub health: ObservedHealth,
1466 pub lifecycle: ProviderLifecycleState,
1467 pub message: Option<String>,
1468 pub stale: bool,
1469 pub partial: bool,
1470 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1471}
1472
1473impl Default for KvHeartbeatStatus {
1474 fn default() -> Self {
1475 Self {
1476 health: ObservedHealth::Unknown,
1477 lifecycle: ProviderLifecycleState::Unknown,
1478 message: None,
1479 stale: false,
1480 partial: false,
1481 collection_issues: vec![],
1482 }
1483 }
1484}
1485
1486#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1487#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1488#[serde(rename_all = "camelCase")]
1489pub struct AwsDynamoDbKvHeartbeatData {
1490 pub status: KvHeartbeatStatus,
1491 pub name: String,
1492 pub region: Option<String>,
1493 pub table_arn: Option<String>,
1494 pub table_status: Option<String>,
1495 pub billing_mode: Option<String>,
1496 pub key_schema: Vec<AwsDynamoDbKeySchemaElement>,
1497 pub global_secondary_index_count: Option<u32>,
1498 pub local_secondary_index_count: Option<u32>,
1499 pub item_count: Option<u64>,
1500 pub table_size_bytes: Option<u64>,
1501 pub stream_enabled: Option<bool>,
1502 pub stream_view_type: Option<String>,
1503 pub ttl_status: Option<String>,
1504 pub ttl_attribute_name: Option<String>,
1505 pub deletion_protection_enabled: Option<bool>,
1506 pub sse_status: Option<String>,
1507 pub sse_type: Option<String>,
1508 pub table_class: Option<String>,
1509 pub replica_count: Option<u32>,
1510 pub restore_in_progress: Option<bool>,
1511}
1512
1513#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1514#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1515#[serde(rename_all = "camelCase")]
1516pub struct AwsDynamoDbKeySchemaElement {
1517 pub attribute_name: String,
1518 pub key_type: String,
1519}
1520
1521#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1522#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1523#[serde(rename_all = "camelCase")]
1524pub struct GcpFirestoreKvHeartbeatData {
1525 pub status: KvHeartbeatStatus,
1526 pub database_name: String,
1527 pub project_id: Option<String>,
1528 pub endpoint: Option<String>,
1529 pub location_id: Option<String>,
1530 pub database_type: Option<String>,
1531 pub concurrency_mode: Option<String>,
1532 pub app_engine_integration_mode: Option<String>,
1533 pub delete_protection_state: Option<String>,
1534 pub point_in_time_recovery_enablement: Option<String>,
1535 pub version_retention_period: Option<String>,
1536 pub earliest_version_time: Option<String>,
1537 pub create_time: Option<String>,
1538 pub update_time: Option<String>,
1539 pub delete_time: Option<String>,
1540 pub database_edition: Option<String>,
1541 pub cmek_enabled: bool,
1542 pub source_info_present: bool,
1543}
1544
1545#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1546#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1547#[serde(rename_all = "camelCase")]
1548pub struct AzureTableKvHeartbeatData {
1549 pub status: KvHeartbeatStatus,
1550 pub table_name: String,
1551 pub storage_account_name: String,
1552 pub resource_group: Option<String>,
1553 pub endpoint: Option<String>,
1554 pub storage_account_resource_id: Option<String>,
1555 pub storage_account_location: Option<String>,
1556 pub storage_account_kind: Option<String>,
1557 pub storage_account_provisioning_state: Option<String>,
1558 pub storage_account_primary_status: Option<String>,
1559 pub table_exists: bool,
1560 pub signed_identifier_count: Option<u32>,
1561}
1562
1563#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1564#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1565#[serde(rename_all = "camelCase")]
1566pub struct LocalKvHeartbeatData {
1567 pub status: KvHeartbeatStatus,
1568 pub name: String,
1569 pub path: String,
1570 pub path_exists: bool,
1571 pub is_directory: Option<bool>,
1572 pub cloud_metadata_supported: bool,
1573}
1574
1575#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1576#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1577#[serde(tag = "backend", rename_all = "camelCase")]
1578pub enum PostgresHeartbeatData {
1579 Aurora(AuroraPostgresHeartbeatData),
1581 CloudSql(GcpCloudSqlPostgresHeartbeatData),
1583 FlexibleServer(AzureFlexibleServerPostgresHeartbeatData),
1585 Local(LocalPostgresHeartbeatData),
1587}
1588
1589#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1590#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1591#[serde(rename_all = "camelCase")]
1592pub struct PostgresHeartbeatStatus {
1593 pub health: ObservedHealth,
1594 pub lifecycle: ProviderLifecycleState,
1595 pub message: Option<String>,
1596 pub stale: bool,
1597 pub partial: bool,
1598 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1599}
1600
1601impl Default for PostgresHeartbeatStatus {
1602 fn default() -> Self {
1603 Self {
1604 health: ObservedHealth::Unknown,
1605 lifecycle: ProviderLifecycleState::Unknown,
1606 message: None,
1607 stale: false,
1608 partial: false,
1609 collection_issues: vec![],
1610 }
1611 }
1612}
1613
1614#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1619#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1620#[serde(tag = "backend", rename_all = "camelCase")]
1621pub enum SandboxHeartbeatData {
1622 AwsMicrovm(AwsMicrovmSandboxHeartbeatData),
1623 AzureSandboxGroup(AzureSandboxGroupHeartbeatData),
1624 GcpAgentPlatform(GcpAgentPlatformSandboxHeartbeatData),
1625 KubernetesPods(KubernetesSandboxHeartbeatData),
1626 Local(LocalSandboxHeartbeatData),
1627}
1628
1629#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1630#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1631#[serde(rename_all = "camelCase")]
1632pub struct SandboxHeartbeatStatus {
1633 pub health: ObservedHealth,
1634 pub lifecycle: ProviderLifecycleState,
1635 pub message: Option<String>,
1636 pub stale: bool,
1637 pub partial: bool,
1638 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1639}
1640
1641impl Default for SandboxHeartbeatStatus {
1642 fn default() -> Self {
1643 Self {
1644 health: ObservedHealth::Healthy,
1645 lifecycle: ProviderLifecycleState::Running,
1646 message: None,
1647 stale: false,
1648 partial: false,
1649 collection_issues: Vec::new(),
1650 }
1651 }
1652}
1653
1654#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1656#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1657#[serde(rename_all = "camelCase")]
1658pub struct AwsMicrovmSandboxHeartbeatData {
1659 pub status: SandboxHeartbeatStatus,
1660 pub image_identifier: String,
1662 pub image_state: Option<String>,
1669}
1670
1671#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1674#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1675#[serde(rename_all = "camelCase")]
1676pub struct AzureSandboxGroupHeartbeatData {
1677 pub status: SandboxHeartbeatStatus,
1678 pub sandbox_group: String,
1679 pub provisioning_state: Option<String>,
1680}
1681
1682#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1688#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1689#[serde(rename_all = "camelCase")]
1690pub struct GcpAgentPlatformSandboxHeartbeatData {
1691 pub status: SandboxHeartbeatStatus,
1692 pub engine: String,
1694 pub template_id: String,
1696}
1697
1698#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1700#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1701#[serde(rename_all = "camelCase")]
1702pub struct KubernetesSandboxHeartbeatData {
1703 pub status: SandboxHeartbeatStatus,
1704 pub namespace: String,
1705 pub active_sessions: u32,
1706 pub idle_pods: u32,
1708}
1709
1710#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1712#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1713#[serde(rename_all = "camelCase")]
1714pub struct LocalSandboxHeartbeatData {
1715 pub status: SandboxHeartbeatStatus,
1716 pub active_sessions: u32,
1717 pub route_serving: bool,
1720}
1721
1722#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1723#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1724#[serde(tag = "backend", rename_all = "camelCase")]
1725pub enum AiHeartbeatData {
1726 AwsBedrock(AwsBedrockAiHeartbeatData),
1727 GcpVertex(GcpVertexAiHeartbeatData),
1728 AzureFoundry(AzureFoundryAiHeartbeatData),
1729 External(ExternalAiHeartbeatData),
1730}
1731
1732#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1733#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1734#[serde(rename_all = "camelCase")]
1735pub struct AiHeartbeatStatus {
1736 pub health: ObservedHealth,
1737 pub lifecycle: ProviderLifecycleState,
1738 pub message: Option<String>,
1739 pub stale: bool,
1740 pub partial: bool,
1741 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1742}
1743
1744impl Default for AiHeartbeatStatus {
1745 fn default() -> Self {
1746 Self {
1748 health: ObservedHealth::Unknown,
1749 lifecycle: ProviderLifecycleState::Unknown,
1750 message: None,
1751 stale: false,
1752 partial: false,
1753 collection_issues: vec![],
1754 }
1755 }
1756}
1757
1758#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1761#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1762#[serde(rename_all = "kebab-case")]
1763pub enum AiAvailabilitySource {
1764 AwsBedrock,
1765 GcpVertex,
1766 AzureFoundry,
1767 Anthropic,
1768}
1769
1770#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1771#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1772#[serde(rename_all = "kebab-case")]
1773pub enum AiModelAvailability {
1774 Available,
1775 Blocked,
1776 Unknown,
1777}
1778
1779#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1780#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1781#[serde(rename_all = "kebab-case")]
1782pub enum AiAvailabilityBlocker {
1783 AgreementRequired,
1784 EntitlementRequired,
1785 ModelActivationRequired,
1786 DeploymentRequired,
1787 QuotaConfigurationRequired,
1788 RegionUnavailable,
1789 AccessDenied,
1790 ObservationFailed,
1791}
1792
1793#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1794#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1795#[serde(rename_all = "kebab-case")]
1796pub enum AiAccessTest {
1797 Verified,
1798 Failed,
1799 NotChecked,
1800}
1801
1802#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1803#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1804#[serde(rename_all = "camelCase")]
1805pub struct AiModelAvailabilityObservation {
1806 pub public_model_id: String,
1807 pub client_apis: Vec<ClientApi>,
1808 pub availability: AiModelAvailability,
1809 pub blockers: Vec<AiAvailabilityBlocker>,
1810 pub access_test: AiAccessTest,
1811 #[serde(skip_serializing_if = "Option::is_none")]
1812 pub tested_at: Option<DateTime<Utc>>,
1813 #[serde(skip_serializing_if = "Option::is_none")]
1814 pub error_code: Option<String>,
1815}
1816
1817#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1818#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1819#[serde(rename_all = "camelCase")]
1820pub struct AiAvailabilityObservation {
1821 pub source: AiAvailabilitySource,
1822 pub catalog_revision: String,
1823 #[serde(skip_serializing_if = "Option::is_none")]
1824 pub location: Option<String>,
1825 pub models: Vec<AiModelAvailabilityObservation>,
1826}
1827
1828impl AiAvailabilityObservation {
1829 pub fn unobserved(
1832 source: AiAvailabilitySource,
1833 platform: Platform,
1834 location: Option<String>,
1835 ) -> Self {
1836 Self {
1837 source,
1838 catalog_revision: crate::ai_catalog::AI_CATALOG_REVISION.to_string(),
1839 location,
1840 models: crate::ai_catalog::models_for(platform)
1841 .into_iter()
1842 .map(|model| AiModelAvailabilityObservation {
1843 public_model_id: model.public_id.to_string(),
1844 client_apis: ClientApi::ALL.to_vec(),
1845 availability: AiModelAvailability::Unknown,
1846 blockers: vec![AiAvailabilityBlocker::ObservationFailed],
1847 access_test: AiAccessTest::NotChecked,
1848 tested_at: None,
1849 error_code: None,
1850 })
1851 .collect(),
1852 }
1853 }
1854}
1855
1856#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1857#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1858#[serde(rename_all = "camelCase")]
1859pub struct LocalPostgresHeartbeatData {
1860 pub status: PostgresHeartbeatStatus,
1861 pub name: String,
1862 pub port: Option<u16>,
1863 pub version: String,
1864 pub process_running: bool,
1865}
1866
1867#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1868#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1869#[serde(rename_all = "camelCase")]
1870pub struct AuroraPostgresHeartbeatData {
1871 pub status: PostgresHeartbeatStatus,
1872 pub cluster_identifier: String,
1873 #[serde(skip_serializing_if = "Option::is_none")]
1874 pub engine_version: Option<String>,
1875 #[serde(skip_serializing_if = "Option::is_none")]
1876 pub endpoint: Option<String>,
1877 #[serde(skip_serializing_if = "Option::is_none")]
1879 pub serverless_capacity: Option<f64>,
1880 pub never_pauses: bool,
1883}
1884
1885#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1886#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1887#[serde(rename_all = "camelCase")]
1888pub struct GcpCloudSqlPostgresHeartbeatData {
1889 pub status: PostgresHeartbeatStatus,
1890 pub instance_name: String,
1891 #[serde(skip_serializing_if = "Option::is_none")]
1892 pub state: Option<String>,
1893 #[serde(skip_serializing_if = "Option::is_none")]
1894 pub database_version: Option<String>,
1895}
1896
1897#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1898#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1899#[serde(rename_all = "camelCase")]
1900pub struct AzureFlexibleServerPostgresHeartbeatData {
1901 pub status: PostgresHeartbeatStatus,
1902 pub server_name: String,
1903 #[serde(skip_serializing_if = "Option::is_none")]
1904 pub state: Option<String>,
1905 #[serde(skip_serializing_if = "Option::is_none")]
1906 pub version: Option<String>,
1907}
1908
1909#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1910#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1911#[serde(rename_all = "camelCase")]
1912pub struct AwsBedrockAiHeartbeatData {
1913 pub status: AiHeartbeatStatus,
1914 pub region: String,
1915 pub availability: AiAvailabilityObservation,
1916}
1917
1918#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1919#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1920#[serde(rename_all = "camelCase")]
1921pub struct GcpVertexAiHeartbeatData {
1922 pub status: AiHeartbeatStatus,
1923 pub project: String,
1924 pub location: String,
1925 pub availability: AiAvailabilityObservation,
1926}
1927
1928#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1929#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1930#[serde(rename_all = "camelCase")]
1931pub struct AzureFoundryAiHeartbeatData {
1932 pub status: AiHeartbeatStatus,
1933 pub account_name: String,
1934 pub endpoint: Option<String>,
1935 pub resource_group: Option<String>,
1936 pub location: Option<String>,
1937 pub availability: AiAvailabilityObservation,
1938}
1939
1940#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1941#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1942#[serde(rename_all = "camelCase")]
1943pub struct ExternalAiHeartbeatData {
1944 pub status: AiHeartbeatStatus,
1945 pub provider: String,
1948 #[serde(skip_serializing_if = "Option::is_none")]
1949 pub availability: Option<AiAvailabilityObservation>,
1950}
1951
1952#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1953#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1954#[serde(tag = "backend", rename_all = "camelCase")]
1955pub enum VaultHeartbeatData {
1956 AwsParameterStore(AwsParameterStoreVaultHeartbeatData),
1957 GcpSecretManager(GcpSecretManagerVaultHeartbeatData),
1958 AzureKeyVault(AzureKeyVaultHeartbeatData),
1959 KubernetesSecret(KubernetesSecretVaultHeartbeatData),
1960 Local(LocalVaultHeartbeatData),
1961}
1962
1963#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1964#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1965#[serde(rename_all = "camelCase")]
1966pub struct VaultHeartbeatStatus {
1967 pub health: ObservedHealth,
1968 pub lifecycle: ProviderLifecycleState,
1969 pub message: Option<String>,
1970 pub stale: bool,
1971 pub partial: bool,
1972 pub collection_issues: Vec<HeartbeatCollectionIssue>,
1973}
1974
1975impl Default for VaultHeartbeatStatus {
1976 fn default() -> Self {
1977 Self {
1978 health: ObservedHealth::Healthy,
1979 lifecycle: ProviderLifecycleState::Running,
1980 message: None,
1981 stale: false,
1982 partial: false,
1983 collection_issues: vec![],
1984 }
1985 }
1986}
1987
1988#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1989#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
1990#[serde(rename_all = "camelCase")]
1991pub struct AwsParameterStoreVaultHeartbeatData {
1992 pub status: VaultHeartbeatStatus,
1993 pub account_id: String,
1994 pub region: String,
1995 pub prefix: String,
1996 pub parameter_metadata_sampled: bool,
1997 pub sampled_parameter_count: Option<u32>,
1998 pub sampled_secure_string_count: Option<u32>,
1999 pub sampled_string_count: Option<u32>,
2000 pub sampled_string_list_count: Option<u32>,
2001 pub sampled_advanced_tier_count: Option<u32>,
2002 pub sampled_kms_key_metadata_present_count: Option<u32>,
2003 pub latest_modified_at: Option<DateTime<Utc>>,
2004 pub has_more_parameters: Option<bool>,
2005}
2006
2007#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2008#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2009#[serde(rename_all = "camelCase")]
2010pub struct GcpSecretManagerVaultHeartbeatData {
2011 pub status: VaultHeartbeatStatus,
2012 pub project_id: String,
2013 pub location: String,
2014 pub prefix: String,
2015 pub secret_metadata_listed: bool,
2016}
2017
2018#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2019#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2020#[serde(rename_all = "camelCase")]
2021pub struct AzureKeyVaultHeartbeatData {
2022 pub status: VaultHeartbeatStatus,
2023 pub name: String,
2024 pub resource_group: Option<String>,
2025 pub resource_id: Option<String>,
2026 pub location: Option<String>,
2027 pub vault_uri: Option<String>,
2028 pub provisioning_state: Option<String>,
2029 pub sku_family: Option<String>,
2030 pub sku_name: Option<String>,
2031 pub soft_delete_enabled: bool,
2032 pub soft_delete_retention_days: i32,
2033 pub purge_protection_enabled: Option<bool>,
2034 pub rbac_authorization_enabled: bool,
2035 pub public_network_access: String,
2036 pub access_policy_count: u32,
2037 pub private_endpoint_connection_count: u32,
2038 pub secret_metadata_listed: bool,
2039}
2040
2041#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2042#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2043#[serde(rename_all = "camelCase")]
2044pub struct KubernetesSecretVaultHeartbeatData {
2045 pub status: VaultHeartbeatStatus,
2046 pub namespace: String,
2047 pub prefix: String,
2048 pub secret_metadata_listed: bool,
2049}
2050
2051#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2052#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2053#[serde(rename_all = "camelCase")]
2054pub struct LocalVaultHeartbeatData {
2055 pub status: VaultHeartbeatStatus,
2056 pub path: String,
2057 pub path_exists: bool,
2058 pub is_directory: Option<bool>,
2059 pub readonly: Option<bool>,
2060 pub modified_at: Option<DateTime<Utc>>,
2061 pub secret_metadata_listed: bool,
2062}
2063
2064#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2065#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2066#[serde(tag = "backend", rename_all = "camelCase")]
2067pub enum ServiceAccountHeartbeatData {
2068 AwsIamRole(AwsIamRoleServiceAccountHeartbeatData),
2069 GcpServiceAccount(GcpServiceAccountHeartbeatData),
2070 AzureManagedIdentity(AzureManagedIdentityServiceAccountHeartbeatData),
2071 Local(LocalServiceAccountHeartbeatData),
2072}
2073
2074#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2075#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2076#[serde(rename_all = "camelCase")]
2077pub struct ServiceAccountHeartbeatStatus {
2078 pub health: ObservedHealth,
2079 pub lifecycle: ProviderLifecycleState,
2080 pub message: Option<String>,
2081 pub stale: bool,
2082 pub partial: bool,
2083 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2084}
2085
2086#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2087#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2088#[serde(rename_all = "camelCase")]
2089pub struct AwsIamRoleServiceAccountHeartbeatData {
2090 pub status: ServiceAccountHeartbeatStatus,
2091 pub role_name: String,
2092 pub role_arn: String,
2093 pub role_id: String,
2094 pub path: String,
2095 pub create_date: String,
2096 pub description: Option<String>,
2097 pub max_session_duration: Option<i32>,
2098 pub assume_role_policy_present: bool,
2099 pub permissions_boundary_type: Option<String>,
2100 pub permissions_boundary_arn: Option<String>,
2101 pub tag_count: u32,
2102 pub managed_tag_count: u32,
2103 pub attached_policy_count: u32,
2104 pub attached_policy_names: Vec<String>,
2105 pub inline_policy_count: u32,
2106 pub inline_policy_names: Vec<String>,
2107 pub stack_permissions_applied: bool,
2108 pub last_used_date: Option<String>,
2109 pub last_used_region: Option<String>,
2110}
2111
2112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2113#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2114#[serde(rename_all = "camelCase")]
2115pub struct GcpServiceAccountHeartbeatData {
2116 pub status: ServiceAccountHeartbeatStatus,
2117 pub name: Option<String>,
2118 pub project_id: Option<String>,
2119 pub unique_id: Option<String>,
2120 pub email: String,
2121 pub display_name: Option<String>,
2122 pub description: Option<String>,
2123 pub oauth2_client_id: Option<String>,
2124 pub disabled: Option<bool>,
2125 pub etag: Option<String>,
2126 pub project_binding_count: u32,
2127 pub project_roles: Vec<String>,
2128 pub service_account_binding_count: u32,
2129 pub service_account_roles: Vec<String>,
2130}
2131
2132#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2133#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2134#[serde(rename_all = "camelCase")]
2135pub struct AzureManagedIdentityServiceAccountHeartbeatData {
2136 pub status: ServiceAccountHeartbeatStatus,
2137 pub name: String,
2138 pub resource_id: String,
2139 pub resource_group: String,
2140 pub location: String,
2141 pub type_: Option<String>,
2142 pub client_id: Option<String>,
2143 pub principal_id: Option<String>,
2144 pub tenant_id: Option<String>,
2145 pub isolation_scope: Option<String>,
2146 pub managed_tag_count: u32,
2147 pub role_assignment_count: u32,
2148 pub role_assignment_ids: Vec<String>,
2149 pub custom_role_definition_count: u32,
2150 pub custom_role_definition_ids: Vec<String>,
2151 pub stack_permissions_applied: bool,
2152}
2153
2154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2155#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2156#[serde(rename_all = "camelCase")]
2157pub struct LocalServiceAccountHeartbeatData {
2158 pub status: ServiceAccountHeartbeatStatus,
2159 pub identity: String,
2160 pub configured: bool,
2161}
2162
2163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2164#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2165#[serde(tag = "backend", rename_all = "camelCase")]
2166pub enum NetworkHeartbeatData {
2167 AwsVpc(AwsVpcNetworkHeartbeatData),
2168 GcpVpc(GcpVpcNetworkHeartbeatData),
2169 AzureVnet(AzureVnetNetworkHeartbeatData),
2170}
2171
2172#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2173#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2174#[serde(rename_all = "camelCase")]
2175pub struct NetworkHeartbeatStatus {
2176 pub health: ObservedHealth,
2177 pub lifecycle: ProviderLifecycleState,
2178 pub message: Option<String>,
2179 pub stale: bool,
2180 pub partial: bool,
2181 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2182}
2183
2184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2185#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2186#[serde(rename_all = "camelCase")]
2187pub struct AwsVpcNetworkHeartbeatData {
2188 pub status: NetworkHeartbeatStatus,
2189 pub vpc_id: Option<String>,
2190 pub vpc_state: Option<String>,
2191 pub cidr_block: Option<String>,
2192 pub public_subnet_ids: Vec<String>,
2193 pub private_subnet_ids: Vec<String>,
2194 pub availability_zones: Vec<String>,
2195 pub internet_gateway_id: Option<String>,
2196 pub nat_gateway_id: Option<String>,
2197 pub route_table_count: u32,
2198 pub security_group_id: Option<String>,
2199 pub is_byo_vpc: bool,
2200}
2201
2202#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2203#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2204#[serde(rename_all = "camelCase")]
2205pub struct GcpVpcNetworkHeartbeatData {
2206 pub status: NetworkHeartbeatStatus,
2207 pub network_name: Option<String>,
2208 pub network_self_link: Option<String>,
2209 pub subnetwork_name: Option<String>,
2210 pub subnetwork_self_link: Option<String>,
2211 pub region: Option<String>,
2212 pub cidr_block: Option<String>,
2213 pub router_name: Option<String>,
2214 pub cloud_nat_name: Option<String>,
2215 pub firewall_name: Option<String>,
2216 pub is_byo_vpc: bool,
2217}
2218
2219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2220#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2221#[serde(rename_all = "camelCase")]
2222pub struct AzureVnetNetworkHeartbeatData {
2223 pub status: NetworkHeartbeatStatus,
2224 pub vnet_name: Option<String>,
2225 pub vnet_resource_id: Option<String>,
2226 pub resource_group: Option<String>,
2227 pub location: Option<String>,
2228 pub cidr_block: Option<String>,
2229 pub public_subnet_name: Option<String>,
2230 pub private_subnet_name: Option<String>,
2231 pub application_gateway_subnet_name: Option<String>,
2232 pub private_endpoint_subnet_name: Option<String>,
2233 pub nat_gateway_id: Option<String>,
2234 pub public_ip_id: Option<String>,
2235 pub nsg_id: Option<String>,
2236 pub is_byo_vnet: bool,
2237 pub last_byo_vnet_verification_error_code: Option<String>,
2238}
2239
2240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2241#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2242#[serde(tag = "backend", rename_all = "camelCase")]
2243pub enum RemoteStackManagementHeartbeatData {
2244 AwsIamRole(AwsRemoteStackManagementHeartbeatData),
2245 GcpServiceAccount(GcpRemoteStackManagementHeartbeatData),
2246 AzureManagedIdentity(AzureRemoteStackManagementHeartbeatData),
2247}
2248
2249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2250#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2251#[serde(rename_all = "camelCase")]
2252pub struct RemoteStackManagementHeartbeatStatus {
2253 pub health: ObservedHealth,
2254 pub lifecycle: ProviderLifecycleState,
2255 pub message: Option<String>,
2256 pub stale: bool,
2257 pub partial: bool,
2258 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2259}
2260
2261#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2262#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2263#[serde(rename_all = "camelCase")]
2264pub struct AwsRemoteStackManagementHeartbeatData {
2265 pub status: RemoteStackManagementHeartbeatStatus,
2266 pub role_name: Option<String>,
2267 pub role_arn: Option<String>,
2268 pub management_permissions_applied: bool,
2269}
2270
2271#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2272#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2273#[serde(rename_all = "camelCase")]
2274pub struct GcpRemoteStackManagementHeartbeatData {
2275 pub status: RemoteStackManagementHeartbeatStatus,
2276 pub service_account_email: Option<String>,
2277 pub service_account_unique_id: Option<String>,
2278 pub role_bound: bool,
2279 pub impersonation_granted: bool,
2280}
2281
2282#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2283#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2284#[serde(rename_all = "camelCase")]
2285pub struct AzureRemoteStackManagementHeartbeatData {
2286 pub status: RemoteStackManagementHeartbeatStatus,
2287 pub uami_resource_id: Option<String>,
2288 pub uami_client_id: Option<String>,
2289 pub uami_principal_id: Option<String>,
2290 pub tenant_id: Option<String>,
2291 pub fic_name: Option<String>,
2292 pub role_definition_id: Option<String>,
2293 pub role_assignment_ids: Vec<String>,
2294}
2295
2296#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2297#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2298#[serde(tag = "backend", rename_all = "camelCase")]
2299pub enum ArtifactRegistryHeartbeatData {
2300 AwsEcr(AwsEcrArtifactRegistryHeartbeatData),
2301 GcpArtifactRegistry(GcpArtifactRegistryHeartbeatData),
2302 AzureContainerRegistry(AzureContainerRegistryHeartbeatData),
2303 Local(LocalArtifactRegistryHeartbeatData),
2304}
2305
2306#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2307#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2308#[serde(rename_all = "camelCase")]
2309pub struct ArtifactRegistryHeartbeatStatus {
2310 pub health: ObservedHealth,
2311 pub lifecycle: ProviderLifecycleState,
2312 pub message: Option<String>,
2313 pub stale: bool,
2314 pub partial: bool,
2315 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2316}
2317
2318#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2319#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2320#[serde(rename_all = "camelCase")]
2321pub struct AwsEcrArtifactRegistryHeartbeatData {
2322 pub status: ArtifactRegistryHeartbeatStatus,
2323 pub registry_id: String,
2324 pub region: String,
2325 pub registry_uri: String,
2326 pub repository_prefix: String,
2327 pub pull_role_arn: Option<String>,
2328 pub push_role_arn: Option<String>,
2329 pub repository_count: u32,
2330 pub repositories_truncated: bool,
2331 pub repositories: Vec<AwsEcrRepositoryHeartbeatData>,
2332}
2333
2334#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2335#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2336#[serde(rename_all = "camelCase")]
2337pub struct AwsEcrRepositoryHeartbeatData {
2338 pub repository_arn: String,
2339 pub registry_id: String,
2340 pub repository_name: String,
2341 pub repository_uri: String,
2342 pub created_at: f64,
2343 pub image_tag_mutability: Option<String>,
2344 pub scan_on_push: Option<bool>,
2345 pub encryption_type: Option<String>,
2346 pub kms_key_present: bool,
2347}
2348
2349#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2350#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2351#[serde(rename_all = "camelCase")]
2352pub struct GcpArtifactRegistryHeartbeatData {
2353 pub status: ArtifactRegistryHeartbeatStatus,
2354 pub project_id: String,
2355 pub location: String,
2356 pub repository_id: String,
2357 pub name: Option<String>,
2358 pub format: Option<String>,
2359 pub mode: Option<String>,
2360 pub description: Option<String>,
2361 pub label_count: u32,
2362 pub cleanup_policy_count: u32,
2363 pub cleanup_policy_dry_run: Option<bool>,
2364 pub kms_key_name_present: bool,
2365 pub size_bytes: Option<String>,
2366 pub satisfies_pzs: Option<bool>,
2367 pub create_time: Option<String>,
2368 pub update_time: Option<String>,
2369 pub iam_policy_etag_present: bool,
2370 pub iam_binding_count: u32,
2371 pub iam_roles: Vec<String>,
2372 pub pull_service_account_email: Option<String>,
2373 pub push_service_account_email: Option<String>,
2374}
2375
2376#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2377#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2378#[serde(rename_all = "camelCase")]
2379pub struct AzureContainerRegistryHeartbeatData {
2380 pub status: ArtifactRegistryHeartbeatStatus,
2381 pub name: String,
2382 pub resource_id: Option<String>,
2383 pub resource_group: String,
2384 pub location: String,
2385 pub type_: Option<String>,
2386 pub login_server: Option<String>,
2387 pub sku_name: String,
2388 pub sku_tier: Option<String>,
2389 pub provisioning_state: Option<String>,
2390 pub admin_user_enabled: bool,
2391 pub anonymous_pull_enabled: bool,
2392 pub public_network_access: String,
2393 pub network_rule_bypass_options: String,
2394 pub network_rule_default_action: Option<String>,
2395 pub ip_rule_count: u32,
2396 pub encryption_status: Option<String>,
2397 pub encryption_key_vault_uri_present: bool,
2398 pub encryption_key_identifier_present: bool,
2399 pub policies_present: bool,
2400 pub policy_count: u32,
2401 pub private_endpoint_connection_count: u32,
2402 pub data_endpoint_enabled: Option<bool>,
2403 pub data_endpoint_host_names: Vec<String>,
2404 pub zone_redundancy: String,
2405 pub creation_date: Option<String>,
2406 pub managed_tag_count: u32,
2407}
2408
2409#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2410#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2411#[serde(rename_all = "camelCase")]
2412pub struct LocalArtifactRegistryHeartbeatData {
2413 pub status: ArtifactRegistryHeartbeatStatus,
2414 pub registry_url: String,
2415 pub reachable: bool,
2416}
2417
2418#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2419#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2420#[serde(tag = "backend", rename_all = "camelCase")]
2421pub enum BuildHeartbeatData {
2422 AwsCodeBuild(AwsCodeBuildHeartbeatData),
2423 GcpCloudBuild(GcpCloudBuildHeartbeatData),
2424 AzureContainerApps(AzureContainerAppsBuildHeartbeatData),
2425 KubernetesJob(KubernetesBuildHeartbeatData),
2426}
2427
2428#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2429#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2430#[serde(rename_all = "camelCase")]
2431pub struct BuildHeartbeatStatus {
2432 pub health: ObservedHealth,
2433 pub lifecycle: ProviderLifecycleState,
2434 pub message: Option<String>,
2435 pub stale: bool,
2436 pub partial: bool,
2437 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2438}
2439
2440#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2441#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2442#[serde(rename_all = "camelCase")]
2443pub struct AwsCodeBuildHeartbeatData {
2444 pub status: BuildHeartbeatStatus,
2445 pub project_name: String,
2446 pub project_arn: Option<String>,
2447 pub description: Option<String>,
2448 pub source_type: Option<String>,
2449 pub artifacts_type: Option<String>,
2450 pub artifacts_encryption_disabled: Option<bool>,
2451 pub environment_type: Option<String>,
2452 pub environment_image: Option<String>,
2453 pub compute_type: Option<String>,
2454 pub image_pull_credentials_type: Option<String>,
2455 pub privileged_mode: Option<bool>,
2456 pub environment_variable_count: u32,
2457 pub service_role_present: bool,
2458 pub encryption_key_present: bool,
2459 pub cloud_watch_logs_status: Option<String>,
2460 pub s3_logs_status: Option<String>,
2461 pub timeout_in_minutes: Option<i32>,
2462 pub queued_timeout_in_minutes: Option<i32>,
2463 pub created: Option<f64>,
2464 pub last_modified: Option<f64>,
2465}
2466
2467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2468#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2469#[serde(rename_all = "camelCase")]
2470pub struct GcpCloudBuildHeartbeatData {
2471 pub status: BuildHeartbeatStatus,
2472 pub project_id: String,
2473 pub location: String,
2474 pub build_config_id: String,
2475 pub service_account: Option<String>,
2476 pub environment_variable_count: u32,
2477}
2478
2479#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2480#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2481#[serde(rename_all = "camelCase")]
2482pub struct AzureContainerAppsBuildHeartbeatData {
2483 pub status: BuildHeartbeatStatus,
2484 pub managed_environment_id: String,
2485 pub resource_group_name: String,
2486 pub managed_identity_id: Option<String>,
2487 pub resource_prefix: Option<String>,
2488 pub environment_variable_count: u32,
2489}
2490
2491#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2492#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2493#[serde(rename_all = "camelCase")]
2494pub struct KubernetesBuildHeartbeatData {
2495 pub status: BuildHeartbeatStatus,
2496 pub job_name: String,
2497 pub namespace: String,
2498 pub active: Option<i32>,
2499 pub succeeded: Option<i32>,
2500 pub failed: Option<i32>,
2501 pub start_time: Option<DateTime<Utc>>,
2502 pub completion_time: Option<DateTime<Utc>>,
2503 pub condition_count: u32,
2504 pub image_digest: Option<String>,
2505 pub events: Vec<KubernetesEventSnapshot>,
2506}
2507
2508#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2509#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2510#[serde(tag = "backend", rename_all = "camelCase")]
2511pub enum ServiceActivationHeartbeatData {
2512 GcpServiceUsage(GcpServiceUsageActivationHeartbeatData),
2513 AzureResourceProvider(AzureResourceProviderActivationHeartbeatData),
2514}
2515
2516#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2517#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2518#[serde(rename_all = "camelCase")]
2519pub struct ServiceActivationHeartbeatStatus {
2520 pub health: ObservedHealth,
2521 pub lifecycle: ProviderLifecycleState,
2522 pub message: Option<String>,
2523 pub stale: bool,
2524 pub partial: bool,
2525 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2526}
2527
2528impl Default for ServiceActivationHeartbeatStatus {
2529 fn default() -> Self {
2530 Self {
2531 health: ObservedHealth::Healthy,
2532 lifecycle: ProviderLifecycleState::Running,
2533 message: None,
2534 stale: false,
2535 partial: false,
2536 collection_issues: vec![],
2537 }
2538 }
2539}
2540
2541#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2542#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2543#[serde(rename_all = "camelCase")]
2544pub struct GcpServiceUsageActivationHeartbeatData {
2545 pub status: ServiceActivationHeartbeatStatus,
2546 pub project_id: String,
2547 pub service_name: String,
2548 pub service_resource_name: Option<String>,
2549 pub title: Option<String>,
2550 pub state: Option<String>,
2551 pub enabled: bool,
2552 pub last_operation_name: Option<String>,
2553}
2554
2555#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2556#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2557#[serde(rename_all = "camelCase")]
2558pub struct AzureResourceProviderActivationHeartbeatData {
2559 pub status: ServiceActivationHeartbeatStatus,
2560 pub namespace: String,
2561 pub provider_id: Option<String>,
2562 pub registration_state: Option<String>,
2563 pub registration_policy: Option<String>,
2564 pub resource_type_count: u32,
2565 pub registered: bool,
2566}
2567
2568#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2569#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2570#[serde(rename_all = "camelCase")]
2571pub struct AzureResourceGroupHeartbeatData {
2572 pub status: AzureResourceGroupHeartbeatStatus,
2573 pub name: String,
2574 pub resource_id: Option<String>,
2575 pub location: Option<String>,
2576 pub provisioning_state: Option<String>,
2577 pub managed_tags: BTreeMap<String, String>,
2578}
2579
2580#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2581#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2582#[serde(rename_all = "camelCase")]
2583pub struct AzureResourceGroupHeartbeatStatus {
2584 pub health: ObservedHealth,
2585 pub lifecycle: ProviderLifecycleState,
2586 pub message: Option<String>,
2587 pub stale: bool,
2588 pub partial: bool,
2589 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2590}
2591
2592impl Default for AzureResourceGroupHeartbeatStatus {
2593 fn default() -> Self {
2594 Self {
2595 health: ObservedHealth::Healthy,
2596 lifecycle: ProviderLifecycleState::Running,
2597 message: None,
2598 stale: false,
2599 partial: false,
2600 collection_issues: vec![],
2601 }
2602 }
2603}
2604
2605#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2606#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2607#[serde(rename_all = "camelCase")]
2608pub struct AzureStorageAccountHeartbeatData {
2609 pub status: StorageHeartbeatStatus,
2610 pub name: String,
2611 pub resource_id: Option<String>,
2612 pub resource_group: Option<String>,
2613 pub location: Option<String>,
2614 pub kind: Option<String>,
2615 pub sku_name: Option<String>,
2616 pub sku_tier: Option<String>,
2617 pub provisioning_state: Option<String>,
2618 pub primary_endpoints: AzureStorageAccountEndpoints,
2619 pub secondary_endpoints: AzureStorageAccountEndpoints,
2620 pub public_network_access: Option<String>,
2621 pub allow_blob_public_access: Option<bool>,
2622 pub allow_shared_key_access: Option<bool>,
2623 pub minimum_tls_version: Option<String>,
2624 pub supports_https_traffic_only: Option<bool>,
2625 pub encryption_key_source: Option<String>,
2626 pub require_infrastructure_encryption: Option<bool>,
2627 pub network_default_action: Option<String>,
2628 pub network_bypass: Option<String>,
2629 pub network_ip_rule_count: Option<u32>,
2630 pub network_virtual_network_rule_count: Option<u32>,
2631 pub network_resource_access_rule_count: Option<u32>,
2632}
2633
2634#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
2635#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2636#[serde(rename_all = "camelCase")]
2637pub struct AzureStorageAccountEndpoints {
2638 pub blob: Option<String>,
2639 pub dfs: Option<String>,
2640 pub file: Option<String>,
2641 pub queue: Option<String>,
2642 pub table: Option<String>,
2643 pub web: Option<String>,
2644}
2645
2646#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2647#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2648#[serde(rename_all = "camelCase")]
2649pub struct AzureContainerAppsEnvironmentHeartbeatData {
2650 pub status: AzureContainerAppsEnvironmentHeartbeatStatus,
2651 pub name: String,
2652 pub resource_id: Option<String>,
2653 pub resource_group: Option<String>,
2654 pub location: Option<String>,
2655 pub kind: Option<String>,
2656 pub provisioning_state: Option<String>,
2657 pub default_domain: Option<String>,
2658 pub static_ip: Option<String>,
2659 pub custom_domain_verification_id: Option<String>,
2660 pub infrastructure_resource_group: Option<String>,
2661 pub event_stream_endpoint: Option<String>,
2662 pub zone_redundant: Option<bool>,
2663 pub workload_profile_count: u32,
2664 pub workload_profiles: Vec<AzureContainerAppsEnvironmentWorkloadProfile>,
2665}
2666
2667#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2668#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2669#[serde(rename_all = "camelCase")]
2670pub struct AzureContainerAppsEnvironmentHeartbeatStatus {
2671 pub health: ObservedHealth,
2672 pub lifecycle: ProviderLifecycleState,
2673 pub message: Option<String>,
2674 pub stale: bool,
2675 pub partial: bool,
2676 pub collection_issues: Vec<HeartbeatCollectionIssue>,
2677}
2678
2679#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2680#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2681#[serde(rename_all = "camelCase")]
2682pub struct AzureContainerAppsEnvironmentWorkloadProfile {
2683 pub name: String,
2684 pub workload_profile_type: String,
2685 pub minimum_count: Option<i32>,
2686 pub maximum_count: Option<i32>,
2687}
2688
2689#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2690#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2691#[serde(rename_all = "camelCase")]
2692pub struct AzureServiceBusNamespaceHeartbeatData {
2693 pub status: QueueHeartbeatStatus,
2694 pub name: String,
2695 pub resource_id: Option<String>,
2696 pub resource_group: Option<String>,
2697 pub location: Option<String>,
2698 pub sku_name: Option<String>,
2699 pub sku_tier: Option<String>,
2700 pub sku_capacity: Option<i32>,
2701 pub namespace_status: Option<String>,
2702 pub provisioning_state: Option<String>,
2703 pub service_bus_endpoint: Option<String>,
2704 pub metric_id: Option<String>,
2705 pub public_network_access: Option<String>,
2706 pub disable_local_auth: Option<bool>,
2707 pub minimum_tls_version: Option<String>,
2708 pub premium_messaging_partitions: Option<i32>,
2709 pub private_endpoint_connection_count: u32,
2710 pub zone_redundant: Option<bool>,
2711 pub created_at: Option<String>,
2712 pub updated_at: Option<String>,
2713}
2714
2715#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2716#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
2717#[serde(rename_all = "camelCase")]
2718pub struct NamedResourceDetail {
2719 pub name: String,
2720 pub region: Option<String>,
2721}
2722
2723#[cfg(test)]
2724mod tests {
2725 use super::*;
2726 use chrono::TimeZone as _;
2727 use serde_json::json;
2728
2729 fn observed_at() -> DateTime<Utc> {
2730 Utc.with_ymd_and_hms(2026, 5, 28, 10, 30, 0).unwrap()
2731 }
2732
2733 fn workload_status() -> WorkloadHeartbeatStatus {
2734 WorkloadHeartbeatStatus {
2735 health: ObservedHealth::Healthy,
2736 lifecycle: ProviderLifecycleState::Running,
2737 message: None,
2738 stale: false,
2739 partial: false,
2740 collection_issues: vec![],
2741 }
2742 }
2743
2744 fn workload_replicas() -> WorkloadReplicaStatus {
2745 WorkloadReplicaStatus {
2746 desired: Some(2),
2747 current: Some(2),
2748 ready: Some(1),
2749 available: Some(1),
2750 updated: Some(2),
2751 misscheduled: None,
2752 }
2753 }
2754
2755 fn heartbeat(data: ResourceHeartbeatData, resource_type: &str) -> ResourceHeartbeat {
2756 ResourceHeartbeat {
2757 deployment_id: Some("dep_123".to_string()),
2758 resource_id: "api".to_string(),
2759 resource_type: ResourceType::from(resource_type),
2760 controller_platform: Platform::Kubernetes,
2761 backend: HeartbeatBackend::Kubernetes,
2762 observed_at: observed_at(),
2763 data,
2764 raw: vec![RawHeartbeatSnippet {
2765 source: "kubernetes/apps/v1/deployments/api".to_string(),
2766 format: RawHeartbeatSnippetFormat::Json,
2767 collected_at: observed_at(),
2768 body: r#"{"readyReplicas":1}"#.to_string(),
2769 truncated: false,
2770 }],
2771 }
2772 }
2773
2774 #[test]
2775 fn resource_heartbeat_roundtrips_managed_resource_data() {
2776 let heartbeat_json = serde_json::to_value(heartbeat(
2777 ResourceHeartbeatData::Container(ContainerHeartbeatData::Kubernetes(
2778 KubernetesContainerHeartbeatData {
2779 status: workload_status(),
2780 namespace: "default".to_string(),
2781 name: "api".to_string(),
2782 workload_kind: KubernetesWorkloadKind::Deployment,
2783 replicas: workload_replicas(),
2784 restarts: None,
2785 cpu: None,
2786 memory: None,
2787 workload: None,
2788 pods: vec![],
2789 events: vec![],
2790 },
2791 )),
2792 "container",
2793 ))
2794 .unwrap();
2795
2796 let parsed: ResourceHeartbeat = serde_json::from_value(heartbeat_json).unwrap();
2797 assert_eq!(parsed.resource_id, "api");
2798 assert!(matches!(
2799 parsed.data,
2800 ResourceHeartbeatData::Container(ContainerHeartbeatData::Kubernetes(_))
2801 ));
2802 }
2803
2804 #[test]
2805 fn local_daemon_heartbeat_defaults_missing_daemon_name() {
2806 let mut value =
2807 serde_json::to_value(DaemonHeartbeatData::Local(LocalDaemonHeartbeatData {
2808 status: workload_status(),
2809 daemon_name: "agent".to_string(),
2810 runtime_id: "local-agent".to_string(),
2811 pid: None,
2812 command_supported: false,
2813 image_path_present: true,
2814 restart_count: None,
2815 exit_reason: None,
2816 daemon_instance: None,
2817 events: vec![],
2818 }))
2819 .unwrap();
2820
2821 value.as_object_mut().unwrap().remove("daemonName");
2822
2823 let parsed: DaemonHeartbeatData = serde_json::from_value(value).unwrap();
2824 match parsed {
2825 DaemonHeartbeatData::Local(data) => assert_eq!(data.daemon_name, ""),
2826 other => panic!("expected local daemon heartbeat, got {other:?}"),
2827 }
2828 }
2829
2830 #[test]
2831 fn container_heartbeat_serializes_resource_first_data() {
2832 let heartbeat = heartbeat(
2833 ResourceHeartbeatData::Container(ContainerHeartbeatData::Kubernetes(
2834 KubernetesContainerHeartbeatData {
2835 status: workload_status(),
2836 namespace: "default".to_string(),
2837 name: "api".to_string(),
2838 workload_kind: KubernetesWorkloadKind::Deployment,
2839 replicas: workload_replicas(),
2840 restarts: Some(1),
2841 cpu: Some(MetricSample {
2842 value: 0.5,
2843 unit: MetricUnit::Cores,
2844 }),
2845 memory: None,
2846 workload: None,
2847 pods: vec![],
2848 events: vec![],
2849 },
2850 )),
2851 "container",
2852 );
2853
2854 let value = serde_json::to_value(&heartbeat).unwrap();
2855
2856 assert_eq!(value["resourceType"], "container");
2857 assert_eq!(value["data"]["resourceType"], "container");
2858 assert_eq!(value["data"]["data"]["backend"], "kubernetes");
2859 assert_eq!(value["raw"][0]["body"], r#"{"readyReplicas":1}"#);
2860 assert!(value.get("collection").is_none());
2861 assert!(value["data"]["data"].get("summary").is_none());
2862 assert!(value["data"]["data"].get("detail").is_none());
2863 }
2864
2865 #[test]
2866 fn representative_workload_data_has_stable_tags() {
2867 let daemon = serde_json::to_value(ResourceHeartbeatData::Daemon(
2868 DaemonHeartbeatData::Kubernetes(KubernetesDaemonHeartbeatData {
2869 status: workload_status(),
2870 namespace: "default".to_string(),
2871 name: "agent".to_string(),
2872 replicas: workload_replicas(),
2873 restarts: Some(0),
2874 command_supported: true,
2875 cpu: None,
2876 memory: None,
2877 workload: None,
2878 pods: vec![],
2879 events: vec![],
2880 }),
2881 ))
2882 .unwrap();
2883 let worker = serde_json::to_value(ResourceHeartbeatData::Worker(
2884 WorkerHeartbeatData::AwsLambda(AwsLambdaWorkerHeartbeatData {
2885 status: workload_status(),
2886 function_name: "handler".to_string(),
2887 runtime: Some("nodejs22.x".to_string()),
2888 package_type: None,
2889 memory_size_mb: None,
2890 timeout_seconds: None,
2891 version: None,
2892 revision_id: None,
2893 last_modified: None,
2894 state: None,
2895 state_reason: None,
2896 state_reason_code: None,
2897 last_update_status: None,
2898 last_update_status_reason: None,
2899 last_update_status_reason_code: None,
2900 code_sha256: None,
2901 layer_count: 0,
2902 function_url_auth_type: None,
2903 function_url_cors_present: false,
2904 trigger_count: 0,
2905 }),
2906 ))
2907 .unwrap();
2908
2909 assert_eq!(daemon["resourceType"], "daemon");
2910 assert_eq!(daemon["data"]["backend"], "kubernetes");
2911 assert_eq!(worker["resourceType"], "worker");
2912 assert_eq!(worker["data"]["backend"], "awsLambda");
2913 }
2914
2915 #[test]
2918 fn gcp_sandbox_heartbeat_keeps_its_wire_tag_and_camel_case_names() {
2919 let data = ResourceHeartbeatData::Sandbox(SandboxHeartbeatData::GcpAgentPlatform(
2920 GcpAgentPlatformSandboxHeartbeatData {
2921 status: SandboxHeartbeatStatus::default(),
2922 engine: "eng".to_string(),
2923 template_id: "tpl1".to_string(),
2924 },
2925 ));
2926
2927 let value = serde_json::to_value(&data).unwrap();
2928 assert_eq!(
2929 value,
2930 json!({
2931 "resourceType": "sandbox",
2932 "data": {
2933 "backend": "gcpAgentPlatform",
2934 "status": {
2935 "health": "healthy",
2936 "lifecycle": "running",
2937 "message": null,
2938 "stale": false,
2939 "partial": false,
2940 "collectionIssues": []
2941 },
2942 "engine": "eng",
2943 "templateId": "tpl1"
2944 }
2945 })
2946 );
2947
2948 let parsed: ResourceHeartbeatData = serde_json::from_value(value).unwrap();
2949 assert_eq!(parsed, data);
2950 }
2951
2952 #[test]
2953 fn representative_cluster_and_data_variants_have_optional_counts() {
2954 let cluster = serde_json::to_value(ResourceHeartbeatData::KubernetesCluster(
2955 KubernetesClusterHeartbeatData {
2956 status: WorkloadHeartbeatStatus {
2957 health: ObservedHealth::Healthy,
2958 lifecycle: ProviderLifecycleState::Running,
2959 message: None,
2960 stale: false,
2961 partial: false,
2962 collection_issues: vec![],
2963 },
2964 node_counts: ObservedCounts {
2965 desired: Some(3),
2966 current: Some(3),
2967 ready: None,
2968 },
2969 pod_counts: ObservedCounts {
2970 desired: None,
2971 current: Some(12),
2972 ready: Some(11),
2973 },
2974 cpu: None,
2975 memory: None,
2976 name: "prod".to_string(),
2977 region: Some("us-east-1".to_string()),
2978 namespace: None,
2979 version: Some("1.33".to_string()),
2980 node_statuses: vec![],
2981 events: vec![],
2982 },
2983 ))
2984 .unwrap();
2985 let queue = serde_json::to_value(ResourceHeartbeatData::Queue(QueueHeartbeatData::AwsSqs(
2986 AwsSqsQueueHeartbeatData {
2987 status: QueueHeartbeatStatus {
2988 health: ObservedHealth::Healthy,
2989 lifecycle: ProviderLifecycleState::Running,
2990 message: None,
2991 stale: false,
2992 partial: false,
2993 collection_issues: vec![],
2994 },
2995 name: "jobs".to_string(),
2996 region: Some("us-east-1".to_string()),
2997 queue_url: Some("https://sqs.us-east-1.amazonaws.com/123/jobs".to_string()),
2998 queue_arn: Some("arn:aws:sqs:us-east-1:123:jobs".to_string()),
2999 visibility_timeout_seconds: Some(30),
3000 message_retention_period_seconds: Some(345600),
3001 delay_seconds: Some(0),
3002 receive_message_wait_time_seconds: Some(0),
3003 maximum_message_size: Some(262144),
3004 redrive_policy: None,
3005 redrive_allow_policy: None,
3006 fifo_queue: Some(false),
3007 content_based_deduplication: None,
3008 deduplication_scope: None,
3009 fifo_throughput_limit: None,
3010 sse_enabled: Some(false),
3011 kms_master_key_id: None,
3012 kms_data_key_reuse_period_seconds: None,
3013 sqs_managed_sse_enabled: Some(false),
3014 approximate_visible_messages: Some(42),
3015 approximate_in_flight_messages: Some(1),
3016 approximate_delayed_messages: Some(0),
3017 approximate_counts: true,
3018 },
3019 )))
3020 .unwrap();
3021 let storage = serde_json::to_value(ResourceHeartbeatData::Storage(
3022 StorageHeartbeatData::AwsS3(AwsS3StorageHeartbeatData {
3023 status: StorageHeartbeatStatus {
3024 health: ObservedHealth::Healthy,
3025 lifecycle: ProviderLifecycleState::Running,
3026 message: None,
3027 stale: false,
3028 partial: false,
3029 collection_issues: vec![],
3030 },
3031 name: "assets".to_string(),
3032 region: Some("us-east-1".to_string()),
3033 bucket_location: Some("us-east-1".to_string()),
3034 versioning_status: Some("Enabled".to_string()),
3035 versioning_enabled: Some(true),
3036 lifecycle_present: false,
3037 lifecycle_rule_count: Some(0),
3038 encryption_config_present: true,
3039 encryption_enabled: Some(true),
3040 public_access_block_present: true,
3041 block_public_acls: Some(true),
3042 ignore_public_acls: Some(true),
3043 block_public_policy: Some(true),
3044 restrict_public_buckets: Some(true),
3045 bucket_policy_present: Some(false),
3046 bucket_acl_present: Some(true),
3047 }),
3048 ))
3049 .unwrap();
3050 let gcp_storage = serde_json::to_value(ResourceHeartbeatData::Storage(
3051 StorageHeartbeatData::GcpCloudStorage(GcpCloudStorageHeartbeatData {
3052 status: StorageHeartbeatStatus {
3053 health: ObservedHealth::Healthy,
3054 lifecycle: ProviderLifecycleState::Running,
3055 message: None,
3056 stale: false,
3057 partial: false,
3058 collection_issues: vec![],
3059 },
3060 name: "assets".to_string(),
3061 bucket_id: Some("project/assets".to_string()),
3062 location: Some("US".to_string()),
3063 location_type: Some("multi-region".to_string()),
3064 storage_class: Some("STANDARD".to_string()),
3065 versioning_enabled: Some(true),
3066 lifecycle_present: false,
3067 lifecycle_rule_count: Some(0),
3068 retention_policy_effective_time: None,
3069 retention_policy_is_locked: None,
3070 retention_period: None,
3071 soft_delete_retention_duration_seconds: None,
3072 soft_delete_effective_time: None,
3073 uniform_bucket_level_access_enabled: Some(true),
3074 uniform_bucket_level_access_locked_time: None,
3075 public_access_prevention: Some("enforced".to_string()),
3076 encryption_config_present: true,
3077 default_kms_key_name: Some(
3078 "projects/p/locations/l/keyRings/r/cryptoKeys/k".to_string(),
3079 ),
3080 }),
3081 ))
3082 .unwrap();
3083 let kv = serde_json::to_value(ResourceHeartbeatData::Kv(KvHeartbeatData::AwsDynamoDb(
3084 AwsDynamoDbKvHeartbeatData {
3085 status: KvHeartbeatStatus {
3086 health: ObservedHealth::Healthy,
3087 lifecycle: ProviderLifecycleState::Running,
3088 message: None,
3089 stale: false,
3090 partial: false,
3091 collection_issues: vec![],
3092 },
3093 name: "state".to_string(),
3094 region: Some("us-east-1".to_string()),
3095 table_arn: None,
3096 table_status: Some("ACTIVE".to_string()),
3097 billing_mode: Some("PAY_PER_REQUEST".to_string()),
3098 key_schema: vec![AwsDynamoDbKeySchemaElement {
3099 attribute_name: "pk".to_string(),
3100 key_type: "HASH".to_string(),
3101 }],
3102 global_secondary_index_count: Some(0),
3103 local_secondary_index_count: Some(0),
3104 item_count: None,
3105 table_size_bytes: None,
3106 stream_enabled: Some(false),
3107 stream_view_type: None,
3108 ttl_status: Some("ENABLED".to_string()),
3109 ttl_attribute_name: Some("ttl".to_string()),
3110 deletion_protection_enabled: Some(false),
3111 sse_status: Some("ENABLED".to_string()),
3112 sse_type: Some("KMS".to_string()),
3113 table_class: None,
3114 replica_count: Some(0),
3115 restore_in_progress: None,
3116 },
3117 )))
3118 .unwrap();
3119
3120 assert_eq!(cluster["resourceType"], "kubernetes-cluster");
3121 assert!(cluster["data"].get("summary").is_none());
3122 assert!(cluster["data"].get("detail").is_none());
3123 assert_eq!(cluster["data"]["name"], "prod");
3124 assert_eq!(queue["data"]["backend"], "awsSqs");
3125 assert_eq!(queue["data"]["approximateVisibleMessages"], 42);
3126 assert!(queue["data"].get("summary").is_none());
3127 assert_eq!(storage["data"]["backend"], "awsS3");
3128 assert!(storage["data"].get("summary").is_none());
3129 assert_eq!(gcp_storage["data"]["backend"], "gcpCloudStorage");
3130 assert_eq!(gcp_storage["data"]["publicAccessPrevention"], "enforced");
3131 assert_eq!(kv["data"]["backend"], "awsDynamoDb");
3132 assert!(kv["data"].get("summary").is_none());
3133 assert_eq!(kv["data"]["itemCount"], json!(null));
3134 }
3135
3136 #[test]
3137 fn ai_heartbeat_serializes_stable_tags() {
3138 let aws = serde_json::to_value(ResourceHeartbeatData::Ai(AiHeartbeatData::AwsBedrock(
3139 AwsBedrockAiHeartbeatData {
3140 status: AiHeartbeatStatus::default(),
3141 region: "us-east-1".to_string(),
3142 availability: AiAvailabilityObservation::unobserved(
3143 AiAvailabilitySource::AwsBedrock,
3144 Platform::Aws,
3145 Some("us-east-1".to_string()),
3146 ),
3147 },
3148 )))
3149 .unwrap();
3150 let gcp = serde_json::to_value(ResourceHeartbeatData::Ai(AiHeartbeatData::GcpVertex(
3151 GcpVertexAiHeartbeatData {
3152 status: AiHeartbeatStatus::default(),
3153 project: "my-project".to_string(),
3154 location: "us-central1".to_string(),
3155 availability: AiAvailabilityObservation::unobserved(
3156 AiAvailabilitySource::GcpVertex,
3157 Platform::Gcp,
3158 Some("us-central1".to_string()),
3159 ),
3160 },
3161 )))
3162 .unwrap();
3163 let azure = serde_json::to_value(ResourceHeartbeatData::Ai(AiHeartbeatData::AzureFoundry(
3164 AzureFoundryAiHeartbeatData {
3165 status: AiHeartbeatStatus::default(),
3166 account_name: "my-ai-account".to_string(),
3167 endpoint: Some("https://my-ai-account.openai.azure.com/".to_string()),
3168 resource_group: Some("my-rg".to_string()),
3169 location: Some("eastus".to_string()),
3170 availability: AiAvailabilityObservation::unobserved(
3171 AiAvailabilitySource::AzureFoundry,
3172 Platform::Azure,
3173 Some("eastus".to_string()),
3174 ),
3175 },
3176 )))
3177 .unwrap();
3178
3179 assert_eq!(aws["resourceType"], "ai");
3180 assert_eq!(aws["data"]["backend"], "awsBedrock");
3181 assert_eq!(aws["data"]["region"], "us-east-1");
3182 assert!(aws["data"].get("summary").is_none());
3183
3184 assert_eq!(gcp["resourceType"], "ai");
3185 assert_eq!(gcp["data"]["backend"], "gcpVertex");
3186 assert_eq!(gcp["data"]["project"], "my-project");
3187 assert_eq!(gcp["data"]["location"], "us-central1");
3188
3189 assert_eq!(azure["resourceType"], "ai");
3190 assert_eq!(azure["data"]["backend"], "azureFoundry");
3191 assert_eq!(azure["data"]["accountName"], "my-ai-account");
3192 assert_eq!(
3193 azure["data"]["endpoint"],
3194 "https://my-ai-account.openai.azure.com/"
3195 );
3196 }
3197}