use serde::{Deserialize, Serialize};
use super::{InternalVerb, VerbCategory};
pub struct FloatingIpAssign;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct FloatingIpAssignInput {
pub ip_id: String,
pub attach_id: String,
pub zone: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct FloatingIpAssignOutput {
pub reassigned: bool,
pub attached_to: String,
}
impl InternalVerb for FloatingIpAssign {
type Input = FloatingIpAssignInput;
type Output = FloatingIpAssignOutput;
const ID: &'static str = "floating_ip.assign";
const CATEGORY: VerbCategory = VerbCategory::FloatingIp;
}
pub struct FloatingIpStatus;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct FloatingIpStatusInput {
pub ip_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct FloatingIpStatusOutput {
pub zone: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub attached_to: Option<String>,
}
impl InternalVerb for FloatingIpStatus {
type Input = FloatingIpStatusInput;
type Output = FloatingIpStatusOutput;
const ID: &'static str = "floating_ip.status";
const CATEGORY: VerbCategory = VerbCategory::FloatingIp;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verb_ids_match_canonical_namespace() {
assert_eq!(FloatingIpAssign::ID, "floating_ip.assign");
assert_eq!(FloatingIpStatus::ID, "floating_ip.status");
for id in [FloatingIpAssign::ID, FloatingIpStatus::ID] {
assert!(id.starts_with("floating_ip."), "{id}");
}
}
#[test]
fn verbs_are_under_floating_ip_category() {
assert_eq!(FloatingIpAssign::CATEGORY, VerbCategory::FloatingIp);
assert_eq!(FloatingIpStatus::CATEGORY, VerbCategory::FloatingIp);
}
#[test]
fn assign_input_round_trips() {
let input = FloatingIpAssignInput {
ip_id: "42".into(),
attach_id: "123".into(),
zone: "eu-central".into(),
};
let wire = serde_json::to_string(&input).unwrap();
let back: FloatingIpAssignInput = serde_json::from_str(&wire).unwrap();
assert_eq!(back.ip_id, "42");
assert_eq!(back.attach_id, "123");
assert_eq!(back.zone, "eu-central");
}
#[test]
fn assign_output_round_trips() {
let out = FloatingIpAssignOutput {
reassigned: true,
attached_to: "123".into(),
};
let wire = serde_json::to_value(&out).unwrap();
assert_eq!(
wire,
serde_json::json!({ "reassigned": true, "attached_to": "123" })
);
}
#[test]
fn status_output_omits_attached_to_when_absent() {
let out = FloatingIpStatusOutput {
zone: "us-east".into(),
attached_to: None,
};
let wire = serde_json::to_value(&out).unwrap();
assert_eq!(wire, serde_json::json!({ "zone": "us-east" }));
}
#[test]
fn status_output_includes_attached_to_when_present() {
let out = FloatingIpStatusOutput {
zone: "us-east".into(),
attached_to: Some("123".into()),
};
let wire = serde_json::to_value(&out).unwrap();
assert_eq!(
wire,
serde_json::json!({ "zone": "us-east", "attached_to": "123" })
);
}
#[cfg(feature = "json-schema")]
#[test]
fn verbs_emit_schemas_via_for_verb() {
use super::super::VerbDescriptor;
let assign = VerbDescriptor::for_verb::<FloatingIpAssign>();
assert_eq!(assign.id, "floating_ip.assign");
assert!(assign.input_schema.to_string().contains("attach_id"));
let status = VerbDescriptor::for_verb::<FloatingIpStatus>();
assert_eq!(status.id, "floating_ip.status");
assert!(status.output_schema.to_string().contains("zone"));
}
}