use crate::api::generated::machine::{
Upgrade as ProtoUpgrade, UpgradeRequest as ProtoUpgradeRequest,
UpgradeResponse as ProtoUpgradeResponse,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum UpgradeRebootMode {
#[default]
Default,
PowerCycle,
}
impl From<UpgradeRebootMode> for i32 {
fn from(mode: UpgradeRebootMode) -> Self {
match mode {
UpgradeRebootMode::Default => 0,
UpgradeRebootMode::PowerCycle => 1,
}
}
}
impl std::fmt::Display for UpgradeRebootMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UpgradeRebootMode::Default => write!(f, "default"),
UpgradeRebootMode::PowerCycle => write!(f, "powercycle"),
}
}
}
#[derive(Debug, Clone)]
pub struct UpgradeRequest {
pub image: String,
pub preserve: bool,
pub stage: bool,
pub force: bool,
pub reboot_mode: UpgradeRebootMode,
}
impl UpgradeRequest {
#[must_use]
pub fn new(image: impl Into<String>) -> Self {
Self {
image: image.into(),
preserve: false,
stage: false,
force: false,
reboot_mode: UpgradeRebootMode::Default,
}
}
#[must_use]
pub fn builder(image: impl Into<String>) -> UpgradeRequestBuilder {
UpgradeRequestBuilder::new(image)
}
}
impl From<UpgradeRequest> for ProtoUpgradeRequest {
fn from(req: UpgradeRequest) -> Self {
Self {
image: req.image,
preserve: req.preserve,
stage: req.stage,
force: req.force,
reboot_mode: req.reboot_mode.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct UpgradeRequestBuilder {
image: String,
preserve: bool,
stage: bool,
force: bool,
reboot_mode: UpgradeRebootMode,
}
impl UpgradeRequestBuilder {
#[must_use]
pub fn new(image: impl Into<String>) -> Self {
Self {
image: image.into(),
preserve: false,
stage: false,
force: false,
reboot_mode: UpgradeRebootMode::Default,
}
}
#[must_use]
pub fn preserve(mut self, preserve: bool) -> Self {
self.preserve = preserve;
self
}
#[must_use]
pub fn stage(mut self, stage: bool) -> Self {
self.stage = stage;
self
}
#[must_use]
pub fn force(mut self, force: bool) -> Self {
self.force = force;
self
}
#[must_use]
pub fn reboot_mode(mut self, mode: UpgradeRebootMode) -> Self {
self.reboot_mode = mode;
self
}
#[must_use]
pub fn build(self) -> UpgradeRequest {
UpgradeRequest {
image: self.image,
preserve: self.preserve,
stage: self.stage,
force: self.force,
reboot_mode: self.reboot_mode,
}
}
}
#[derive(Debug, Clone)]
pub struct UpgradeResult {
pub node: Option<String>,
pub ack: String,
pub actor_id: String,
}
impl From<ProtoUpgrade> for UpgradeResult {
fn from(proto: ProtoUpgrade) -> Self {
Self {
node: proto.metadata.map(|m| m.hostname),
ack: proto.ack,
actor_id: proto.actor_id,
}
}
}
#[derive(Debug, Clone)]
pub struct UpgradeResponse {
pub results: Vec<UpgradeResult>,
}
impl From<ProtoUpgradeResponse> for UpgradeResponse {
fn from(proto: ProtoUpgradeResponse) -> Self {
Self {
results: proto
.messages
.into_iter()
.map(UpgradeResult::from)
.collect(),
}
}
}
impl UpgradeResponse {
#[must_use]
pub fn is_success(&self) -> bool {
!self.results.is_empty()
}
#[must_use]
pub fn first(&self) -> Option<&UpgradeResult> {
self.results.first()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_upgrade_request_new() {
let req = UpgradeRequest::new("ghcr.io/siderolabs/installer:v1.6.0");
assert_eq!(req.image, "ghcr.io/siderolabs/installer:v1.6.0");
assert!(!req.preserve);
assert!(!req.stage);
assert!(!req.force);
assert_eq!(req.reboot_mode, UpgradeRebootMode::Default);
}
#[test]
fn test_upgrade_request_builder() {
let req = UpgradeRequest::builder("ghcr.io/siderolabs/installer:v1.6.0")
.preserve(true)
.stage(true)
.force(true)
.reboot_mode(UpgradeRebootMode::PowerCycle)
.build();
assert_eq!(req.image, "ghcr.io/siderolabs/installer:v1.6.0");
assert!(req.preserve);
assert!(req.stage);
assert!(req.force);
assert_eq!(req.reboot_mode, UpgradeRebootMode::PowerCycle);
}
#[test]
fn test_upgrade_reboot_mode() {
assert_eq!(i32::from(UpgradeRebootMode::Default), 0);
assert_eq!(i32::from(UpgradeRebootMode::PowerCycle), 1);
assert_eq!(UpgradeRebootMode::PowerCycle.to_string(), "powercycle");
}
#[test]
fn test_proto_conversion() {
let req = UpgradeRequest::builder("test:v1.0")
.stage(true)
.force(true)
.build();
let proto: ProtoUpgradeRequest = req.into();
assert_eq!(proto.image, "test:v1.0");
assert!(proto.stage);
assert!(proto.force);
}
}