cloudformatious 0.5.0

Extension traits for rusoto_cloudformation
Documentation
//! Types representing CloudFormation stack events.
#![allow(clippy::module_name_repetitions)]

use aws_smithy_types_convert::date_time::DateTimeExt;
use chrono::{DateTime, Utc};

use crate::{status_reason::StatusReason, ResourceStatus, StackStatus, Status};

/// A stack event from the `DescribeStackEvents` API.
///
/// Stack events are represented as an enum because the API reports both events for the stack and
/// events for the resources in the stack, but these can have different sets of statuses.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum StackEvent {
    /// An event for the stack itself.
    Stack {
        /// Current status of the stack.
        resource_status: StackStatus,

        /// The details of the event.
        details: StackEventDetails,
    },
    Resource {
        /// Current status of the resource.
        resource_status: ResourceStatus,

        /// The details of the event.
        details: StackEventDetails,
    },
}

impl StackEvent {
    /// Get the resource status of the event.
    ///
    /// This returns a trait object. You can match on `self` if you need the specific status type.
    #[must_use]
    pub fn resource_status(&self) -> &dyn Status {
        match self {
            Self::Stack {
                resource_status, ..
            } => resource_status,
            Self::Resource {
                resource_status, ..
            } => resource_status,
        }
    }

    /// Get the details of the event.
    #[must_use]
    pub fn details(&self) -> &StackEventDetails {
        match self {
            Self::Stack { details, .. } | Self::Resource { details, .. } => details,
        }
    }

    /// Get the token passed to the operation that generated this event.
    ///
    /// All events triggerd by a given stack operation are assigne dthe same client request token,
    /// you can use to track operations. For example, if you execute a `CreateStack` operation with
    /// the token `token1`, then all the `StackEvents` generated by that operation will have
    /// `ClientRequestToken` set as `token1`.
    ///
    /// In the console, stack operations display the client request token on the Events tab. Stack
    /// operations that are initiated from the console use the token format
    /// *Console-StackOperation-ID*, which helps you easily identify the stack operation. For
    /// example, if you create a stack using the console, each stack event would be assigned the
    /// same token in the following format:
    /// `Console-CreateStack-7f59c3cf-00d2-40c7-b2ff-e75db0987002`.
    #[must_use]
    pub fn client_request_token(&self) -> Option<&str> {
        self.details().client_request_token.as_deref()
    }

    /// Get the unique ID of this event.
    #[must_use]
    pub fn event_id(&self) -> &str {
        self.details().event_id.as_str()
    }

    /// Get the logical name of the resource specified in the template.
    #[must_use]
    pub fn logical_resource_id(&self) -> &str {
        self.details().logical_resource_id.as_str()
    }

    /// Get the name of unique identifier associated with the physical instance of the resource.
    ///
    /// This is unset when a physical resource does not exist, e.g. when creation is still in
    /// progress or has failed.
    #[must_use]
    pub fn physical_resource_id(&self) -> Option<&str> {
        self.details().physical_resource_id.as_deref()
    }

    /// Get the success/failure message associated with the resource.
    #[must_use]
    pub fn resource_status_reason(&self) -> Option<&str> {
        self.details().resource_status_reason.as_deref()
    }

    /// Get the type of resource.
    #[must_use]
    pub fn resource_type(&self) -> &str {
        self.details().resource_type.as_str()
    }

    /// Get the unique ID of the instance of the stack.
    #[must_use]
    pub fn stack_id(&self) -> &str {
        self.details().stack_id.as_str()
    }

    /// Get the name associated with the stack.
    #[must_use]
    pub fn stack_name(&self) -> &str {
        self.details().stack_name.as_str()
    }

    /// Get the time the status was updated.
    #[must_use]
    pub fn timestamp(&self) -> &DateTime<Utc> {
        &self.details().timestamp
    }

    /// Indicates whether or not an event is terminal.
    ///
    /// A terminal event is the last one that will occur during the current stack operation. By
    /// definition, the terminal event is an event for the stack itself with a terminal
    /// [`StackStatus`].
    #[must_use]
    pub fn is_terminal(&self) -> bool {
        if let Self::Stack {
            resource_status, ..
        } = self
        {
            resource_status.is_settled()
        } else {
            false
        }
    }

