1use std::{
9 collections::{BTreeMap, BTreeSet},
10 fmt,
11 net::IpAddr,
12};
13
14use crate::{
15 Diagnostic, DiagnosticCode, InventoryFinding, JsonValueKind, ResourceEvidence, ResourceIdentity, ResourceKind,
16 SensitiveEnvironmentValue,
17};
18
19#[derive(Clone, Eq, PartialEq)]
25#[non_exhaustive]
26pub enum ObservationField<T> {
27 Absent,
29 Observed(ObservedValue<T>),
31 Unavailable,
33 Malformed,
35 VersionInapplicable,
37 NotApplicable,
39 Unmodelled(UnmodelledFieldId),
41}
42
43impl<T> fmt::Debug for ObservationField<T> {
44 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
45 formatter
46 .debug_tuple("ObservationField")
47 .field(&match self {
48 Self::Absent => "absent",
49 Self::Observed(_) => "observed",
50 Self::Unavailable => "unavailable",
51 Self::Malformed => "malformed",
52 Self::VersionInapplicable => "version_inapplicable",
53 Self::NotApplicable => "not_applicable",
54 Self::Unmodelled(id) => id.as_str(),
55 })
56 .finish()
57 }
58}
59
60impl<T> ObservationField<T> {
61 #[must_use]
63 pub const fn observed(&self) -> Option<&ObservedValue<T>> {
64 match self {
65 Self::Observed(value) => Some(value),
66 _ => None,
67 }
68 }
69
70 #[must_use]
72 pub const fn is_observed(&self) -> bool {
73 matches!(self, Self::Observed(_))
74 }
75
76 #[must_use]
78 pub const fn is_malformed(&self) -> bool {
79 matches!(self, Self::Malformed)
80 }
81}
82
83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
85#[non_exhaustive]
86pub enum ObservationOrigin {
87 Configured,
89 Effective,
91 RuntimeAssigned,
93 LocalResolution,
95}
96
97#[derive(Clone, Eq, PartialEq)]
99pub struct ObservedValue<T> {
100 value: T,
101 origin: ObservationOrigin,
102}
103
104impl<T> fmt::Debug for ObservedValue<T> {
105 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106 formatter
107 .debug_struct("ObservedValue")
108 .field("origin", &self.origin)
109 .finish_non_exhaustive()
110 }
111}
112
113impl<T> ObservedValue<T> {
114 #[must_use]
116 pub const fn new(value: T, origin: ObservationOrigin) -> Self {
117 Self { value, origin }
118 }
119
120 #[must_use]
122 pub const fn value(&self) -> &T {
123 &self.value
124 }
125
126 #[must_use]
128 pub const fn origin(&self) -> ObservationOrigin {
129 self.origin
130 }
131}
132
133#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
138#[non_exhaustive]
139pub enum UnmodelledFieldId {
140 ContainerHostConfig,
142 ContainerSecretGrant,
144 ContainerConfig,
146 ContainerNetworkSettings,
148 ContainerMount,
150 ContainerTopLevel,
152 PodMember,
154 PodInfraConfig,
156 PodTopLevel,
158 NetworkSubnet,
160 NetworkRoute,
162 NetworkTopLevel,
164 VolumeTopLevel,
166 ImageConfig,
168 ImageTopLevel,
170 SecretSpec,
172 SecretTopLevel,
174}
175
176impl UnmodelledFieldId {
177 #[must_use]
179 pub const fn as_str(self) -> &'static str {
180 match self {
181 Self::ContainerHostConfig => "podman.native.container.host-config",
182 Self::ContainerSecretGrant => "podman.native.container.secret-grant",
183 Self::ContainerConfig => "podman.native.container.config",
184 Self::ContainerNetworkSettings => "podman.native.container.network-settings",
185 Self::ContainerMount => "podman.native.container.mount",
186 Self::ContainerTopLevel => "podman.native.container.top-level",
187 Self::PodMember => "podman.native.pod.member",
188 Self::PodInfraConfig => "podman.native.pod.infra-config",
189 Self::PodTopLevel => "podman.native.pod.top-level",
190 Self::NetworkSubnet => "podman.native.network.subnet",
191 Self::NetworkRoute => "podman.native.network.route",
192 Self::NetworkTopLevel => "podman.native.network.top-level",
193 Self::VolumeTopLevel => "podman.native.volume.top-level",
194 Self::ImageConfig => "podman.native.image.config",
195 Self::ImageTopLevel => "podman.native.image.top-level",
196 Self::SecretSpec => "podman.native.secret.spec",
197 Self::SecretTopLevel => "podman.native.secret.top-level",
198 }
199 }
200}
201
202#[derive(Clone, Debug, Eq, PartialEq)]
204pub struct UnmodelledField {
205 id: UnmodelledFieldId,
206 path: String,
207 json_kind: JsonValueKind,
208 resource: ResourceIdentity,
209 evidence: ResourceEvidence,
210}
211
212impl UnmodelledField {
213 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
215 path: String,
216 json_kind: JsonValueKind,
217 resource: ResourceIdentity,
218 evidence: ResourceEvidence,
219 ) -> Self {
220 Self {
221 id: semantic_unmodelled_id(resource.kind(), &path),
222 path,
223 json_kind,
224 resource,
225 evidence,
226 }
227 }
228
229 #[must_use]
231 pub fn id(&self) -> &UnmodelledFieldId {
232 &self.id
233 }
234
235 #[must_use]
237 pub fn path(&self) -> &str {
238 &self.path
239 }
240
241 #[must_use]
243 pub const fn json_kind(&self) -> JsonValueKind {
244 self.json_kind
245 }
246
247 #[must_use]
249 pub fn resource(&self) -> &ResourceIdentity {
250 &self.resource
251 }
252
253 #[must_use]
255 pub fn evidence(&self) -> &ResourceEvidence {
256 &self.evidence
257 }
258}
259
260fn semantic_unmodelled_id(kind: ResourceKind, path: &str) -> UnmodelledFieldId {
261 match (kind, path) {
262 (ResourceKind::Container, value) if value.starts_with("$.HostConfig") => UnmodelledFieldId::ContainerHostConfig,
263 (ResourceKind::Container, value) if value.starts_with("$.Config.Secrets") => {
264 UnmodelledFieldId::ContainerSecretGrant
265 }
266 (ResourceKind::Container, value) if value.starts_with("$.Config") => UnmodelledFieldId::ContainerConfig,
267 (ResourceKind::Container, value) if value.starts_with("$.NetworkSettings") => {
268 UnmodelledFieldId::ContainerNetworkSettings
269 }
270 (ResourceKind::Container, value) if value.starts_with("$.Mounts") => UnmodelledFieldId::ContainerMount,
271 (ResourceKind::Pod, value) if value.starts_with("$.Containers") => UnmodelledFieldId::PodMember,
272 (ResourceKind::Pod, value) if value.starts_with("$.InfraConfig") => UnmodelledFieldId::PodInfraConfig,
273 (ResourceKind::Network, value) if value.starts_with("$.subnets") => UnmodelledFieldId::NetworkSubnet,
274 (ResourceKind::Network, value) if value.starts_with("$.routes") => UnmodelledFieldId::NetworkRoute,
275 (ResourceKind::Image, value) if value.starts_with("$.Config") => UnmodelledFieldId::ImageConfig,
276 (ResourceKind::Secret, value) if value.starts_with("$.Spec") => UnmodelledFieldId::SecretSpec,
277 (ResourceKind::Container, _) => UnmodelledFieldId::ContainerTopLevel,
278 (ResourceKind::Pod, _) => UnmodelledFieldId::PodTopLevel,
279 (ResourceKind::Network, _) => UnmodelledFieldId::NetworkTopLevel,
280 (ResourceKind::Volume, _) => UnmodelledFieldId::VolumeTopLevel,
281 (ResourceKind::Image, _) => UnmodelledFieldId::ImageTopLevel,
282 (ResourceKind::Secret, _) => UnmodelledFieldId::SecretTopLevel,
283 }
284}
285
286#[derive(Clone, Copy, Debug, Eq, PartialEq)]
288pub enum UnmodelledCompleteness {
289 Complete,
291 Incomplete,
293}
294
295#[derive(Clone, Copy, Debug, Eq, PartialEq)]
297#[non_exhaustive]
298pub enum ResourceObservationState {
299 Complete,
301 Unavailable,
303 Malformed,
305}
306
307#[derive(Clone, Debug, Eq, PartialEq)]
309pub struct ObservationHeader {
310 identity: ResourceIdentity,
311 state: ResourceObservationState,
312 evidence: ResourceEvidence,
313 findings: Vec<InventoryFinding>,
314 unmodelled: Vec<UnmodelledField>,
315 unmodelled_completeness: UnmodelledCompleteness,
316}
317
318impl ObservationHeader {
319 pub(crate) fn complete(
320 identity: ResourceIdentity,
321 evidence: ResourceEvidence,
322 findings: Vec<InventoryFinding>,
323 unmodelled: Vec<UnmodelledField>,
324 unmodelled_completeness: UnmodelledCompleteness,
325 ) -> Self {
326 Self {
327 identity,
328 state: ResourceObservationState::Complete,
329 evidence,
330 findings,
331 unmodelled,
332 unmodelled_completeness,
333 }
334 }
335
336 pub(crate) fn incomplete(
337 identity: ResourceIdentity,
338 evidence: ResourceEvidence,
339 state: ResourceObservationState,
340 findings: Vec<InventoryFinding>,
341 ) -> Self {
342 Self {
343 identity,
344 state,
345 evidence,
346 findings,
347 unmodelled: Vec::new(),
348 unmodelled_completeness: UnmodelledCompleteness::Incomplete,
349 }
350 }
351
352 #[must_use]
354 pub fn identity(&self) -> &ResourceIdentity {
355 &self.identity
356 }
357
358 #[must_use]
360 pub const fn state(&self) -> ResourceObservationState {
361 self.state
362 }
363
364 #[must_use]
366 pub fn evidence(&self) -> &ResourceEvidence {
367 &self.evidence
368 }
369
370 #[must_use]
372 pub fn findings(&self) -> &[InventoryFinding] {
373 &self.findings
374 }
375
376 pub(crate) fn findings_mut(&mut self) -> &mut Vec<InventoryFinding> {
377 &mut self.findings
378 }
379
380 #[must_use]
382 pub fn unmodelled_fields(&self) -> &[UnmodelledField] {
383 &self.unmodelled
384 }
385
386 #[must_use]
388 pub const fn unmodelled_completeness(&self) -> UnmodelledCompleteness {
389 self.unmodelled_completeness
390 }
391}
392
393#[derive(Clone, Debug, Eq, PartialEq)]
395pub(crate) struct NativeRelationship {
396 pub(crate) kind: ResourceKind,
397 pub(crate) references: Vec<String>,
401 pub(crate) field_paths: Vec<String>,
403}
404
405impl NativeRelationship {
406 pub(crate) fn new(kind: ResourceKind, target_id: impl Into<String>, field_path: impl Into<String>) -> Self {
407 Self {
408 kind,
409 references: vec![target_id.into()],
410 field_paths: vec![field_path.into()],
411 }
412 }
413
414 pub(crate) fn coalesced(
415 kind: ResourceKind,
416 references: impl IntoIterator<Item = (String, String)>,
417 ) -> Option<Self> {
418 let mut values = Vec::new();
419 let mut paths = Vec::new();
420 for (value, path) in references {
421 if !values.contains(&value) {
422 values.push(value);
423 }
424 paths.push(path);
425 }
426 (!values.is_empty()).then_some(Self {
427 kind,
428 references: values,
429 field_paths: paths,
430 })
431 }
432}
433
434#[derive(Clone, Debug, Eq, PartialEq)]
436pub struct ProtectedEnvironment {
437 entries: Vec<ProtectedEnvironmentEntry>,
438}
439
440impl ProtectedEnvironment {
441 pub(crate) fn new(entries: Vec<ProtectedEnvironmentEntry>) -> Self {
442 Self { entries }
443 }
444
445 #[must_use]
447 pub fn entries(&self) -> &[ProtectedEnvironmentEntry] {
448 &self.entries
449 }
450}
451
452#[derive(Clone, Debug, Eq, PartialEq)]
454pub struct ProtectedEnvironmentEntry {
455 name: String,
456 value: ProtectedEnvironmentValue,
457}
458
459impl ProtectedEnvironmentEntry {
460 pub(crate) fn new(name: String, value: ProtectedEnvironmentValue) -> Self {
461 Self { name, value }
462 }
463
464 #[must_use]
466 pub fn name(&self) -> &str {
467 &self.name
468 }
469
470 #[must_use]
472 pub fn value(&self) -> &ProtectedEnvironmentValue {
473 &self.value
474 }
475}
476
477#[derive(Clone, Debug, Eq, PartialEq)]
479#[non_exhaustive]
480pub enum ProtectedEnvironmentValue {
481 Redacted,
483 AuthorizedOpaque(SensitiveEnvironmentValue),
485}
486
487pub type Labels = BTreeMap<String, String>;
489
490#[derive(Clone, Eq, PartialEq)]
495pub struct ConfiguredContainerCommand(Vec<String>);
496
497impl ConfiguredContainerCommand {
498 pub(crate) const fn new(arguments: Vec<String>) -> Self {
499 Self(arguments)
500 }
501
502 #[must_use]
504 pub fn arguments(&self) -> &[String] {
505 &self.0
506 }
507}
508
509impl fmt::Debug for ConfiguredContainerCommand {
510 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
511 formatter
512 .debug_struct("ConfiguredContainerCommand")
513 .field("argument_count", &self.0.len())
514 .finish()
515 }
516}
517
518#[derive(Clone, Eq, PartialEq)]
520pub struct ConfiguredContainerEntrypoint(Vec<String>);
521
522impl ConfiguredContainerEntrypoint {
523 pub(crate) const fn new(arguments: Vec<String>) -> Self {
524 Self(arguments)
525 }
526
527 #[must_use]
529 pub fn arguments(&self) -> &[String] {
530 &self.0
531 }
532}
533
534impl fmt::Debug for ConfiguredContainerEntrypoint {
535 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
536 formatter
537 .debug_struct("ConfiguredContainerEntrypoint")
538 .field("argument_count", &self.0.len())
539 .finish()
540 }
541}
542
543macro_rules! configured_container_text {
544 ($type:ident, $doc:literal) => {
545 #[doc = $doc]
546 #[derive(Clone, Eq, PartialEq)]
547 pub struct $type(String);
548
549 impl $type {
550 pub(crate) fn new(value: String) -> Self {
551 Self(value)
552 }
553
554 #[must_use]
556 pub fn value(&self) -> &str {
557 &self.0
558 }
559 }
560
561 impl fmt::Debug for $type {
562 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
563 formatter.write_str(concat!(stringify!($type), "([redacted])"))
564 }
565 }
566 };
567}
568
569configured_container_text!(
570 ConfiguredContainerUser,
571 "A configured container user from `Config.User`."
572);
573configured_container_text!(
574 ConfiguredContainerWorkdir,
575 "A configured container working directory from `Config.WorkingDir`."
576);
577configured_container_text!(
578 ConfiguredContainerHostname,
579 "A configured container hostname from `Config.Hostname`."
580);
581
582#[derive(Clone, Eq, PartialEq)]
584pub struct NativeResourceReference {
585 reference: String,
586 field_path: String,
587}
588
589impl NativeResourceReference {
590 pub(crate) fn new(reference: String, field_path: String) -> Self {
591 Self { reference, field_path }
592 }
593
594 #[must_use]
596 pub fn reference(&self) -> &str {
597 &self.reference
598 }
599
600 #[must_use]
602 pub fn field_path(&self) -> &str {
603 &self.field_path
604 }
605}
606
607impl fmt::Debug for NativeResourceReference {
608 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
609 formatter
610 .debug_struct("NativeResourceReference")
611 .field("field_path", &self.field_path)
612 .finish_non_exhaustive()
613 }
614}
615
616#[derive(Clone, Copy, Debug, Eq, PartialEq)]
618#[non_exhaustive]
619pub enum ContainerMountKind {
620 NamedVolume,
622 Bind,
624}
625
626#[derive(Clone, Eq, PartialEq)]
628#[non_exhaustive]
629pub enum ContainerMountSource {
630 NamedVolume(String),
632 LocalBindPath(String),
634}
635
636#[derive(Clone, Copy, Debug, Eq, PartialEq)]
642#[non_exhaustive]
643pub enum ContainerMountSelinuxRelabel {
644 Shared,
646 Private,
648}
649
650#[derive(Clone, Copy, Debug, Eq, PartialEq)]
657#[non_exhaustive]
658pub enum AuthoredImageSpellingHint {
659 MatchesConfiguredImage,
661 MatchesLocalImageId,
663 Contradictory,
666}
667
668#[derive(Clone, Copy, Debug, Eq, PartialEq)]
673#[non_exhaustive]
674pub enum AuthoredMountRelabelHint {
675 Shared {
677 mount_index: usize,
679 },
680 Private {
682 mount_index: usize,
684 },
685 Contradictory {
687 mount_index: usize,
689 },
690}
691
692#[derive(Clone, Eq, PartialEq)]
700pub struct ContainerCreationEvidence {
701 image: ObservationField<AuthoredImageSpellingHint>,
702 mount_relabels: ObservationField<Vec<AuthoredMountRelabelHint>>,
703}
704
705impl ContainerCreationEvidence {
706 pub(crate) fn new(
707 image: ObservationField<AuthoredImageSpellingHint>,
708 mount_relabels: ObservationField<Vec<AuthoredMountRelabelHint>>,
709 ) -> Self {
710 Self { image, mount_relabels }
711 }
712
713 #[must_use]
716 pub const fn image(&self) -> &ObservationField<AuthoredImageSpellingHint> {
717 &self.image
718 }
719
720 #[must_use]
723 pub const fn mount_relabels(&self) -> &ObservationField<Vec<AuthoredMountRelabelHint>> {
724 &self.mount_relabels
725 }
726}
727
728impl fmt::Debug for ContainerCreationEvidence {
729 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
730 formatter
731 .debug_struct("ContainerCreationEvidence")
732 .field("image", &self.image)
733 .field("mount_relabels", &self.mount_relabels)
734 .finish()
735 }
736}
737
738impl ContainerMountSource {
739 #[must_use]
742 pub fn value(&self) -> &str {
743 match self {
744 Self::NamedVolume(value) | Self::LocalBindPath(value) => value,
745 }
746 }
747}
748
749impl fmt::Debug for ContainerMountSource {
750 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
751 let kind = match self {
752 Self::NamedVolume(_) => "named_volume",
753 Self::LocalBindPath(_) => "local_bind_path",
754 };
755 formatter.debug_tuple("ContainerMountSource").field(&kind).finish()
756 }
757}
758
759#[derive(Clone, Eq, PartialEq)]
761pub struct ContainerMountObservation {
762 kind: ContainerMountKind,
763 source: ObservationField<ContainerMountSource>,
764 local_backing_path: ObservationField<String>,
765 destination: ObservationField<String>,
766 writable: ObservationField<bool>,
767 options: ObservationField<Vec<String>>,
768 selinux_relabel: ObservationField<ContainerMountSelinuxRelabel>,
769 propagation: ObservationField<String>,
770 subpath: ObservationField<String>,
771}
772
773impl ContainerMountObservation {
774 #[allow(clippy::too_many_arguments)]
775 pub(crate) const fn new(
776 kind: ContainerMountKind,
777 source: ObservationField<ContainerMountSource>,
778 local_backing_path: ObservationField<String>,
779 destination: ObservationField<String>,
780 writable: ObservationField<bool>,
781 options: ObservationField<Vec<String>>,
782 selinux_relabel: ObservationField<ContainerMountSelinuxRelabel>,
783 propagation: ObservationField<String>,
784 subpath: ObservationField<String>,
785 ) -> Self {
786 Self {
787 kind,
788 source,
789 local_backing_path,
790 destination,
791 writable,
792 options,
793 selinux_relabel,
794 propagation,
795 subpath,
796 }
797 }
798
799 #[must_use]
801 pub const fn kind(&self) -> ContainerMountKind {
802 self.kind
803 }
804 #[must_use]
806 pub fn source(&self) -> &ObservationField<ContainerMountSource> {
807 &self.source
808 }
809 #[must_use]
812 pub fn local_backing_path(&self) -> &ObservationField<String> {
813 &self.local_backing_path
814 }
815 #[must_use]
817 pub fn destination(&self) -> &ObservationField<String> {
818 &self.destination
819 }
820 #[must_use]
822 pub fn writable(&self) -> &ObservationField<bool> {
823 &self.writable
824 }
825 #[must_use]
827 pub fn options(&self) -> &ObservationField<Vec<String>> {
828 &self.options
829 }
830
831 #[must_use]
834 pub fn selinux_relabel(&self) -> &ObservationField<ContainerMountSelinuxRelabel> {
835 &self.selinux_relabel
836 }
837 #[must_use]
839 pub fn propagation(&self) -> &ObservationField<String> {
840 &self.propagation
841 }
842 #[must_use]
844 pub fn subpath(&self) -> &ObservationField<String> {
845 &self.subpath
846 }
847}
848
849impl fmt::Debug for ContainerMountObservation {
850 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
851 formatter
852 .debug_struct("ContainerMountObservation")
853 .field("kind", &self.kind)
854 .field("source", &self.source)
855 .field(
856 "local_backing_path_state",
857 &observation_field_state(&self.local_backing_path),
858 )
859 .field("destination_state", &observation_field_state(&self.destination))
860 .field("writable", &self.writable)
861 .field(
862 "option_count",
863 &self.options.observed().map_or(0, |options| options.value().len()),
864 )
865 .field("selinux_relabel", &self.selinux_relabel)
866 .field("propagation_state", &observation_field_state(&self.propagation))
867 .field("subpath_state", &observation_field_state(&self.subpath))
868 .finish()
869 }
870}
871
872fn observation_field_state<T>(field: &ObservationField<T>) -> &'static str {
873 match field {
874 ObservationField::Observed(_) => "observed",
875 ObservationField::Absent => "absent",
876 ObservationField::Unavailable => "unavailable",
877 ObservationField::Malformed => "malformed",
878 ObservationField::VersionInapplicable => "version-inapplicable",
879 ObservationField::NotApplicable => "not-applicable",
880 ObservationField::Unmodelled(_) => "unmodelled",
881 }
882}
883
884#[derive(Clone, Eq, PartialEq)]
886pub struct ContainerSecretReference {
887 id: Option<NativeResourceReference>,
888 name: Option<NativeResourceReference>,
889}
890
891impl ContainerSecretReference {
892 pub(crate) const fn new(id: Option<NativeResourceReference>, name: Option<NativeResourceReference>) -> Self {
893 Self { id, name }
894 }
895 #[must_use]
897 pub fn id(&self) -> Option<&NativeResourceReference> {
898 self.id.as_ref()
899 }
900 #[must_use]
902 pub fn name(&self) -> Option<&NativeResourceReference> {
903 self.name.as_ref()
904 }
905}
906
907impl fmt::Debug for ContainerSecretReference {
908 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
909 formatter
910 .debug_struct("ContainerSecretReference")
911 .field("has_id", &self.id.is_some())
912 .field("has_name", &self.name.is_some())
913 .finish()
914 }
915}
916
917#[derive(Clone, Eq, PartialEq)]
919pub struct ContainerSecretGrantObservation {
920 reference: ObservationField<ContainerSecretReference>,
921 uid: ObservationField<u32>,
922 gid: ObservationField<u32>,
923 mode: ObservationField<u32>,
924}
925
926impl ContainerSecretGrantObservation {
927 pub(crate) const fn new(
928 reference: ObservationField<ContainerSecretReference>,
929 uid: ObservationField<u32>,
930 gid: ObservationField<u32>,
931 mode: ObservationField<u32>,
932 ) -> Self {
933 Self {
934 reference,
935 uid,
936 gid,
937 mode,
938 }
939 }
940 #[must_use]
942 pub fn reference(&self) -> &ObservationField<ContainerSecretReference> {
943 &self.reference
944 }
945 #[must_use]
947 pub fn uid(&self) -> &ObservationField<u32> {
948 &self.uid
949 }
950 #[must_use]
952 pub fn gid(&self) -> &ObservationField<u32> {
953 &self.gid
954 }
955 #[must_use]
957 pub fn mode(&self) -> &ObservationField<u32> {
958 &self.mode
959 }
960}
961
962impl fmt::Debug for ContainerSecretGrantObservation {
963 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
964 formatter
965 .debug_struct("ContainerSecretGrantObservation")
966 .field("reference", &self.reference)
967 .field("uid", &self.uid)
968 .field("gid", &self.gid)
969 .field("mode", &self.mode)
970 .finish()
971 }
972}
973
974#[derive(Clone, Copy, Debug, Eq, PartialEq)]
976#[non_exhaustive]
977pub enum NativeRestartPolicyName {
978 No,
980 Always,
982 OnFailure,
984 UnlessStopped,
986}
987
988#[derive(Clone, Debug, Eq, PartialEq)]
990pub struct NativeRestartPolicyObservation {
991 name: ObservationField<NativeRestartPolicyName>,
992 maximum_retry_count: ObservationField<u64>,
993}
994
995impl NativeRestartPolicyObservation {
996 pub(crate) const fn new(
997 name: ObservationField<NativeRestartPolicyName>,
998 maximum_retry_count: ObservationField<u64>,
999 ) -> Self {
1000 Self {
1001 name,
1002 maximum_retry_count,
1003 }
1004 }
1005
1006 #[must_use]
1008 pub fn name(&self) -> &ObservationField<NativeRestartPolicyName> {
1009 &self.name
1010 }
1011
1012 #[must_use]
1014 pub fn maximum_retry_count(&self) -> &ObservationField<u64> {
1015 &self.maximum_retry_count
1016 }
1017}
1018
1019#[derive(Clone, Eq, PartialEq)]
1021pub struct ProtectedHealthCommand {
1022 arguments: Vec<String>,
1023}
1024
1025impl ProtectedHealthCommand {
1026 pub(crate) const fn new(arguments: Vec<String>) -> Self {
1027 Self { arguments }
1028 }
1029
1030 #[must_use]
1032 pub fn argument_count(&self) -> usize {
1033 self.arguments.len()
1034 }
1035 pub fn expose<R>(&self, use_arguments: impl FnOnce(&[String]) -> R) -> R {
1037 use_arguments(&self.arguments)
1038 }
1039}
1040
1041impl fmt::Debug for ProtectedHealthCommand {
1042 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1043 formatter
1044 .debug_struct("ProtectedHealthCommand")
1045 .field("argument_count", &self.arguments.len())
1046 .finish()
1047 }
1048}
1049
1050impl fmt::Display for ProtectedHealthCommand {
1051 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1052 formatter.write_str("[redacted]")
1053 }
1054}
1055
1056#[derive(Clone, Debug, Eq, PartialEq)]
1058#[non_exhaustive]
1059pub enum NativeHealthCommand {
1060 Disabled,
1062 Shell(ProtectedHealthCommand),
1064 Exec(ProtectedHealthCommand),
1066}
1067
1068#[derive(Clone, Debug, Eq, PartialEq)]
1070pub struct NativeHealthCheckObservation {
1071 command: ObservationField<NativeHealthCommand>,
1072 interval: ObservationField<i64>,
1073 timeout: ObservationField<i64>,
1074 retries: ObservationField<u64>,
1075 start_period: ObservationField<i64>,
1076}
1077
1078impl NativeHealthCheckObservation {
1079 pub(crate) const fn new(
1080 command: ObservationField<NativeHealthCommand>,
1081 interval: ObservationField<i64>,
1082 timeout: ObservationField<i64>,
1083 retries: ObservationField<u64>,
1084 start_period: ObservationField<i64>,
1085 ) -> Self {
1086 Self {
1087 command,
1088 interval,
1089 timeout,
1090 retries,
1091 start_period,
1092 }
1093 }
1094
1095 #[must_use]
1097 pub fn command(&self) -> &ObservationField<NativeHealthCommand> {
1098 &self.command
1099 }
1100 #[must_use]
1102 pub fn interval(&self) -> &ObservationField<i64> {
1103 &self.interval
1104 }
1105 #[must_use]
1107 pub fn timeout(&self) -> &ObservationField<i64> {
1108 &self.timeout
1109 }
1110 #[must_use]
1112 pub fn retries(&self) -> &ObservationField<u64> {
1113 &self.retries
1114 }
1115 #[must_use]
1117 pub fn start_period(&self) -> &ObservationField<i64> {
1118 &self.start_period
1119 }
1120}
1121
1122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1124#[non_exhaustive]
1125pub enum NativeHealthFailureAction {
1126 None,
1128 Kill,
1130 Restart,
1132 Stop,
1134}
1135
1136#[derive(Clone, Debug, Eq, PartialEq)]
1138pub struct NativeStartupHealthCheckObservation {
1139 command: ObservationField<NativeHealthCommand>,
1140 interval: ObservationField<i64>,
1141 timeout: ObservationField<i64>,
1142 retries: ObservationField<u64>,
1143 start_period: ObservationField<i64>,
1144 successes: ObservationField<u64>,
1145}
1146
1147impl NativeStartupHealthCheckObservation {
1148 pub(crate) const fn new(
1149 command: ObservationField<NativeHealthCommand>,
1150 interval: ObservationField<i64>,
1151 timeout: ObservationField<i64>,
1152 retries: ObservationField<u64>,
1153 start_period: ObservationField<i64>,
1154 successes: ObservationField<u64>,
1155 ) -> Self {
1156 Self {
1157 command,
1158 interval,
1159 timeout,
1160 retries,
1161 start_period,
1162 successes,
1163 }
1164 }
1165
1166 #[must_use]
1168 pub fn command(&self) -> &ObservationField<NativeHealthCommand> {
1169 &self.command
1170 }
1171 #[must_use]
1173 pub fn interval(&self) -> &ObservationField<i64> {
1174 &self.interval
1175 }
1176 #[must_use]
1178 pub fn timeout(&self) -> &ObservationField<i64> {
1179 &self.timeout
1180 }
1181 #[must_use]
1183 pub fn retries(&self) -> &ObservationField<u64> {
1184 &self.retries
1185 }
1186 #[must_use]
1188 pub fn start_period(&self) -> &ObservationField<i64> {
1189 &self.start_period
1190 }
1191 #[must_use]
1193 pub fn successes(&self) -> &ObservationField<u64> {
1194 &self.successes
1195 }
1196}
1197
1198#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1200#[non_exhaustive]
1201pub enum NativeLogDriver {
1202 Journald,
1204 K8sFile,
1206}
1207
1208#[derive(Clone, Debug, Eq, PartialEq)]
1210pub struct NativeLoggingObservation {
1211 driver: ObservationField<NativeLogDriver>,
1212 size: ObservationField<String>,
1213}
1214
1215impl NativeLoggingObservation {
1216 pub(crate) const fn new(driver: ObservationField<NativeLogDriver>, size: ObservationField<String>) -> Self {
1217 Self { driver, size }
1218 }
1219
1220 #[must_use]
1222 pub fn driver(&self) -> &ObservationField<NativeLogDriver> {
1223 &self.driver
1224 }
1225
1226 #[must_use]
1228 pub fn size(&self) -> &ObservationField<String> {
1229 &self.size
1230 }
1231}
1232
1233#[derive(Clone, Debug, Eq, PartialEq)]
1238pub struct NativeCapability(String);
1239
1240impl NativeCapability {
1241 pub(crate) fn new(value: String) -> Self {
1242 Self(value)
1243 }
1244
1245 #[must_use]
1247 pub fn as_str(&self) -> &str {
1248 &self.0
1249 }
1250}
1251
1252#[derive(Clone, Debug, Eq, PartialEq)]
1254pub struct NativeOpaqueSecurityOptions {
1255 count: usize,
1256}
1257
1258impl NativeOpaqueSecurityOptions {
1259 pub(crate) const fn new(count: usize) -> Self {
1260 Self { count }
1261 }
1262
1263 #[must_use]
1265 pub const fn len(&self) -> usize {
1266 self.count
1267 }
1268
1269 #[must_use]
1271 pub const fn is_empty(&self) -> bool {
1272 self.count == 0
1273 }
1274}
1275
1276#[derive(Clone, Debug, Eq, PartialEq)]
1278pub struct NativeSecurityObservation {
1279 privileged: ObservationField<bool>,
1280 cap_add: ObservationField<Vec<NativeCapability>>,
1281 cap_drop: ObservationField<Vec<NativeCapability>>,
1282 security_options: ObservationField<NativeOpaqueSecurityOptions>,
1283 read_only_root_filesystem: ObservationField<bool>,
1284}
1285
1286impl NativeSecurityObservation {
1287 pub(crate) const fn new(
1288 privileged: ObservationField<bool>,
1289 cap_add: ObservationField<Vec<NativeCapability>>,
1290 cap_drop: ObservationField<Vec<NativeCapability>>,
1291 security_options: ObservationField<NativeOpaqueSecurityOptions>,
1292 read_only_root_filesystem: ObservationField<bool>,
1293 ) -> Self {
1294 Self {
1295 privileged,
1296 cap_add,
1297 cap_drop,
1298 security_options,
1299 read_only_root_filesystem,
1300 }
1301 }
1302
1303 #[must_use]
1305 pub fn privileged(&self) -> &ObservationField<bool> {
1306 &self.privileged
1307 }
1308
1309 #[must_use]
1311 pub fn cap_add(&self) -> &ObservationField<Vec<NativeCapability>> {
1312 &self.cap_add
1313 }
1314
1315 #[must_use]
1317 pub fn cap_drop(&self) -> &ObservationField<Vec<NativeCapability>> {
1318 &self.cap_drop
1319 }
1320
1321 #[must_use]
1323 pub fn security_options(&self) -> &ObservationField<NativeOpaqueSecurityOptions> {
1324 &self.security_options
1325 }
1326
1327 #[must_use]
1329 pub fn read_only_root_filesystem(&self) -> &ObservationField<bool> {
1330 &self.read_only_root_filesystem
1331 }
1332}
1333
1334#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1336#[non_exhaustive]
1337pub enum NativeNamespaceMode {
1338 Private,
1340 Host,
1342}
1343
1344#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1346#[non_exhaustive]
1347pub enum NativeIpcNamespaceMode {
1348 Private,
1350 Host,
1352 Shareable,
1354 None,
1356}
1357
1358#[derive(Clone, Debug, Eq, PartialEq)]
1360pub struct NativeNamespaceObservation {
1361 pid: ObservationField<NativeNamespaceMode>,
1362 ipc: ObservationField<NativeIpcNamespaceMode>,
1363 uts: ObservationField<NativeNamespaceMode>,
1364 cgroup: ObservationField<NativeNamespaceMode>,
1365}
1366
1367impl NativeNamespaceObservation {
1368 pub(crate) const fn new(
1369 pid: ObservationField<NativeNamespaceMode>,
1370 ipc: ObservationField<NativeIpcNamespaceMode>,
1371 uts: ObservationField<NativeNamespaceMode>,
1372 cgroup: ObservationField<NativeNamespaceMode>,
1373 ) -> Self {
1374 Self { pid, ipc, uts, cgroup }
1375 }
1376
1377 #[must_use]
1379 pub fn pid(&self) -> &ObservationField<NativeNamespaceMode> {
1380 &self.pid
1381 }
1382
1383 #[must_use]
1385 pub fn ipc(&self) -> &ObservationField<NativeIpcNamespaceMode> {
1386 &self.ipc
1387 }
1388
1389 #[must_use]
1391 pub fn uts(&self) -> &ObservationField<NativeNamespaceMode> {
1392 &self.uts
1393 }
1394
1395 #[must_use]
1397 pub fn cgroup(&self) -> &ObservationField<NativeNamespaceMode> {
1398 &self.cgroup
1399 }
1400}
1401
1402#[derive(Clone, Debug, Eq, PartialEq)]
1404pub struct NativeUlimitObservation {
1405 name: ObservationField<String>,
1406 soft: ObservationField<i64>,
1407 hard: ObservationField<i64>,
1408}
1409
1410impl NativeUlimitObservation {
1411 pub(crate) const fn new(
1412 name: ObservationField<String>,
1413 soft: ObservationField<i64>,
1414 hard: ObservationField<i64>,
1415 ) -> Self {
1416 Self { name, soft, hard }
1417 }
1418
1419 #[must_use]
1421 pub fn name(&self) -> &ObservationField<String> {
1422 &self.name
1423 }
1424
1425 #[must_use]
1427 pub fn soft(&self) -> &ObservationField<i64> {
1428 &self.soft
1429 }
1430
1431 #[must_use]
1433 pub fn hard(&self) -> &ObservationField<i64> {
1434 &self.hard
1435 }
1436}
1437
1438#[derive(Clone, Debug, Eq, PartialEq)]
1440pub struct NativeResourceControlObservation {
1441 cpu_shares: ObservationField<u64>,
1442 cpu_period: ObservationField<u64>,
1443 cpu_quota: ObservationField<i64>,
1444 memory: ObservationField<i64>,
1445 pids_limit: ObservationField<i64>,
1446 ulimits: ObservationField<Vec<NativeUlimitObservation>>,
1447}
1448
1449impl NativeResourceControlObservation {
1450 pub(crate) const fn new(
1451 cpu_shares: ObservationField<u64>,
1452 cpu_period: ObservationField<u64>,
1453 cpu_quota: ObservationField<i64>,
1454 memory: ObservationField<i64>,
1455 pids_limit: ObservationField<i64>,
1456 ulimits: ObservationField<Vec<NativeUlimitObservation>>,
1457 ) -> Self {
1458 Self {
1459 cpu_shares,
1460 cpu_period,
1461 cpu_quota,
1462 memory,
1463 pids_limit,
1464 ulimits,
1465 }
1466 }
1467
1468 #[must_use]
1470 pub fn cpu_shares(&self) -> &ObservationField<u64> {
1471 &self.cpu_shares
1472 }
1473
1474 #[must_use]
1476 pub fn cpu_period(&self) -> &ObservationField<u64> {
1477 &self.cpu_period
1478 }
1479
1480 #[must_use]
1482 pub fn cpu_quota(&self) -> &ObservationField<i64> {
1483 &self.cpu_quota
1484 }
1485
1486 #[must_use]
1488 pub fn memory(&self) -> &ObservationField<i64> {
1489 &self.memory
1490 }
1491
1492 #[must_use]
1494 pub fn pids_limit(&self) -> &ObservationField<i64> {
1495 &self.pids_limit
1496 }
1497
1498 #[must_use]
1500 pub fn ulimits(&self) -> &ObservationField<Vec<NativeUlimitObservation>> {
1501 &self.ulimits
1502 }
1503}
1504
1505#[derive(Clone, Eq, PartialEq)]
1507pub struct ContainerObservation {
1508 configured_image: ObservationField<String>,
1509 labels: ObservationField<Labels>,
1510 local_image_id: ObservationField<String>,
1511 relationships: ObservationField<Vec<NativeRelationship>>,
1512 environment: ObservationField<ProtectedEnvironment>,
1513 command: ObservationField<ConfiguredContainerCommand>,
1514 entrypoint: ObservationField<ConfiguredContainerEntrypoint>,
1515 user: ObservationField<ConfiguredContainerUser>,
1516 working_directory: ObservationField<ConfiguredContainerWorkdir>,
1517 hostname: ObservationField<ConfiguredContainerHostname>,
1518 pod_membership: ObservationField<NativeResourceReference>,
1519 native_dependencies: ObservationField<Vec<NativeResourceReference>>,
1520 mounts: ObservationField<Vec<ContainerMountObservation>>,
1521 secret_grants: ObservationField<Vec<ContainerSecretGrantObservation>>,
1522 memory_swappiness: ObservationField<u64>,
1523 infra: ObservationField<bool>,
1524 restart_policy: ObservationField<NativeRestartPolicyObservation>,
1525 health_check: ObservationField<NativeHealthCheckObservation>,
1526 health_failure_action: ObservationField<NativeHealthFailureAction>,
1527 startup_health_check: ObservationField<NativeStartupHealthCheckObservation>,
1528 logging: ObservationField<NativeLoggingObservation>,
1529 security: ObservationField<NativeSecurityObservation>,
1530 namespaces: ObservationField<NativeNamespaceObservation>,
1531 resource_controls: ObservationField<NativeResourceControlObservation>,
1532 networking: ObservationField<NativeNetworkingObservation>,
1533 creation_evidence: ObservationField<ContainerCreationEvidence>,
1534}
1535
1536macro_rules! observation_debug {
1537 ($type:ty, $($field:ident),+ $(,)?) => {
1538 impl fmt::Debug for $type {
1539 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1540 let mut debug = formatter.debug_struct(stringify!($type));
1541 $(debug.field(stringify!($field), &self.$field);)+
1542 debug.finish()
1543 }
1544 }
1545 };
1546}
1547
1548observation_debug!(
1549 ContainerObservation,
1550 labels,
1551 configured_image,
1552 local_image_id,
1553 relationships,
1554 environment,
1555 command,
1556 entrypoint,
1557 user,
1558 working_directory,
1559 hostname,
1560 pod_membership,
1561 native_dependencies,
1562 mounts,
1563 secret_grants,
1564 memory_swappiness,
1565 infra,
1566 networking,
1567 restart_policy,
1568 health_check,
1569 health_failure_action,
1570 startup_health_check,
1571 logging,
1572 security,
1573 namespaces,
1574 resource_controls,
1575);
1576
1577impl ContainerObservation {
1578 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
1580 labels: ObservationField<Labels>,
1581 configured_image: ObservationField<String>,
1582 local_image_id: ObservationField<String>,
1583 relationships: ObservationField<Vec<NativeRelationship>>,
1584 environment: ObservationField<ProtectedEnvironment>,
1585 command: ObservationField<ConfiguredContainerCommand>,
1586 entrypoint: ObservationField<ConfiguredContainerEntrypoint>,
1587 user: ObservationField<ConfiguredContainerUser>,
1588 working_directory: ObservationField<ConfiguredContainerWorkdir>,
1589 hostname: ObservationField<ConfiguredContainerHostname>,
1590 pod_membership: ObservationField<NativeResourceReference>,
1591 native_dependencies: ObservationField<Vec<NativeResourceReference>>,
1592 mounts: ObservationField<Vec<ContainerMountObservation>>,
1593 secret_grants: ObservationField<Vec<ContainerSecretGrantObservation>>,
1594 memory_swappiness: ObservationField<u64>,
1595 infra: ObservationField<bool>,
1596 restart_policy: ObservationField<NativeRestartPolicyObservation>,
1597 health_check: ObservationField<NativeHealthCheckObservation>,
1598 health_failure_action: ObservationField<NativeHealthFailureAction>,
1599 startup_health_check: ObservationField<NativeStartupHealthCheckObservation>,
1600 logging: ObservationField<NativeLoggingObservation>,
1601 security: ObservationField<NativeSecurityObservation>,
1602 namespaces: ObservationField<NativeNamespaceObservation>,
1603 resource_controls: ObservationField<NativeResourceControlObservation>,
1604 networking: ObservationField<NativeNetworkingObservation>,
1605 creation_evidence: ObservationField<ContainerCreationEvidence>,
1606 ) -> Self {
1607 Self {
1608 configured_image,
1609 labels,
1610 local_image_id,
1611 relationships,
1612 environment,
1613 command,
1614 entrypoint,
1615 user,
1616 working_directory,
1617 hostname,
1618 pod_membership,
1619 native_dependencies,
1620 mounts,
1621 secret_grants,
1622 memory_swappiness,
1623 infra,
1624 restart_policy,
1625 health_check,
1626 health_failure_action,
1627 startup_health_check,
1628 logging,
1629 security,
1630 namespaces,
1631 resource_controls,
1632 networking,
1633 creation_evidence,
1634 }
1635 }
1636
1637 #[must_use]
1639 pub fn labels(&self) -> &ObservationField<Labels> {
1640 &self.labels
1641 }
1642 #[must_use]
1646 pub fn configured_image(&self) -> &ObservationField<String> {
1647 &self.configured_image
1648 }
1649 #[must_use]
1653 pub fn local_image_id(&self) -> &ObservationField<String> {
1654 &self.local_image_id
1655 }
1656 #[must_use]
1658 pub fn environment(&self) -> &ObservationField<ProtectedEnvironment> {
1659 &self.environment
1660 }
1661 #[must_use]
1663 pub fn command(&self) -> &ObservationField<ConfiguredContainerCommand> {
1664 &self.command
1665 }
1666 #[must_use]
1668 pub fn entrypoint(&self) -> &ObservationField<ConfiguredContainerEntrypoint> {
1669 &self.entrypoint
1670 }
1671 #[must_use]
1673 pub fn user(&self) -> &ObservationField<ConfiguredContainerUser> {
1674 &self.user
1675 }
1676 #[must_use]
1678 pub fn working_directory(&self) -> &ObservationField<ConfiguredContainerWorkdir> {
1679 &self.working_directory
1680 }
1681 #[must_use]
1683 pub fn hostname(&self) -> &ObservationField<ConfiguredContainerHostname> {
1684 &self.hostname
1685 }
1686 #[must_use]
1688 pub fn pod_membership(&self) -> &ObservationField<NativeResourceReference> {
1689 &self.pod_membership
1690 }
1691 #[must_use]
1693 pub fn native_dependencies(&self) -> &ObservationField<Vec<NativeResourceReference>> {
1694 &self.native_dependencies
1695 }
1696 #[must_use]
1698 pub fn mounts(&self) -> &ObservationField<Vec<ContainerMountObservation>> {
1699 &self.mounts
1700 }
1701
1702 #[must_use]
1707 pub fn creation_evidence(&self) -> &ObservationField<ContainerCreationEvidence> {
1708 &self.creation_evidence
1709 }
1710 #[must_use]
1712 pub fn secret_grants(&self) -> &ObservationField<Vec<ContainerSecretGrantObservation>> {
1713 &self.secret_grants
1714 }
1715 #[must_use]
1717 pub fn memory_swappiness(&self) -> &ObservationField<u64> {
1718 &self.memory_swappiness
1719 }
1720 #[must_use]
1722 pub fn restart_policy(&self) -> &ObservationField<NativeRestartPolicyObservation> {
1723 &self.restart_policy
1724 }
1725 #[must_use]
1729 pub fn health_check(&self) -> &ObservationField<NativeHealthCheckObservation> {
1730 &self.health_check
1731 }
1732 #[must_use]
1736 pub fn health_failure_action(&self) -> &ObservationField<NativeHealthFailureAction> {
1737 &self.health_failure_action
1738 }
1739 #[must_use]
1743 pub fn startup_health_check(&self) -> &ObservationField<NativeStartupHealthCheckObservation> {
1744 &self.startup_health_check
1745 }
1746 #[must_use]
1748 pub fn logging(&self) -> &ObservationField<NativeLoggingObservation> {
1749 &self.logging
1750 }
1751 #[must_use]
1753 pub fn security(&self) -> &ObservationField<NativeSecurityObservation> {
1754 &self.security
1755 }
1756 #[must_use]
1758 pub fn namespaces(&self) -> &ObservationField<NativeNamespaceObservation> {
1759 &self.namespaces
1760 }
1761 #[must_use]
1763 pub fn resource_controls(&self) -> &ObservationField<NativeResourceControlObservation> {
1764 &self.resource_controls
1765 }
1766 #[must_use]
1768 pub fn infra(&self) -> &ObservationField<bool> {
1769 &self.infra
1770 }
1771 #[must_use]
1775 pub fn networking(&self) -> &ObservationField<NativeNetworkingObservation> {
1776 &self.networking
1777 }
1778 pub(crate) fn relationships(&self) -> &ObservationField<Vec<NativeRelationship>> {
1779 &self.relationships
1780 }
1781}
1782
1783#[derive(Clone, Eq, PartialEq)]
1785pub struct PodObservation {
1786 labels: ObservationField<Labels>,
1787 relationships: ObservationField<Vec<NativeRelationship>>,
1788 create_infra: ObservationField<bool>,
1789 networking: ObservationField<NativeNetworkingObservation>,
1790}
1791observation_debug!(PodObservation, labels, relationships, create_infra, networking);
1792
1793impl PodObservation {
1794 pub(crate) fn new(
1795 labels: ObservationField<Labels>,
1796 relationships: ObservationField<Vec<NativeRelationship>>,
1797 create_infra: ObservationField<bool>,
1798 networking: ObservationField<NativeNetworkingObservation>,
1799 ) -> Self {
1800 Self {
1801 labels,
1802 relationships,
1803 create_infra,
1804 networking,
1805 }
1806 }
1807 #[must_use]
1809 pub fn labels(&self) -> &ObservationField<Labels> {
1810 &self.labels
1811 }
1812 #[must_use]
1814 pub fn create_infra(&self) -> &ObservationField<bool> {
1815 &self.create_infra
1816 }
1817 #[must_use]
1819 pub fn networking(&self) -> &ObservationField<NativeNetworkingObservation> {
1820 &self.networking
1821 }
1822 pub(crate) fn relationships(&self) -> &ObservationField<Vec<NativeRelationship>> {
1823 &self.relationships
1824 }
1825}
1826
1827#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1829#[non_exhaustive]
1830pub enum NativePortProtocol {
1831 Tcp,
1833 Udp,
1835 Sctp,
1837}
1838
1839#[derive(Clone, Debug, Eq, PartialEq)]
1841pub struct NativePortBindingObservation {
1842 container_port: u16,
1843 protocol: NativePortProtocol,
1844 host_ip: ObservationField<IpAddr>,
1845 host_port: ObservationField<u16>,
1846}
1847
1848impl NativePortBindingObservation {
1849 pub(crate) const fn new(
1850 container_port: u16,
1851 protocol: NativePortProtocol,
1852 host_ip: ObservationField<IpAddr>,
1853 host_port: ObservationField<u16>,
1854 ) -> Self {
1855 Self {
1856 container_port,
1857 protocol,
1858 host_ip,
1859 host_port,
1860 }
1861 }
1862 #[must_use]
1864 pub const fn container_port(&self) -> u16 {
1865 self.container_port
1866 }
1867 #[must_use]
1869 pub const fn protocol(&self) -> NativePortProtocol {
1870 self.protocol
1871 }
1872 #[must_use]
1874 pub fn host_ip(&self) -> &ObservationField<IpAddr> {
1875 &self.host_ip
1876 }
1877 #[must_use]
1879 pub fn host_port(&self) -> &ObservationField<u16> {
1880 &self.host_port
1881 }
1882}
1883
1884#[derive(Clone, Debug, Eq, PartialEq)]
1886pub struct NativeOpaqueNetworkOptions {
1887 count: usize,
1888}
1889
1890impl NativeOpaqueNetworkOptions {
1891 pub(crate) const fn new(count: usize) -> Self {
1892 Self { count }
1893 }
1894 #[must_use]
1896 pub const fn len(&self) -> usize {
1897 self.count
1898 }
1899 #[must_use]
1901 pub const fn is_empty(&self) -> bool {
1902 self.count == 0
1903 }
1904}
1905
1906#[derive(Clone, Debug, Eq, PartialEq)]
1911pub struct NativeNetworkingObservation {
1912 port_bindings: ObservationField<Vec<NativePortBindingObservation>>,
1913 create_net_ns: ObservationField<bool>,
1914 host_network: ObservationField<bool>,
1915 dns_servers: ObservationField<Vec<IpAddr>>,
1916 dns_search: ObservationField<Vec<String>>,
1917 dns_options: ObservationField<Vec<String>>,
1918 host_entries: ObservationField<NativeOpaqueNetworkOptions>,
1919 networks: ObservationField<Vec<NativeResourceReference>>,
1920 network_options: ObservationField<NativeOpaqueNetworkOptions>,
1921 no_manage_resolv_conf: ObservationField<bool>,
1922 no_manage_hosts: ObservationField<bool>,
1923 static_ip: ObservationField<IpAddr>,
1924 static_mac: ObservationField<String>,
1925}
1926
1927impl NativeNetworkingObservation {
1928 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
1930 port_bindings: ObservationField<Vec<NativePortBindingObservation>>,
1931 create_net_ns: ObservationField<bool>,
1932 host_network: ObservationField<bool>,
1933 dns_servers: ObservationField<Vec<IpAddr>>,
1934 dns_search: ObservationField<Vec<String>>,
1935 dns_options: ObservationField<Vec<String>>,
1936 host_entries: ObservationField<NativeOpaqueNetworkOptions>,
1937 networks: ObservationField<Vec<NativeResourceReference>>,
1938 network_options: ObservationField<NativeOpaqueNetworkOptions>,
1939 no_manage_resolv_conf: ObservationField<bool>,
1940 no_manage_hosts: ObservationField<bool>,
1941 static_ip: ObservationField<IpAddr>,
1942 static_mac: ObservationField<String>,
1943 ) -> Self {
1944 Self {
1945 port_bindings,
1946 create_net_ns,
1947 host_network,
1948 dns_servers,
1949 dns_search,
1950 dns_options,
1951 host_entries,
1952 networks,
1953 network_options,
1954 no_manage_resolv_conf,
1955 no_manage_hosts,
1956 static_ip,
1957 static_mac,
1958 }
1959 }
1960 #[must_use]
1962 pub fn port_bindings(&self) -> &ObservationField<Vec<NativePortBindingObservation>> {
1963 &self.port_bindings
1964 }
1965 #[must_use]
1967 pub fn create_net_ns(&self) -> &ObservationField<bool> {
1968 &self.create_net_ns
1969 }
1970 #[must_use]
1972 pub fn host_network(&self) -> &ObservationField<bool> {
1973 &self.host_network
1974 }
1975 #[must_use]
1977 pub fn dns_servers(&self) -> &ObservationField<Vec<IpAddr>> {
1978 &self.dns_servers
1979 }
1980 #[must_use]
1982 pub fn dns_search(&self) -> &ObservationField<Vec<String>> {
1983 &self.dns_search
1984 }
1985 #[must_use]
1987 pub fn dns_options(&self) -> &ObservationField<Vec<String>> {
1988 &self.dns_options
1989 }
1990 #[must_use]
1995 pub fn host_entries(&self) -> &ObservationField<NativeOpaqueNetworkOptions> {
1996 &self.host_entries
1997 }
1998 #[must_use]
2000 pub fn networks(&self) -> &ObservationField<Vec<NativeResourceReference>> {
2001 &self.networks
2002 }
2003 #[must_use]
2005 pub fn network_options(&self) -> &ObservationField<NativeOpaqueNetworkOptions> {
2006 &self.network_options
2007 }
2008 #[must_use]
2010 pub fn no_manage_resolv_conf(&self) -> &ObservationField<bool> {
2011 &self.no_manage_resolv_conf
2012 }
2013 #[must_use]
2015 pub fn no_manage_hosts(&self) -> &ObservationField<bool> {
2016 &self.no_manage_hosts
2017 }
2018 #[must_use]
2020 pub fn static_ip(&self) -> &ObservationField<IpAddr> {
2021 &self.static_ip
2022 }
2023 #[must_use]
2025 pub fn static_mac(&self) -> &ObservationField<String> {
2026 &self.static_mac
2027 }
2028}
2029
2030#[derive(Clone, Eq, PartialEq)]
2032pub struct NetworkObservation {
2033 labels: ObservationField<Labels>,
2034 internal: ObservationField<bool>,
2035 options: ObservationField<NetworkOptionKeys>,
2036 subnets: ObservationField<Vec<NativeNetworkSubnetObservation>>,
2037 routes: ObservationField<Vec<NativeNetworkRouteObservation>>,
2038}
2039
2040impl NetworkObservation {
2041 pub(crate) fn new(
2042 labels: ObservationField<Labels>,
2043 internal: ObservationField<bool>,
2044 options: ObservationField<NetworkOptionKeys>,
2045 subnets: ObservationField<Vec<NativeNetworkSubnetObservation>>,
2046 routes: ObservationField<Vec<NativeNetworkRouteObservation>>,
2047 ) -> Self {
2048 Self {
2049 labels,
2050 internal,
2051 options,
2052 subnets,
2053 routes,
2054 }
2055 }
2056 #[must_use]
2058 pub fn labels(&self) -> &ObservationField<Labels> {
2059 &self.labels
2060 }
2061 #[must_use]
2063 pub fn internal(&self) -> &ObservationField<bool> {
2064 &self.internal
2065 }
2066 #[must_use]
2069 pub fn options(&self) -> &ObservationField<NetworkOptionKeys> {
2070 &self.options
2071 }
2072 #[must_use]
2074 pub fn subnets(&self) -> &ObservationField<Vec<NativeNetworkSubnetObservation>> {
2075 &self.subnets
2076 }
2077 #[must_use]
2079 pub fn routes(&self) -> &ObservationField<Vec<NativeNetworkRouteObservation>> {
2080 &self.routes
2081 }
2082}
2083observation_debug!(NetworkObservation, labels, internal, options, subnets, routes);
2084
2085#[derive(Clone, Debug, Eq, PartialEq)]
2090pub struct NativeNetworkCidr {
2091 spelling: String,
2092 network: IpAddr,
2093 prefix: u8,
2094}
2095
2096impl NativeNetworkCidr {
2097 pub(crate) fn parse(spelling: String) -> Option<Self> {
2098 let (network, prefix) = spelling.split_once('/')?;
2099 let network = network.parse::<IpAddr>().ok()?;
2100 let prefix = prefix.parse::<u8>().ok()?;
2101 (prefix <= if network.is_ipv4() { 32 } else { 128 }).then_some(Self {
2102 spelling,
2103 network,
2104 prefix,
2105 })
2106 }
2107
2108 #[must_use]
2110 pub fn as_str(&self) -> &str {
2111 &self.spelling
2112 }
2113
2114 #[must_use]
2116 pub(crate) fn contains(&self, address: IpAddr) -> bool {
2117 self.network.is_ipv4() == address.is_ipv4()
2118 && native_masked_address(self.network, self.prefix) == native_masked_address(address, self.prefix)
2119 }
2120
2121 #[must_use]
2123 pub(crate) const fn has_address_family(&self, address: IpAddr) -> bool {
2124 self.network.is_ipv4() == address.is_ipv4()
2125 }
2126}
2127
2128#[derive(Clone, Debug, Eq, PartialEq)]
2130pub struct NativeNetworkLeaseRange {
2131 start_ip: ObservationField<IpAddr>,
2132 end_ip: ObservationField<IpAddr>,
2133}
2134
2135impl NativeNetworkLeaseRange {
2136 pub(crate) const fn new(start_ip: ObservationField<IpAddr>, end_ip: ObservationField<IpAddr>) -> Self {
2137 Self { start_ip, end_ip }
2138 }
2139 #[must_use]
2141 pub const fn start_ip(&self) -> &ObservationField<IpAddr> {
2142 &self.start_ip
2143 }
2144 #[must_use]
2146 pub const fn end_ip(&self) -> &ObservationField<IpAddr> {
2147 &self.end_ip
2148 }
2149}
2150
2151#[derive(Clone, Debug, Eq, PartialEq)]
2153pub struct NativeNetworkSubnetObservation {
2154 cidr: ObservationField<NativeNetworkCidr>,
2155 gateway: ObservationField<IpAddr>,
2156 lease_range: ObservationField<NativeNetworkLeaseRange>,
2157}
2158
2159impl NativeNetworkSubnetObservation {
2160 pub(crate) const fn new(
2161 cidr: ObservationField<NativeNetworkCidr>,
2162 gateway: ObservationField<IpAddr>,
2163 lease_range: ObservationField<NativeNetworkLeaseRange>,
2164 ) -> Self {
2165 Self {
2166 cidr,
2167 gateway,
2168 lease_range,
2169 }
2170 }
2171 #[must_use]
2173 pub fn cidr(&self) -> &ObservationField<NativeNetworkCidr> {
2174 &self.cidr
2175 }
2176 #[must_use]
2178 pub fn gateway(&self) -> &ObservationField<IpAddr> {
2179 &self.gateway
2180 }
2181 #[must_use]
2183 pub fn lease_range(&self) -> &ObservationField<NativeNetworkLeaseRange> {
2184 &self.lease_range
2185 }
2186}
2187
2188#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2190#[non_exhaustive]
2191pub enum NativeNetworkRouteType {
2192 Unicast,
2194 Blackhole,
2196 Unreachable,
2198 Prohibit,
2200}
2201
2202#[derive(Clone, Debug, Eq, PartialEq)]
2204pub struct NativeNetworkRouteObservation {
2205 destination: ObservationField<NativeNetworkCidr>,
2206 gateway: ObservationField<IpAddr>,
2207 metric: ObservationField<u32>,
2208 route_type: ObservationField<NativeNetworkRouteType>,
2209}
2210
2211impl NativeNetworkRouteObservation {
2212 pub(crate) const fn new(
2213 destination: ObservationField<NativeNetworkCidr>,
2214 gateway: ObservationField<IpAddr>,
2215 metric: ObservationField<u32>,
2216 route_type: ObservationField<NativeNetworkRouteType>,
2217 ) -> Self {
2218 Self {
2219 destination,
2220 gateway,
2221 metric,
2222 route_type,
2223 }
2224 }
2225 #[must_use]
2227 pub fn destination(&self) -> &ObservationField<NativeNetworkCidr> {
2228 &self.destination
2229 }
2230 #[must_use]
2232 pub fn gateway(&self) -> &ObservationField<IpAddr> {
2233 &self.gateway
2234 }
2235 #[must_use]
2237 pub fn metric(&self) -> &ObservationField<u32> {
2238 &self.metric
2239 }
2240 #[must_use]
2242 pub fn route_type(&self) -> &ObservationField<NativeNetworkRouteType> {
2243 &self.route_type
2244 }
2245}
2246
2247fn native_masked_address(address: IpAddr, prefix: u8) -> IpAddr {
2248 match address {
2249 IpAddr::V4(address) => {
2250 let mask = if prefix == 0 { 0 } else { u32::MAX << (32 - prefix) };
2251 IpAddr::V4(std::net::Ipv4Addr::from(u32::from(address) & mask))
2252 }
2253 IpAddr::V6(address) => {
2254 let mask = if prefix == 0 { 0 } else { u128::MAX << (128 - prefix) };
2255 IpAddr::V6(std::net::Ipv6Addr::from(u128::from(address) & mask))
2256 }
2257 }
2258}
2259
2260#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
2262pub struct NetworkOptionKeys(BTreeSet<String>);
2263
2264impl NetworkOptionKeys {
2265 pub(crate) fn new(keys: impl IntoIterator<Item = String>) -> Self {
2266 Self(keys.into_iter().collect())
2267 }
2268
2269 pub fn keys(&self) -> impl Iterator<Item = &str> {
2271 self.0.iter().map(String::as_str)
2272 }
2273
2274 #[must_use]
2276 pub fn len(&self) -> usize {
2277 self.0.len()
2278 }
2279
2280 #[must_use]
2282 pub fn is_empty(&self) -> bool {
2283 self.0.is_empty()
2284 }
2285}
2286
2287impl fmt::Debug for NetworkOptionKeys {
2288 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2289 formatter
2290 .debug_struct("NetworkOptionKeys")
2291 .field("count", &self.len())
2292 .finish()
2293 }
2294}
2295
2296#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2298pub enum VolumeOwnerIdWireValue {
2299 WireAbsentMayMeanZero,
2302 Explicit(UnixId),
2304}
2305
2306#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2308pub struct UnixId(u32);
2309
2310impl UnixId {
2311 pub(crate) const fn new(value: u32) -> Self {
2312 Self(value)
2313 }
2314 #[must_use]
2316 pub const fn get(self) -> u32 {
2317 self.0
2318 }
2319}
2320
2321#[derive(Clone, Debug, Eq, PartialEq)]
2323pub struct NativeTimestamp(String);
2324
2325impl NativeTimestamp {
2326 pub(crate) fn new(value: String) -> Self {
2327 Self(value)
2328 }
2329
2330 #[must_use]
2332 pub fn as_str(&self) -> &str {
2333 &self.0
2334 }
2335}
2336
2337#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2339pub struct NativeSecretDriverOptions {
2340 count: usize,
2341}
2342
2343impl NativeSecretDriverOptions {
2344 pub(crate) const fn new(count: usize) -> Self {
2345 Self { count }
2346 }
2347
2348 #[must_use]
2350 pub const fn len(&self) -> usize {
2351 self.count
2352 }
2353
2354 #[must_use]
2356 pub const fn is_empty(&self) -> bool {
2357 self.count == 0
2358 }
2359}
2360
2361#[derive(Clone, Debug, Eq, PartialEq)]
2363pub struct NativeSecretDriverObservation {
2364 name: ObservationField<String>,
2365 options: ObservationField<NativeSecretDriverOptions>,
2366}
2367
2368impl NativeSecretDriverObservation {
2369 pub(crate) const fn new(
2370 name: ObservationField<String>,
2371 options: ObservationField<NativeSecretDriverOptions>,
2372 ) -> Self {
2373 Self { name, options }
2374 }
2375
2376 #[must_use]
2378 pub fn name(&self) -> &ObservationField<String> {
2379 &self.name
2380 }
2381
2382 #[must_use]
2384 pub fn options(&self) -> &ObservationField<NativeSecretDriverOptions> {
2385 &self.options
2386 }
2387}
2388
2389#[derive(Clone, Eq, PartialEq)]
2391pub struct VolumeObservation {
2392 labels: ObservationField<Labels>,
2393 uid: ObservationField<VolumeOwnerIdWireValue>,
2394 gid: ObservationField<VolumeOwnerIdWireValue>,
2395 driver: ObservationField<String>,
2396 created_at: ObservationField<NativeTimestamp>,
2397 anonymous: ObservationField<bool>,
2398}
2399observation_debug!(VolumeObservation, labels, uid, gid, driver, created_at, anonymous);
2400
2401impl VolumeObservation {
2402 pub(crate) fn new(
2403 labels: ObservationField<Labels>,
2404 uid: ObservationField<VolumeOwnerIdWireValue>,
2405 gid: ObservationField<VolumeOwnerIdWireValue>,
2406 driver: ObservationField<String>,
2407 created_at: ObservationField<NativeTimestamp>,
2408 anonymous: ObservationField<bool>,
2409 ) -> Self {
2410 Self {
2411 labels,
2412 uid,
2413 gid,
2414 driver,
2415 created_at,
2416 anonymous,
2417 }
2418 }
2419 #[must_use]
2421 pub fn labels(&self) -> &ObservationField<Labels> {
2422 &self.labels
2423 }
2424 #[must_use]
2426 pub fn uid(&self) -> &ObservationField<VolumeOwnerIdWireValue> {
2427 &self.uid
2428 }
2429 #[must_use]
2431 pub fn gid(&self) -> &ObservationField<VolumeOwnerIdWireValue> {
2432 &self.gid
2433 }
2434 #[must_use]
2436 pub fn driver(&self) -> &ObservationField<String> {
2437 &self.driver
2438 }
2439 #[must_use]
2441 pub fn created_at(&self) -> &ObservationField<NativeTimestamp> {
2442 &self.created_at
2443 }
2444 #[must_use]
2446 pub fn anonymous(&self) -> &ObservationField<bool> {
2447 &self.anonymous
2448 }
2449}
2450
2451#[derive(Clone, Eq, PartialEq)]
2453pub struct ImageObservation {
2454 labels: ObservationField<Labels>,
2455 repo_tags: ObservationField<Vec<String>>,
2456 repo_digests: ObservationField<Vec<String>>,
2457 environment: ObservationField<ProtectedEnvironment>,
2458 digest: ObservationField<String>,
2459 created: ObservationField<NativeTimestamp>,
2460 author: ObservationField<String>,
2461 architecture: ObservationField<String>,
2462 operating_system: ObservationField<String>,
2463 manifest_type: ObservationField<String>,
2464}
2465
2466pub(crate) struct ImageObservationFields {
2467 pub(crate) labels: ObservationField<Labels>,
2468 pub(crate) repo_tags: ObservationField<Vec<String>>,
2469 pub(crate) repo_digests: ObservationField<Vec<String>>,
2470 pub(crate) environment: ObservationField<ProtectedEnvironment>,
2471 pub(crate) digest: ObservationField<String>,
2472 pub(crate) created: ObservationField<NativeTimestamp>,
2473 pub(crate) author: ObservationField<String>,
2474 pub(crate) architecture: ObservationField<String>,
2475 pub(crate) operating_system: ObservationField<String>,
2476 pub(crate) manifest_type: ObservationField<String>,
2477}
2478observation_debug!(
2479 ImageObservation,
2480 labels,
2481 repo_tags,
2482 repo_digests,
2483 environment,
2484 digest,
2485 created,
2486 author,
2487 architecture,
2488 operating_system,
2489 manifest_type
2490);
2491
2492impl ImageObservation {
2493 pub(crate) fn new(fields: ImageObservationFields) -> Self {
2494 let ImageObservationFields {
2495 labels,
2496 repo_tags,
2497 repo_digests,
2498 environment,
2499 digest,
2500 created,
2501 author,
2502 architecture,
2503 operating_system,
2504 manifest_type,
2505 } = fields;
2506 Self {
2507 labels,
2508 repo_tags,
2509 repo_digests,
2510 environment,
2511 digest,
2512 created,
2513 author,
2514 architecture,
2515 operating_system,
2516 manifest_type,
2517 }
2518 }
2519 #[must_use]
2521 pub fn labels(&self) -> &ObservationField<Labels> {
2522 &self.labels
2523 }
2524 #[must_use]
2526 pub fn repo_tags(&self) -> &ObservationField<Vec<String>> {
2527 &self.repo_tags
2528 }
2529 #[must_use]
2531 pub fn repo_digests(&self) -> &ObservationField<Vec<String>> {
2532 &self.repo_digests
2533 }
2534 #[must_use]
2536 pub fn environment(&self) -> &ObservationField<ProtectedEnvironment> {
2537 &self.environment
2538 }
2539 #[must_use]
2541 pub fn digest(&self) -> &ObservationField<String> {
2542 &self.digest
2543 }
2544 #[must_use]
2546 pub fn created(&self) -> &ObservationField<NativeTimestamp> {
2547 &self.created
2548 }
2549 #[must_use]
2551 pub fn author(&self) -> &ObservationField<String> {
2552 &self.author
2553 }
2554 #[must_use]
2556 pub fn architecture(&self) -> &ObservationField<String> {
2557 &self.architecture
2558 }
2559 #[must_use]
2561 pub fn operating_system(&self) -> &ObservationField<String> {
2562 &self.operating_system
2563 }
2564 #[must_use]
2566 pub fn manifest_type(&self) -> &ObservationField<String> {
2567 &self.manifest_type
2568 }
2569}
2570
2571#[derive(Clone, Eq, PartialEq)]
2573pub struct SecretObservation {
2574 labels: ObservationField<Labels>,
2575 driver: ObservationField<NativeSecretDriverObservation>,
2576 created_at: ObservationField<NativeTimestamp>,
2577 updated_at: ObservationField<NativeTimestamp>,
2578}
2579observation_debug!(SecretObservation, labels, driver, created_at, updated_at);
2580
2581impl SecretObservation {
2582 pub(crate) fn new(
2583 labels: ObservationField<Labels>,
2584 driver: ObservationField<NativeSecretDriverObservation>,
2585 created_at: ObservationField<NativeTimestamp>,
2586 updated_at: ObservationField<NativeTimestamp>,
2587 ) -> Self {
2588 Self {
2589 labels,
2590 driver,
2591 created_at,
2592 updated_at,
2593 }
2594 }
2595 #[must_use]
2597 pub fn labels(&self) -> &ObservationField<Labels> {
2598 &self.labels
2599 }
2600 #[must_use]
2602 pub fn driver(&self) -> &ObservationField<NativeSecretDriverObservation> {
2603 &self.driver
2604 }
2605 #[must_use]
2607 pub fn created_at(&self) -> &ObservationField<NativeTimestamp> {
2608 &self.created_at
2609 }
2610 #[must_use]
2612 pub fn updated_at(&self) -> &ObservationField<NativeTimestamp> {
2613 &self.updated_at
2614 }
2615}
2616
2617#[derive(Clone, Eq, PartialEq)]
2619#[non_exhaustive]
2620#[allow(clippy::large_enum_variant)] pub enum ResourceDetails {
2622 Container(ContainerObservation),
2624 Pod(PodObservation),
2626 Network(NetworkObservation),
2628 Volume(VolumeObservation),
2630 Image(ImageObservation),
2632 Secret(SecretObservation),
2634}
2635
2636impl fmt::Debug for ResourceDetails {
2637 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2638 match self {
2639 Self::Container(value) => formatter
2640 .debug_tuple("ResourceDetails::Container")
2641 .field(value)
2642 .finish(),
2643 Self::Pod(value) => formatter.debug_tuple("ResourceDetails::Pod").field(value).finish(),
2644 Self::Network(value) => formatter.debug_tuple("ResourceDetails::Network").field(value).finish(),
2645 Self::Volume(value) => formatter.debug_tuple("ResourceDetails::Volume").field(value).finish(),
2646 Self::Image(value) => formatter.debug_tuple("ResourceDetails::Image").field(value).finish(),
2647 Self::Secret(value) => formatter.debug_tuple("ResourceDetails::Secret").field(value).finish(),
2648 }
2649 }
2650}
2651
2652impl ResourceDetails {
2653 #[must_use]
2655 pub const fn kind(&self) -> ResourceKind {
2656 match self {
2657 Self::Container(_) => ResourceKind::Container,
2658 Self::Pod(_) => ResourceKind::Pod,
2659 Self::Network(_) => ResourceKind::Network,
2660 Self::Volume(_) => ResourceKind::Volume,
2661 Self::Image(_) => ResourceKind::Image,
2662 Self::Secret(_) => ResourceKind::Secret,
2663 }
2664 }
2665}
2666
2667#[derive(Clone, Eq, PartialEq)]
2669pub struct ResourceObservation {
2670 header: ObservationHeader,
2671 details: ResourceDetails,
2672}
2673
2674impl ResourceObservation {
2675 pub(crate) fn try_new(header: ObservationHeader, details: ResourceDetails) -> Result<Self, Diagnostic> {
2676 if header.identity().kind() != details.kind() {
2677 return Err(Diagnostic::new(DiagnosticCode::ResourceMalformed));
2678 }
2679 Ok(Self { header, details })
2680 }
2681
2682 pub(crate) fn incomplete(header: ObservationHeader) -> Self {
2683 let details = incomplete_details(header.identity().kind(), header.state());
2684 Self { header, details }
2685 }
2686
2687 #[must_use]
2689 pub fn header(&self) -> &ObservationHeader {
2690 &self.header
2691 }
2692 #[must_use]
2694 pub fn details(&self) -> &ResourceDetails {
2695 &self.details
2696 }
2697
2698 pub(crate) fn header_mut(&mut self) -> &mut ObservationHeader {
2699 &mut self.header
2700 }
2701
2702 pub(crate) fn relationships(&self) -> Option<&ObservationField<Vec<NativeRelationship>>> {
2703 match &self.details {
2704 ResourceDetails::Container(value) => Some(value.relationships()),
2705 ResourceDetails::Pod(value) => Some(value.relationships()),
2706 _ => None,
2707 }
2708 }
2709
2710 pub(crate) fn labels(&self) -> &ObservationField<Labels> {
2711 match &self.details {
2712 ResourceDetails::Container(value) => value.labels(),
2713 ResourceDetails::Pod(value) => value.labels(),
2714 ResourceDetails::Network(value) => value.labels(),
2715 ResourceDetails::Volume(value) => value.labels(),
2716 ResourceDetails::Image(value) => value.labels(),
2717 ResourceDetails::Secret(value) => value.labels(),
2718 }
2719 }
2720
2721 pub(crate) fn image_repo_tags(&self) -> Option<&ObservationField<Vec<String>>> {
2722 match &self.details {
2723 ResourceDetails::Image(value) => Some(value.repo_tags()),
2724 _ => None,
2725 }
2726 }
2727
2728 pub(crate) fn image_repo_digests(&self) -> Option<&ObservationField<Vec<String>>> {
2729 match &self.details {
2730 ResourceDetails::Image(value) => Some(value.repo_digests()),
2731 _ => None,
2732 }
2733 }
2734}
2735
2736fn incomplete_field<T>(state: ResourceObservationState) -> ObservationField<T> {
2737 if state == ResourceObservationState::Malformed {
2738 ObservationField::Malformed
2739 } else {
2740 ObservationField::Unavailable
2741 }
2742}
2743
2744fn incomplete_details(kind: ResourceKind, state: ResourceObservationState) -> ResourceDetails {
2745 match kind {
2746 ResourceKind::Container => ResourceDetails::Container(ContainerObservation::new(
2747 incomplete_field(state),
2748 incomplete_field(state),
2749 incomplete_field(state),
2750 incomplete_field(state),
2751 incomplete_field(state),
2752 incomplete_field(state),
2753 incomplete_field(state),
2754 incomplete_field(state),
2755 incomplete_field(state),
2756 incomplete_field(state),
2757 incomplete_field(state),
2758 incomplete_field(state),
2759 incomplete_field(state),
2760 incomplete_field(state),
2761 incomplete_field(state),
2762 incomplete_field(state),
2763 incomplete_field(state),
2764 incomplete_field(state),
2765 incomplete_field(state),
2766 incomplete_field(state),
2767 incomplete_field(state),
2768 incomplete_field(state),
2769 incomplete_field(state),
2770 incomplete_field(state),
2771 incomplete_field(state),
2772 incomplete_field(state),
2773 )),
2774 ResourceKind::Pod => ResourceDetails::Pod(PodObservation::new(
2775 incomplete_field(state),
2776 incomplete_field(state),
2777 incomplete_field(state),
2778 incomplete_field(state),
2779 )),
2780 ResourceKind::Network => ResourceDetails::Network(NetworkObservation::new(
2781 incomplete_field(state),
2782 incomplete_field(state),
2783 incomplete_field(state),
2784 incomplete_field(state),
2785 incomplete_field(state),
2786 )),
2787 ResourceKind::Volume => ResourceDetails::Volume(VolumeObservation::new(
2788 incomplete_field(state),
2789 incomplete_field(state),
2790 incomplete_field(state),
2791 incomplete_field(state),
2792 incomplete_field(state),
2793 incomplete_field(state),
2794 )),
2795 ResourceKind::Image => ResourceDetails::Image(ImageObservation::new(ImageObservationFields {
2796 labels: incomplete_field(state),
2797 repo_tags: incomplete_field(state),
2798 repo_digests: incomplete_field(state),
2799 environment: incomplete_field(state),
2800 digest: incomplete_field(state),
2801 created: incomplete_field(state),
2802 author: incomplete_field(state),
2803 architecture: incomplete_field(state),
2804 operating_system: incomplete_field(state),
2805 manifest_type: incomplete_field(state),
2806 })),
2807 ResourceKind::Secret => ResourceDetails::Secret(SecretObservation::new(
2808 incomplete_field(state),
2809 incomplete_field(state),
2810 incomplete_field(state),
2811 incomplete_field(state),
2812 )),
2813 }
2814}
2815
2816impl fmt::Debug for ResourceObservation {
2817 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2818 formatter
2819 .debug_struct("ResourceObservation")
2820 .field("identity", self.header.identity())
2821 .field("state", &self.header.state())
2822 .field("finding_count", &self.header.findings().len())
2823 .field("unmodelled_field_count", &self.header.unmodelled_fields().len())
2824 .field("detail_kind", &self.details.kind())
2825 .finish()
2826 }
2827}