use serde::Serialize;
use crate::skip_serializing_if::SkipSerializingIf;
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct BlockDeviceMapping {
device_name: String,
#[serde(flatten)]
device: BlockDevice,
}
impl BlockDeviceMapping {
pub fn ephemeral(n: u8, name: impl Into<String>) -> Self {
let device_name = name.into();
let device = BlockDevice::ephemeral(n);
Self {
device_name,
device,
}
}
pub fn ebs(name: impl Into<String>, size: u64) -> Self {
let device_name = name.into();
let device = BlockDevice::ebs(size);
Self {
device_name,
device,
}
}
pub fn with_ebs(name: impl Into<String>, ebs: Ebs) -> Self {
let device_name = name.into();
let device = BlockDevice::with_ebs(ebs);
Self {
device_name,
device,
}
}
pub fn no_device(name: impl Into<String>) -> Self {
let device_name = name.into();
let device = BlockDevice::no_device();
Self {
device_name,
device,
}
}
}
#[derive(Clone, Debug, Serialize)]
struct NoDevice {}
#[derive(Clone, Debug, Serialize)]
enum BlockDevice {
Ebs(Ebs),
VirtualName(String),
NoDevice(NoDevice),
}
impl BlockDevice {
fn ephemeral(n: u8) -> Self {
let name = format!("ephemeral{}", n);
Self::VirtualName(name)
}
fn ebs(size: u64) -> Self {
let ebs = Ebs::new(size);
Self::Ebs(ebs)
}
fn with_ebs(ebs: Ebs) -> Self {
Self::Ebs(ebs)
}
fn no_device() -> Self {
Self::NoDevice(NoDevice {})
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct Ebs {
#[serde(skip_serializing_if = "bool::is_true")]
delete_on_termination: bool,
#[serde(skip_serializing_if = "bool::is_false")]
encrypted: bool,
#[serde(skip_serializing_if = "u64::is_zero")]
iops: u64,
#[serde(skip_serializing_if = "String::is_empty")]
kms_key_id: String,
#[serde(skip_serializing_if = "String::is_empty")]
snapshot_id: String,
volume_size: u64,
#[serde(skip_serializing_if = "VolumeType::is_gp2")]
volume_type: VolumeType,
}
impl Default for Ebs {
fn default() -> Self {
Self {
delete_on_termination: true,
encrypted: false,
iops: 0,
kms_key_id: String::new(),
snapshot_id: String::new(),
volume_size: 0,
volume_type: VolumeType::default(),
}
}
}
impl Ebs {
pub fn new(size: u64) -> Self {
Self {
volume_size: size,
..Self::default()
}
}
pub fn standard(self) -> Self {
let volume_type = VolumeType::Standard;
Self {
volume_type,
..self
}
}
pub fn io1(self, iops: u64) -> Self {
let volume_type = VolumeType::Io1;
Self {
iops,
volume_type,
..self
}
}
pub fn sc1(self) -> Self {
let volume_type = VolumeType::Sc1;
Self {
volume_type,
..self
}
}
pub fn st1(self) -> Self {
let volume_type = VolumeType::St1;
Self {
volume_type,
..self
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
enum VolumeType {
Gp2,
Io1,
Sc1,
St1,
Standard,
}
impl Default for VolumeType {
fn default() -> Self {
Self::Gp2
}
}
impl VolumeType {
fn is_gp2(&self) -> bool {
*self == Self::Gp2
}
}
#[cfg(test)]
mod tests {
use super::*;
use inspector::ResultInspector;
#[test]
fn ephemeral() {
let ephemeral = r#"{"DeviceName":"/dev/sdc","VirtualName":"ephemeral3"}"#;
let device = BlockDeviceMapping::ephemeral(3, "/dev/sdc");
let json = serde_json::to_string(&device)
.inspect(|text| println!("{}", text))
.unwrap();
assert_eq!(json, ephemeral);
}
#[test]
fn ebs() {
let ebs = r#"{"DeviceName":"/dev/sdc","Ebs":{"VolumeSize":100}}"#;
let device = BlockDeviceMapping::ebs("/dev/sdc", 100);
let json = serde_json::to_string(&device)
.inspect(|text| println!("{}", text))
.unwrap();
assert_eq!(json, ebs);
}
#[test]
fn no_device() {
let no_device = r#"{"DeviceName":"/dev/sdc","NoDevice":{}}"#;
let device = BlockDeviceMapping::no_device("/dev/sdc");
let json = serde_json::to_string(&device)
.inspect(|text| println!("{}", text))
.unwrap();
assert_eq!(json, no_device);
}
}