four 0.0.13

framework for creating AWS CloudFormation template
Documentation
use crate::{
    core::{
        convert::WillBe,
        function::{HaveAtt, RefInner, Referenced},
        service::IAM,
        Arn, LogicalId,
    },
    iam::{
        action::Action,
        property::{
            action, policy_document::PolicyDocument, principal::Principal, statement::Statement,
        },
        AWSManagedPolicy, RoleArn, RoleId, RoleName,
    },
    ManagedResource,
};

#[derive(ManagedResource, Clone)]
#[resource_type = "AWS::IAM::Role"]
pub struct Role {
    logical_id: LogicalId,
    assume_role_policy_document: PolicyDocument,
    description: Option<String>,
    role_name: Option<WillBe<RoleName>>,
    managed_policy_arns: Option<Vec<AWSManagedPolicy>>,
}

impl Role {
    pub fn assume_role(id: LogicalId, principal: Principal) -> Self {
        let actions: Vec<Box<dyn Action>> = vec![Box::new(action::sts::AssumeRole)];
        let statement = Statement::allow_actions(actions)
            .principal(principal)
            .build()
            .expect("valid statement");
        let policy_document = PolicyDocument::latest(vec![statement]);

        Self::new(id, policy_document)
    }
}

impl Referenced for Role {
    type To = WillBe<RoleName>;

    fn referenced(&self) -> RefInner {
        RefInner::Id(self.logical_id.clone())
    }
}

impl HaveAtt<RoleArn> for Role {
    const KEY: &'static str = "Arn";
}
impl HaveAtt<RoleId> for Role {
    const KEY: &'static str = "RoleId";
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::iam::property::{action, principal::ServicePrincipal};

    #[test]
    fn test_role1() {
        let role_id = LogicalId::try_from("role-id").unwrap();
        let actions: Vec<Box<dyn Action>> = vec![Box::new(action::sts::AssumeRole)];
        let statement = Statement::allow_actions(actions)
            .principal(Principal::from(ServicePrincipal::Lambda))
            .build()
            .expect("");
        let assume_role_policy_document = PolicyDocument::latest(vec![statement]);
        let role = Role::new(role_id, assume_role_policy_document);
        let mut rhs = r#"{
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": [ "sts:AssumeRole" ],
                            "Principal": {
                                "Service": [ "lambda.amazonaws.com" ]
                            }
                        }
                    ]
                }
            }}"#
        .to_string();
        rhs.retain(|c| c != ' ' && c != '\n');
        assert_eq!(serde_json::to_string(&role).unwrap(), rhs);
    }
}