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