use std::fmt;
use crate::error::Error;
pub trait Source: fmt::Debug + Send + Sync {
fn kind(&self) -> SourceKind;
fn probe(&self) -> Result<Option<Probe>, Error>;
}
impl<T: Source + ?Sized> Source for Box<T> {
fn kind(&self) -> SourceKind {
(**self).kind()
}
fn probe(&self) -> Result<Option<Probe>, Error> {
(**self).probe()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Probe {
kind: SourceKind,
value: String,
}
impl Probe {
#[must_use]
pub fn new(kind: SourceKind, value: impl Into<String>) -> Self {
Self {
kind,
value: value.into(),
}
}
#[must_use]
pub fn kind(&self) -> SourceKind {
self.kind
}
#[must_use]
pub fn value(&self) -> &str {
&self.value
}
pub(crate) fn into_parts(self) -> (SourceKind, String) {
(self.kind, self.value)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum SourceKind {
EnvOverride,
FileOverride,
Container,
Lxc,
MachineId,
DbusMachineId,
Dmi,
LinuxHostId,
IoPlatformUuid,
WindowsMachineGuid,
FreeBsdHostId,
KenvSmbios,
BsdKernHostId,
IllumosHostId,
AwsImds,
GcpMetadata,
AzureImds,
DigitalOceanMetadata,
HetznerMetadata,
OciMetadata,
OpenStackMetadata,
KubernetesPodUid,
KubernetesServiceAccount,
KubernetesDownwardApi,
Custom(&'static str),
}
macro_rules! source_kind_ids {
( $( $variant:ident => $id:literal , $desc:literal );* $(;)? ) => {
impl SourceKind {
#[must_use]
pub const fn custom(label: &'static str) -> Self {
Self::Custom(label)
}
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
$( Self::$variant => $id, )*
Self::Custom(label) => label,
}
}
#[must_use]
pub fn from_id(id: &str) -> Option<Self> {
match id {
$( $id => Some(Self::$variant), )*
_ => None,
}
}
#[must_use]
pub fn describe(self) -> &'static str {
match self {
$( Self::$variant => $desc, )*
Self::Custom(_) => "",
}
}
}
};
}
source_kind_ids! {
EnvOverride => "env-override", "environment-variable override (HOST_IDENTITY by default)";
FileOverride => "file-override", "caller-supplied file containing a host identifier";
Container => "container", "container runtime ID from /proc/self/mountinfo (Linux)";
Lxc => "lxc", "LXC/LXD container name from /proc/self/cgroup or /proc/self/mountinfo, salted with /etc/machine-id (Linux)";
MachineId => "machine-id", "/etc/machine-id (Linux)";
DbusMachineId => "dbus-machine-id", "/var/lib/dbus/machine-id (Linux)";
Dmi => "dmi", "/sys/class/dmi/id/product_uuid — SMBIOS system UUID (Linux)";
LinuxHostId => "linux-hostid", "/etc/hostid — 32-bit legacy host identifier (Linux)";
IoPlatformUuid => "io-platform-uuid", "IOPlatformUUID from IOPlatformExpertDevice (macOS)";
WindowsMachineGuid => "windows-machine-guid", "HKLM\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid (Windows)";
FreeBsdHostId => "freebsd-hostid", "/etc/hostid (FreeBSD)";
KenvSmbios => "kenv-smbios", "kenv smbios.system.uuid — SMBIOS system UUID (FreeBSD)";
BsdKernHostId => "bsd-kern-hostid", "sysctl kern.hostid (NetBSD, OpenBSD)";
IllumosHostId => "illumos-hostid", "hostid(1) (illumos, Solaris)";
AwsImds => "aws-imds", "AWS EC2 instance ID via IMDSv2";
GcpMetadata => "gcp-metadata", "GCP Compute Engine numeric instance ID via the metadata server";
AzureImds => "azure-imds", "Azure VM UUID via the Azure Instance Metadata Service";
DigitalOceanMetadata => "digital-ocean-metadata", "DigitalOcean Droplet numeric ID via the metadata service";
HetznerMetadata => "hetzner-metadata", "Hetzner Cloud numeric server ID via the metadata service";
OciMetadata => "oci-metadata", "Oracle Cloud Infrastructure instance OCID via the metadata service";
OpenStackMetadata => "openstack-metadata", "OpenStack Nova instance UUID via the metadata service";
KubernetesPodUid => "kubernetes-pod-uid", "Kubernetes pod UID derived from /proc/self/mountinfo";
KubernetesServiceAccount => "kubernetes-service-account","Kubernetes service-account namespace from the projected token volume";
KubernetesDownwardApi => "kubernetes-downward-api", "caller-supplied Kubernetes downward-API projected file";
}
impl fmt::Display for SourceKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::SourceKind;
#[test]
fn display_honors_formatter_width_and_alignment() {
let k = SourceKind::MachineId;
assert_eq!(format!("[{k:<15}]"), "[machine-id ]");
assert_eq!(format!("[{k:>15}]"), "[ machine-id]");
assert_eq!(format!("[{k:^15}]"), "[ machine-id ]");
assert_eq!(format!("[{k:-<15}]"), "[machine-id-----]");
assert_eq!(format!("[{k:.5}]"), "[machi]");
assert_eq!(format!("[{k}]"), "[machine-id]");
}
}