diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 0aa1ebd0c..dfee6a003 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -22,8 +22,6 @@ hex = "^0.4" fn-error-context = "0.2.0" gvariant = "0.4.0" indicatif = "0.17.0" -k8s-openapi = { version = "0.20.0", features = ["v1_28", "schemars"] } -kube = { version = "0.86.0", default-features = false, features = ["client", "openssl-tls", "runtime", "derive", "openssl-tls"] } libc = "^0.2" liboverdrop = "0.1.0" once_cell = "1.9" diff --git a/lib/src/k8sapitypes.rs b/lib/src/k8sapitypes.rs new file mode 100644 index 000000000..c2b8a87a7 --- /dev/null +++ b/lib/src/k8sapitypes.rs @@ -0,0 +1,28 @@ +//! Subset of API definitions for selected Kubernetes API types. +//! We avoid dragging in all of k8s-openapi because it's *huge*. + +use std::collections::BTreeMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct Resource { + pub api_version: String, + pub kind: String, + #[serde(default)] + pub metadata: ObjectMeta, +} + +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct ObjectMeta { + #[serde(skip_serializing_if = "Option::is_none")] + pub annotations: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub labels: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub namespace: Option, +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 9e8f64cd3..a725301cb 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -33,6 +33,7 @@ mod containerenv; pub(crate) mod ignition; #[cfg(feature = "install")] mod install; +mod k8sapitypes; #[cfg(feature = "install")] pub(crate) mod mount; #[cfg(feature = "install")] diff --git a/lib/src/spec.rs b/lib/src/spec.rs index 8019a3d6f..577924e40 100644 --- a/lib/src/spec.rs +++ b/lib/src/spec.rs @@ -1,25 +1,30 @@ //! The definition for host system state. -use k8s_openapi::apimachinery::pkg::apis::meta::v1 as k8smeta; -use kube::CustomResource; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -/// Representation of a bootc host system -#[derive( - CustomResource, Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, JsonSchema, -)] -#[kube( - group = "org.containers.bootc", - version = "v1alpha1", - kind = "BootcHost", - struct = "Host", - namespaced, - status = "HostStatus", - derive = "PartialEq", - derive = "Default" -)] +use crate::k8sapitypes; + +const API_VERSION: &str = "org.containers.bootc/v1alpha1"; +const KIND: &str = "BootcHost"; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +/// The core host definition +pub struct Host { + /// Metadata + #[serde(flatten)] + pub resource: k8sapitypes::Resource, + /// The spec + #[serde(default)] + pub spec: HostSpec, + /// The status + pub status: Option, +} + +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] +/// The host specification pub struct HostSpec { /// The host image pub image: Option, @@ -58,7 +63,7 @@ pub struct ImageStatus { /// The version string, if any pub version: Option, /// The build timestamp, if any - pub timestamp: Option, + pub timestamp: Option>, /// The digest of the fetched image (e.g. sha256:a0...); pub image_digest: String, } @@ -102,6 +107,25 @@ pub struct HostStatus { pub is_container: bool, } +impl Host { + /// Create a new host + pub fn new(name: &str, spec: HostSpec) -> Self { + let metadata = k8sapitypes::ObjectMeta { + name: Some(name.to_owned()), + ..Default::default() + }; + Self { + resource: k8sapitypes::Resource { + api_version: API_VERSION.to_owned(), + kind: KIND.to_owned(), + metadata, + }, + spec, + status: None, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/lib/src/status.rs b/lib/src/status.rs index e0a342a65..b74721087 100644 --- a/lib/src/status.rs +++ b/lib/src/status.rs @@ -3,7 +3,6 @@ use std::collections::VecDeque; use crate::spec::{BootEntry, Host, HostSpec, HostStatus, ImageStatus}; use crate::spec::{ImageReference, ImageSignature}; use anyhow::{Context, Result}; -use k8s_openapi::apimachinery::pkg::apis::meta::v1 as k8smeta; use ostree::glib; use ostree_container::OstreeImageReference; use ostree_ext::container as ostree_container; @@ -89,9 +88,9 @@ pub(crate) struct Deployments { pub(crate) other: VecDeque, } -fn try_deserialize_timestamp(t: &str) -> Option { +fn try_deserialize_timestamp(t: &str) -> Option> { match chrono::DateTime::parse_from_rfc3339(t).context("Parsing timestamp") { - Ok(t) => Some(k8smeta::Time(t.with_timezone(&chrono::Utc))), + Ok(t) => Some(t.into()), Err(e) => { tracing::warn!("Invalid timestamp in image: {:#}", e); None