use std::{error::Error, fmt};
const NATIVE_FIELD_COVERAGE_UNAVAILABLE_MESSAGE: &str =
"the native-field coverage catalogue is malformed or incomplete";
const IMAGE_PORTABILITY_MANUAL_MESSAGE: &str =
"the image source needs a manual portability decision before it can be acquired";
const VOLUME_OWNER_DEFAULT_AMBIGUOUS_MESSAGE: &str =
"an omitted native volume owner ID may mean Podman's canonical zero default";
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum DiagnosticCode {
InvalidConnection,
TransportUnavailable,
InvalidTransportMessage,
InvalidVersion,
IncompatibleTargetProfile,
CatalogueUnavailable,
ProbeHttpStatus,
ProbeHeader,
ProbeJson,
ProbeShape,
ProbeComponent,
ObservedCompatibility,
InventoryHttpStatus,
InventoryJson,
InventoryShape,
ResourceUnavailable,
ResourceMalformed,
SecretPayloadDiscarded,
EnvironmentMalformed,
RelationshipConflict,
UnknownFieldOverflow,
VersionInapplicableField,
NativeFieldUnsupported,
UnresolvedRelationship,
PodMembershipConflict,
InventoryEvidenceUnavailable,
InvalidDiscoveryRequest,
SelectorUnresolved,
SelectorAmbiguous,
AdvisoryLabelIncomplete,
AdvisoryLabelConflict,
RelationshipAmbiguous,
BoundaryOverrideUnused,
InvalidDeploymentIntent,
DeploymentDuplicateResource,
DeploymentConflictingResource,
DeploymentUnresolvedPrerequisite,
DeploymentUnsupportedCombination,
DeploymentCycle,
SensitivePayloadEmbedded,
InvalidImageReference,
InvalidExternalPrecondition,
DeploymentPodMembership,
SamePodStartupDependency,
RenderingTargetMismatch,
RenderingUnsupported,
NativeFieldCoverageUnavailable,
ImagePortabilityManual,
VolumeOwnerDefaultAmbiguous,
CreationEvidenceConflict,
}
impl DiagnosticCode {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::InvalidConnection => "PLN0001",
Self::TransportUnavailable => "PLN0002",
Self::InvalidTransportMessage => "PLN0003",
Self::InvalidVersion => "PLN0004",
Self::IncompatibleTargetProfile => "PLN0005",
Self::CatalogueUnavailable => "PLN0006",
Self::ProbeHttpStatus => "PLN0007",
Self::ProbeHeader => "PLN0008",
Self::ProbeJson => "PLN0009",
Self::ProbeShape => "PLN0010",
Self::ProbeComponent => "PLN0011",
Self::ObservedCompatibility => "PLN0012",
Self::InventoryHttpStatus => "PLN0013",
Self::InventoryJson => "PLN0014",
Self::InventoryShape => "PLN0015",
Self::ResourceUnavailable => "PLN0016",
Self::ResourceMalformed => "PLN0017",
Self::SecretPayloadDiscarded => "PLN0018",
Self::EnvironmentMalformed => "PLN0019",
Self::RelationshipConflict => "PLN0020",
Self::UnknownFieldOverflow => "PLN0021",
Self::VersionInapplicableField => "PLN0022",
Self::NativeFieldUnsupported => "PLN0023",
Self::UnresolvedRelationship => "PLN0024",
Self::PodMembershipConflict => "PLN0025",
Self::InventoryEvidenceUnavailable => "PLN0026",
Self::InvalidDiscoveryRequest => "PLN0027",
Self::SelectorUnresolved => "PLN0028",
Self::SelectorAmbiguous => "PLN0029",
Self::AdvisoryLabelIncomplete => "PLN0030",
Self::AdvisoryLabelConflict => "PLN0031",
Self::RelationshipAmbiguous => "PLN0032",
Self::BoundaryOverrideUnused => "PLN0033",
Self::InvalidDeploymentIntent => "PLN0034",
Self::DeploymentDuplicateResource => "PLN0035",
Self::DeploymentConflictingResource => "PLN0036",
Self::DeploymentUnresolvedPrerequisite => "PLN0037",
Self::DeploymentUnsupportedCombination => "PLN0038",
Self::DeploymentCycle => "PLN0039",
Self::SensitivePayloadEmbedded => "PLN0040",
Self::InvalidImageReference => "PLN0041",
Self::InvalidExternalPrecondition => "PLN0042",
Self::DeploymentPodMembership => "PLN0043",
Self::SamePodStartupDependency => "PLN0044",
Self::RenderingTargetMismatch => "PLN0045",
Self::RenderingUnsupported => "PLN0046",
Self::NativeFieldCoverageUnavailable => "PLN0047",
Self::ImagePortabilityManual => "PLN0048",
Self::VolumeOwnerDefaultAmbiguous => "PLN0049",
Self::CreationEvidenceConflict => "PLN0050",
}
}
}
impl fmt::Display for DiagnosticCode {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Diagnostic {
code: DiagnosticCode,
message: &'static str,
}
impl Diagnostic {
#[must_use]
pub const fn new(code: DiagnosticCode) -> Self {
Self {
code,
message: match code {
DiagnosticCode::InvalidConnection => "the explicit Podman connection is invalid",
DiagnosticCode::TransportUnavailable => "the selected Podman transport is unavailable",
DiagnosticCode::InvalidTransportMessage => {
"the Libpod transport message is outside supported safety bounds"
}
DiagnosticCode::InvalidVersion => "the Podman or Libpod API version is invalid",
DiagnosticCode::IncompatibleTargetProfile => {
"the requested Podman target profile is not supported by reviewed evidence"
}
DiagnosticCode::CatalogueUnavailable => "the embedded Podman compatibility catalogue is unavailable",
DiagnosticCode::ProbeHttpStatus => "the Libpod probe received an unexpected HTTP status",
DiagnosticCode::ProbeHeader => "the Libpod probe response header is invalid",
DiagnosticCode::ProbeJson => "the Libpod probe response JSON is invalid or exceeds its safety bound",
DiagnosticCode::ProbeShape => "the Libpod probe response has an unsupported JSON shape",
DiagnosticCode::ProbeComponent => {
"the Libpod probe response does not identify one valid Podman Engine component"
}
DiagnosticCode::ObservedCompatibility => {
"the observed Podman engine and Libpod API versions are outside reviewed evidence"
}
DiagnosticCode::InventoryHttpStatus => "a Libpod inventory request received an unexpected HTTP status",
DiagnosticCode::InventoryJson => "a Libpod inventory response is invalid or exceeds its safety bound",
DiagnosticCode::InventoryShape => "a Libpod inventory response has an unsupported JSON shape",
DiagnosticCode::ResourceUnavailable => {
"a listed Podman resource was unavailable during non-atomic inspection"
}
DiagnosticCode::ResourceMalformed => "a Podman resource response is malformed",
DiagnosticCode::SecretPayloadDiscarded => {
"unexpected secret payload material was discarded from metadata inspection"
}
DiagnosticCode::EnvironmentMalformed => "a Podman runtime environment entry is malformed",
DiagnosticCode::RelationshipConflict => "a Podman resource contains conflicting relationship evidence",
DiagnosticCode::UnknownFieldOverflow => "unknown Podman field metadata exceeded a safe retention limit",
DiagnosticCode::VersionInapplicableField => {
"a Podman field is inapplicable for the observed Libpod API version"
}
DiagnosticCode::NativeFieldUnsupported => "a Podman native field is retained as unsupported metadata",
DiagnosticCode::UnresolvedRelationship => "a Podman native relationship could not be resolved",
DiagnosticCode::PodMembershipConflict => "Podman pod and container membership evidence disagrees",
DiagnosticCode::InventoryEvidenceUnavailable => {
"the observed Podman version has no matching immutable inventory evidence"
}
DiagnosticCode::InvalidDiscoveryRequest => "the resource-discovery request is invalid",
DiagnosticCode::SelectorUnresolved => "a requested resource selector did not match inventory",
DiagnosticCode::SelectorAmbiguous => "a requested resource selector matched multiple inventory records",
DiagnosticCode::AdvisoryLabelIncomplete => {
"Compose ownership labels are incomplete or empty and cannot group resources"
}
DiagnosticCode::AdvisoryLabelConflict => {
"Docker and Podman Compose ownership labels disagree and cannot group resources"
}
DiagnosticCode::RelationshipAmbiguous => {
"a Podman native relationship reference matched more than one resource"
}
DiagnosticCode::BoundaryOverrideUnused => {
"a network-boundary override did not cross a selected dependency boundary"
}
DiagnosticCode::InvalidDeploymentIntent => "the typed Podman deployment intent is invalid",
DiagnosticCode::DeploymentDuplicateResource => {
"a deployment resource identity or prerequisite is duplicated"
}
DiagnosticCode::DeploymentConflictingResource => {
"target-side declarations conflict for one resource identity"
}
DiagnosticCode::DeploymentUnresolvedPrerequisite => {
"a deployment prerequisite is not declared by the intent"
}
DiagnosticCode::DeploymentUnsupportedCombination => {
"a deployment intent uses an unsupported semantic combination"
}
DiagnosticCode::DeploymentCycle => "deployment operations contain a dependency cycle",
DiagnosticCode::SensitivePayloadEmbedded => "a deployment plan cannot embed sensitive payload material",
DiagnosticCode::InvalidImageReference => {
"an image source is not a strict supported Podman image reference"
}
DiagnosticCode::InvalidExternalPrecondition => "an external deployment precondition is invalid",
DiagnosticCode::DeploymentPodMembership => {
"explicit target-side pod membership is incomplete or conflicting"
}
DiagnosticCode::SamePodStartupDependency => {
"a startup dependency cannot order containers within one Podman pod"
}
DiagnosticCode::RenderingTargetMismatch => {
"the selected Libpod API version lacks exact renderer evidence for the target engine"
}
DiagnosticCode::RenderingUnsupported => "a semantic operation has no reviewed renderer representation",
DiagnosticCode::NativeFieldCoverageUnavailable => NATIVE_FIELD_COVERAGE_UNAVAILABLE_MESSAGE,
DiagnosticCode::ImagePortabilityManual => IMAGE_PORTABILITY_MANUAL_MESSAGE,
DiagnosticCode::VolumeOwnerDefaultAmbiguous => VOLUME_OWNER_DEFAULT_AMBIGUOUS_MESSAGE,
DiagnosticCode::CreationEvidenceConflict => {
"bounded creation-command evidence disagrees with typed inspect evidence"
}
},
}
}
#[must_use]
pub const fn code(&self) -> DiagnosticCode {
self.code
}
#[must_use]
pub const fn message(&self) -> &'static str {
self.message
}
}
impl fmt::Display for Diagnostic {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}: {}", self.code, self.message)
}
}
impl Error for Diagnostic {}
pub type PodmanLensResult<T> = Result<T, Diagnostic>;