    pub(crate) fn from_sdk(event: aws_sdk_cloudformation::model::StackEvent) -> Self {
        let is_stack = event.physical_resource_id.as_deref() == event.stack_id.as_deref();
        let resource_status = event
            .resource_status
            .expect("StackEvent without resource_status");
        let details = StackEventDetails {
            client_request_token: event.client_request_token,
            event_id: event.event_id.expect("StackEvent without event_id"),
            logical_resource_id: event
                .logical_resource_id
                .expect("StackEvent without logical_resource_id"),
            physical_resource_id: event.physical_resource_id,
            resource_status_reason: event.resource_status_reason,
            resource_type: event
                .resource_type
                .expect("StackEvent without resource_type"),
            stack_id: event.stack_id.expect("StackEvent without stack_id"),
            stack_name: event.stack_name.expect("StackEvent without stack_name"),
            timestamp: event
                .timestamp
                .expect("StackEvent without timestamp")
                .to_chrono_utc(),
        };
        if is_stack {
            Self::Stack {
                resource_status: resource_status
                    .as_str()
                    .parse()
                    .expect("invalid stack status"),
                details,
            }
        } else {
            Self::Resource {
                resource_status: resource_status
                    .as_str()
                    .parse()
                    .expect("invalid resource status"),
                details,
            }
        }
    }
}

/// Event details from the `DescribeStackEvents` API that are common for stack and resource events.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StackEventDetails {
    /// The token passed to the operation that generated this event.
    ///
    /// All events triggerd by a given stack operation are assigne dthe same client request token,
    /// you can use to track operations. For example, if you execute a `CreateStack` operation with
    /// the token `token1`, then all the `StackEvents` generated by that operation will have
    /// `ClientRequestToken` set as `token1`.
    ///
    /// In the console, stack operations display the client request token on the Events tab. Stack
    /// operations that are initiated from the console use the token format
    /// *Console-StackOperation-ID*, which helps you easily identify the stack operation. For
    /// example, if you create a stack using the console, each stack event would be assigned the
    /// same token in the following format:
    /// `Console-CreateStack-7f59c3cf-00d2-40c7-b2ff-e75db0987002`.
    pub client_request_token: Option<String>,

    /// The unique ID of this event.
    pub event_id: String,

    /// The logical name of the resource specified in the template.
    pub logical_resource_id: String,

    /// The name or unique identifier associated with the physical instance of the resource.
    ///
    /// This is unset when a physical resource does not exist, e.g. when creation is still in
    /// progress or has failed.
    pub physical_resource_id: Option<String>,

    /// Success/failure message associated with the resource.
    pub resource_status_reason: Option<String>,

    /// Type of resource.
    pub resource_type: String,

    /// The unique ID of the instance of the stack.
    pub stack_id: String,

    /// The name associated with the stack.
    pub stack_name: String,

    /// Time the status was updated.
    pub timestamp: DateTime<Utc>,
}

impl StackEventDetails {
    /// Get the token passed to the operation that generated this event.
    ///
    /// All events triggerd by a given stack operation are assigne dthe same client request token,
    /// you can use to track operations. For example, if you execute a `CreateStack` operation with
    /// the token `token1`, then all the `StackEvents` generated by that operation will have
    /// `ClientRequestToken` set as `token1`.
    ///
    /// In the console, stack operations display the client request token on the Events tab. Stack
    /// operations that are initiated from the console use the token format
    /// *Console-StackOperation-ID*, which helps you easily identify the stack operation. For
    /// example, if you create a stack using the console, each stack event would be assigned the
    /// same token in the following format:
    /// `Console-CreateStack-7f59c3cf-00d2-40c7-b2ff-e75db0987002`.
    #[must_use]
    pub fn client_request_token(&self) -> Option<&str> {
        self.client_request_token.as_deref()
    }

    /// Get the unique ID of this event.
    #[must_use]
    pub fn event_id(&self) -> &str {
        self.event_id.as_str()
    }

    /// Get the logical name of the resource specified in the template.
    #[must_use]
    pub fn logical_resource_id(&self) -> &str {
        self.logical_resource_id.as_str()
    }

    /// Get the name of unique identifier associated with the physical instance of the resource.
    ///
    /// This is unset when a physical resource does not exist, e.g. when creation is still in
    /// progress or has failed.
    #[must_use]
    pub fn physical_resource_id(&self) -> Option<&str> {
        self.physical_resource_id.as_deref()
    }

    /// Get the success/failure message associated with the resource.
    #[must_use]
    pub fn resource_status_reason(&self) -> StatusReason {
        StatusReason::new(self.resource_status_reason.as_deref())
    }

    /// Get the type of resource.
    #[must_use]
    pub fn resource_type(&self) -> &str {
        self.resource_type.as_str()
    }

    /// Get the unique ID of the instance of the stack.
    #[must_use]
    pub fn stack_id(&self) -> &str {
        self.stack_id.as_str()
    }

    /// Get the name associated with the stack.
    #[must_use]
    pub fn stack_name(&self) -> &str {
        self.stack_name.as_str()
    }

    /// Get the time the status was updated.
    #[must_use]
    pub fn timestamp(&self) -> &DateTime<Utc> {
        &self.timestamp
    }
}