cumulus 0.0.6

AWS CloudFormation Template Generator
Documentation
use serde::Serialize;

use crate::resource::ToResource;
use crate::skip_serializing_if::SkipSerializingIf;
use crate::ValueOrRef;

use super::Affinity;
use super::BlockDeviceMapping;
use super::CpuOptions;
use super::CreditSpecification;
use super::InstanceType;

//{
//    "Type" : "AWS::EC2::Instance",
//    "Properties" : {
//        "AdditionalInfo" : String,
//        "Affinity" : String,
//        "AvailabilityZone" : String,
//        "BlockDeviceMappings" : [ BlockDeviceMapping, ... ],
//        "CpuOptions" : CpuOptions,
//        "CreditSpecification" : CreditSpecification,
//        "DisableApiTermination" : Boolean,
//        "EbsOptimized" : Boolean,
//        "ElasticGpuSpecifications" : [ ElasticGpuSpecification, ... ],
//        "ElasticInferenceAccelerators" : [ ElasticInferenceAccelerator, ... ],
//        "HostId" : String,
//        "IamInstanceProfile" : String,
//        "ImageId" : String,
//        "InstanceInitiatedShutdownBehavior" : String,
//        "InstanceType" : String,
//        "Ipv6AddressCount" : Integer,
//        "Ipv6Addresses" : [ InstanceIpv6Address, ... ],
//        "KernelId" : String,
//        "KeyName" : String,
//        "LaunchTemplate" : LaunchTemplateSpecification,
//        "LicenseSpecifications" : [ LicenseSpecification, ... ],
//        "Monitoring" : Boolean,
//        "NetworkInterfaces" : [ NetworkInterface, ... ],
//        "PlacementGroupName" : String,
//        "PrivateIpAddress" : String,
//        "RamdiskId" : String,
//        "SecurityGroupIds" : [ String, ... ],
//        "SecurityGroups" : [ String, ... ],
//        "SourceDestCheck" : Boolean,
//        "SsmAssociations" : [ SsmAssociation, ... ],
//        "SubnetId" : String,
//        "Tags" : [ Tag, ... ],
//        "Tenancy" : String,
//        "UserData" : String,
//        "Volumes" : [ Volume, ... ]
//    }
//}

#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct Instance {
    #[serde(skip)]
    name: String,
    additional_info: String,
    #[serde(skip_serializing_if = "Affinity::is_default")]
    affinity: Affinity,
    #[serde(skip_serializing_if = "String::is_empty")]
    availability_zone: String,
    block_device_mappings: Vec<BlockDeviceMapping>,
    #[serde(skip_serializing_if = "CpuOptions::is_default")]
    cpu_options: CpuOptions,
    #[serde(skip_serializing_if = "CreditSpecification::is_default")]
    credit_specification: CreditSpecification,
    disable_api_termination: bool,
    #[serde(skip_serializing_if = "bool::is_false")]
    ebs_optimized: bool,
    //        "ElasticGpuSpecifications" : [ ElasticGpuSpecification, ... ],
    //        "ElasticInferenceAccelerators" : [ ElasticInferenceAccelerator, ... ],
    //        "HostId" : String,
    //        "IamInstanceProfile" : String,
    image_id: ValueOrRef,
    //        "InstanceInitiatedShutdownBehavior" : String,
    instance_type: InstanceType,
    //        "Ipv6AddressCount" : Integer,
    //        "Ipv6Addresses" : [ InstanceIpv6Address, ... ],
    //        "KernelId" : String,
    //        "KeyName" : String,
    //        "LaunchTemplate" : LaunchTemplateSpecification,
    //        "LicenseSpecifications" : [ LicenseSpecification, ... ],
    //        "Monitoring" : Boolean,
    //        "NetworkInterfaces" : [ NetworkInterface, ... ],
    //        "PlacementGroupName" : String,
    //        "PrivateIpAddress" : String,
    //        "RamdiskId" : String,
    //        "SecurityGroupIds" : [ String, ... ],
    //        "SecurityGroups" : [ String, ... ],
    //        "SourceDestCheck" : Boolean,
    //        "SsmAssociations" : [ SsmAssociation, ... ],
    //        "SubnetId" : String,
    //        "Tags" : [ Tag, ... ],
    //        "Tenancy" : String,
    //        "UserData" : String,
    //        "Volumes" : [ Volume, ... ]
}

//impl crate::IntoResource for Instance {
//    const RESOURCE_TYPE: &'static str = "AWS::EC2::Instance";
//}

impl Instance {
    pub fn new(name: impl ToString) -> Self {
        let name = name.to_string();
        Self {
            name,
            ..Self::default()
        }
    }

    pub fn host_affinity(self) -> Self {
        let affinity = Affinity::Host;
        Self { affinity, ..self }
    }

    pub fn instance_type(self, r#type: impl AsRef<str>) -> Self {
        let instance_type =
            InstanceType::from_text(r#type.as_ref()).expect("Invalid Instance Type");
        Self {
            instance_type,
            ..self
        }
    }

    pub fn image_id(self, image: impl Into<crate::ValueOrRef>) -> Self {
        let image_id = image.into();
        Self { image_id, ..self }
    }
}

impl ToResource for Instance {
    fn name(&self) -> String {
        self.name.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn simple() {
        let template = r#"{"AdditionalInfo":"","BlockDeviceMappings":[],"DisableApiTermination":false,"ImageId":"","InstanceType":"t2.nano"}"#;
        let instance = Instance::new("instance");
        let json = dbg!(serde_json::to_string(&instance).unwrap());
        assert_eq!(json, template);
    }
}