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