use super::super::common;
use super::super::session::Session;
use super::super::Result;
use serde::ser::{Serialize, SerializeStruct, Serializer};
protocol_enum! {
#[doc = "A destination type for a block device."]
enum BlockDeviceDestinationType {
#[doc = "Local ephemeral device."]
Local = "local",
#[doc = "Attached remote volume."]
Volume = "volume"
}
}
#[derive(Clone, Debug)]
pub enum BlockDeviceSource {
Image(common::ImageRef),
Volume(common::VolumeRef),
Snapshot(common::SnapshotRef),
}
impl BlockDeviceSource {
#[inline]
fn source_type(&self) -> &'static str {
match self {
BlockDeviceSource::Image(..) => "image",
BlockDeviceSource::Volume(..) => "volume",
BlockDeviceSource::Snapshot(..) => "snapshot",
}
}
#[inline]
fn uuid(&self) -> &str {
match self {
BlockDeviceSource::Image(image) => image.as_ref(),
BlockDeviceSource::Volume(volume) => volume.as_ref(),
BlockDeviceSource::Snapshot(snapshot) => snapshot.as_ref(),
}
}
async fn into_verified(self, session: &Session) -> Result<Self> {
Ok(match self {
BlockDeviceSource::Image(inner) => {
BlockDeviceSource::Image(inner.into_verified(session).await?)
}
BlockDeviceSource::Volume(inner) => {
BlockDeviceSource::Volume(inner.into_verified(session).await?)
}
BlockDeviceSource::Snapshot(inner) => {
BlockDeviceSource::Snapshot(inner.into_verified(session).await?)
}
})
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct BlockDevice {
pub boot_index: Option<u16>,
pub delete_on_termination: bool,
pub destination_type: BlockDeviceDestinationType,
pub guest_format: Option<String>,
pub size_gib: Option<u32>,
pub source: Option<BlockDeviceSource>,
}
impl BlockDevice {
pub fn new(
source: BlockDeviceSource,
destination_type: BlockDeviceDestinationType,
) -> BlockDevice {
BlockDevice {
boot_index: None,
delete_on_termination: false,
destination_type,
guest_format: None,
size_gib: None,
source: Some(source),
}
}
pub fn swap(size_gib: u32) -> BlockDevice {
BlockDevice {
boot_index: None,
delete_on_termination: false,
destination_type: BlockDeviceDestinationType::Local,
guest_format: Some("swap".into()),
size_gib: Some(size_gib),
source: None,
}
}
pub fn from_image<I>(image: I) -> BlockDevice
where
I: Into<common::ImageRef>,
{
BlockDevice {
boot_index: Some(0),
delete_on_termination: false,
destination_type: BlockDeviceDestinationType::Local,
guest_format: None,
size_gib: None,
source: Some(BlockDeviceSource::Image(image.into())),
}
}
pub fn from_volume<V>(volume: V, is_boot_device: bool) -> BlockDevice
where
V: Into<common::VolumeRef>,
{
BlockDevice {
boot_index: if is_boot_device { Some(0) } else { None },
delete_on_termination: false,
destination_type: BlockDeviceDestinationType::Volume,
guest_format: None,
size_gib: None,
source: Some(BlockDeviceSource::Volume(volume.into())),
}
}
pub fn from_empty_volume(size_gib: u32) -> BlockDevice {
BlockDevice {
boot_index: None,
delete_on_termination: false,
destination_type: BlockDeviceDestinationType::Volume,
guest_format: None,
size_gib: Some(size_gib),
source: None,
}
}
pub fn from_new_volume<I>(image: I, size_gib: u32, is_boot_device: bool) -> BlockDevice
where
I: Into<common::ImageRef>,
{
BlockDevice {
boot_index: if is_boot_device { Some(0) } else { None },
delete_on_termination: false,
destination_type: BlockDeviceDestinationType::Volume,
guest_format: None,
size_gib: Some(size_gib),
source: Some(BlockDeviceSource::Image(image.into())),
}
}
#[inline]
fn non_null_field_count(&self) -> usize {
let mut count = 4;
if self.source.is_some() {
count += 1;
}
if self.guest_format.is_some() {
count += 1;
}
if self.size_gib.is_some() {
count += 1
}
count
}
pub(crate) async fn into_verified(self, session: &Session) -> Result<Self> {
Ok(if let Some(source) = self.source {
BlockDevice {
source: Some(source.into_verified(session).await?),
..self
}
} else {
self
})
}
}
impl Serialize for BlockDevice {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut bd = serializer.serialize_struct("BlockDevice", self.non_null_field_count())?;
bd.serialize_field("boot_index", &self.boot_index)?;
bd.serialize_field("delete_on_termination", &self.delete_on_termination)?;
bd.serialize_field("destination_type", &self.destination_type)?;
if let Some(ref guest_format) = self.guest_format {
bd.serialize_field("guest_format", guest_format)?;
}
if let Some(ref source) = self.source {
bd.serialize_field("source_type", source.source_type())?;
bd.serialize_field("uuid", source.uuid())?;
} else {
bd.serialize_field("source_type", "blank")?;
}
if let Some(volume_size) = self.size_gib {
bd.serialize_field("volume_size", &volume_size)?;
}
bd.end()
}
}