use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
use crate::membership::NodeRole;
use crate::NodeId;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RoleAssignment {
Promote {
node_id: NodeId,
roles: BTreeSet<NodeRole>,
reason: Reason,
},
Demote {
node_id: NodeId,
roles_relinquished: BTreeSet<NodeRole>,
reason: Reason,
},
Quarantine { node_id: NodeId, reason: Reason },
Restore { node_id: NodeId },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Reason {
ReplacingFailed,
ScalingUp,
ScalingDown,
HealthDegraded,
Operator,
Rebalance,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn role_assignment_serializes_tagged() {
let cmd = RoleAssignment::Promote {
node_id: NodeId::new([1; 32]),
roles: [NodeRole::ApiServer].into_iter().collect(),
reason: Reason::ReplacingFailed,
};
let json = serde_json::to_string(&cmd).unwrap();
assert!(json.contains("\"kind\":\"promote\""));
assert!(json.contains("\"reason\":\"replacing_failed\""));
assert!(json.contains("\"api_server\""));
let back: RoleAssignment = serde_json::from_str(&json).unwrap();
assert_eq!(back, cmd);
}
#[test]
fn every_variant_round_trips() {
let nid = NodeId::new([7; 32]);
let cases: Vec<RoleAssignment> = vec![
RoleAssignment::Promote {
node_id: nid,
roles: [NodeRole::Worker].into_iter().collect(),
reason: Reason::ScalingUp,
},
RoleAssignment::Demote {
node_id: nid,
roles_relinquished: [NodeRole::Etcd].into_iter().collect(),
reason: Reason::Rebalance,
},
RoleAssignment::Quarantine {
node_id: nid,
reason: Reason::HealthDegraded,
},
RoleAssignment::Restore { node_id: nid },
];
for cmd in cases {
let json = serde_json::to_string(&cmd).unwrap();
let back: RoleAssignment = serde_json::from_str(&json).unwrap();
assert_eq!(back, cmd);
}
}
}