Skip to main content

alien_core/
ownership.rs

1use crate::ResourceLifecycle;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub struct ResourceOwnershipPolicy {
5    default_lifecycle: ResourceLifecycle,
6    allow_frozen: bool,
7    allow_live: bool,
8    emit_in_setup: bool,
9    frozen_management: bool,
10}
11
12impl ResourceOwnershipPolicy {
13    pub const fn new(
14        default_lifecycle: ResourceLifecycle,
15        allow_frozen: bool,
16        allow_live: bool,
17        emit_in_setup: bool,
18        frozen_management: bool,
19    ) -> Self {
20        Self {
21            default_lifecycle,
22            allow_frozen,
23            allow_live,
24            emit_in_setup,
25            frozen_management,
26        }
27    }
28
29    pub const fn default_lifecycle(self) -> ResourceLifecycle {
30        self.default_lifecycle
31    }
32
33    pub const fn allows_frozen(self) -> bool {
34        self.allow_frozen
35    }
36
37    pub const fn allows_live(self) -> bool {
38        self.allow_live
39    }
40
41    pub const fn allows_lifecycle(self, lifecycle: ResourceLifecycle) -> bool {
42        match lifecycle {
43            ResourceLifecycle::Frozen => self.allow_frozen,
44            ResourceLifecycle::Live => self.allow_live,
45        }
46    }
47
48    pub const fn should_emit_in_setup(self, lifecycle: ResourceLifecycle) -> bool {
49        self.emit_in_setup && matches!(lifecycle, ResourceLifecycle::Frozen)
50    }
51
52    pub const fn frozen_requires_management(self) -> bool {
53        self.frozen_management
54    }
55
56    pub fn allowed_lifecycles(self) -> &'static str {
57        match (self.allow_frozen, self.allow_live) {
58            (true, true) => "Frozen or Live",
59            (true, false) => "Frozen",
60            (false, true) => "Live",
61            (false, false) => "no lifecycle",
62        }
63    }
64}
65
66pub fn ownership_policy_for_resource_type(resource_type: &str) -> ResourceOwnershipPolicy {
67    match resource_type {
68        "function" | "container-cluster" => removed_resource_type(),
69        "worker" | "daemon" | "container" => live_only(),
70        "compute-cluster" => frozen_with_management(),
71        "artifact-registry" => frozen_with_management(),
72        "build"
73        | "network"
74        | "remote-stack-management"
75        | "service-account"
76        | "service_activation"
77        | "service-activation"
78        | "azure_resource_group"
79        | "azure-resource-group"
80        | "azure_storage_account"
81        | "azure-storage-account"
82        | "azure_container_apps_environment"
83        | "azure-container-apps-environment"
84        | "azure_service_bus_namespace"
85        | "azure-service-bus-namespace" => frozen_only(),
86        "storage" | "queue" | "kv" | "vault" => user_choice(),
87        _ => user_choice(),
88    }
89}
90
91const fn frozen_only() -> ResourceOwnershipPolicy {
92    ResourceOwnershipPolicy::new(ResourceLifecycle::Frozen, true, false, true, false)
93}
94
95const fn frozen_with_management() -> ResourceOwnershipPolicy {
96    ResourceOwnershipPolicy::new(ResourceLifecycle::Frozen, true, false, true, true)
97}
98
99const fn live_only() -> ResourceOwnershipPolicy {
100    ResourceOwnershipPolicy::new(ResourceLifecycle::Live, false, true, false, false)
101}
102
103const fn removed_resource_type() -> ResourceOwnershipPolicy {
104    ResourceOwnershipPolicy::new(ResourceLifecycle::Live, false, false, false, false)
105}
106
107const fn user_choice() -> ResourceOwnershipPolicy {
108    ResourceOwnershipPolicy::new(ResourceLifecycle::Frozen, true, true, true, false)
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn workload_resources_are_live_only() {
117        for resource_type in ["worker", "daemon", "container"] {
118            let policy = ownership_policy_for_resource_type(resource_type);
119            assert_eq!(policy.default_lifecycle(), ResourceLifecycle::Live);
120            assert!(!policy.allows_lifecycle(ResourceLifecycle::Frozen));
121            assert!(policy.allows_lifecycle(ResourceLifecycle::Live));
122            assert!(!policy.should_emit_in_setup(ResourceLifecycle::Live));
123        }
124    }
125
126    #[test]
127    fn compute_cluster_is_frozen_with_management() {
128        for resource_type in ["compute-cluster", "artifact-registry"] {
129            let policy = ownership_policy_for_resource_type(resource_type);
130            assert_eq!(policy.default_lifecycle(), ResourceLifecycle::Frozen);
131            assert!(policy.allows_lifecycle(ResourceLifecycle::Frozen));
132            assert!(!policy.allows_lifecycle(ResourceLifecycle::Live));
133            assert!(policy.should_emit_in_setup(ResourceLifecycle::Frozen));
134            assert!(policy.frozen_requires_management());
135        }
136    }
137
138    #[test]
139    fn removed_resource_type_tags_are_not_normal_policy_entries() {
140        for resource_type in ["function", "container-cluster"] {
141            let policy = ownership_policy_for_resource_type(resource_type);
142            assert!(!policy.allows_lifecycle(ResourceLifecycle::Frozen));
143            assert!(!policy.allows_lifecycle(ResourceLifecycle::Live));
144            assert!(!policy.frozen_requires_management());
145        }
146    }
147
148    #[test]
149    fn data_resources_can_be_frozen_or_live() {
150        for resource_type in ["storage", "queue", "kv", "vault"] {
151            let policy = ownership_policy_for_resource_type(resource_type);
152            assert_eq!(policy.default_lifecycle(), ResourceLifecycle::Frozen);
153            assert!(policy.allows_lifecycle(ResourceLifecycle::Frozen));
154            assert!(policy.allows_lifecycle(ResourceLifecycle::Live));
155            assert!(policy.should_emit_in_setup(ResourceLifecycle::Frozen));
156            assert!(!policy.should_emit_in_setup(ResourceLifecycle::Live));
157        }
158    }
159
160    #[test]
161    fn setup_resources_are_frozen_only() {
162        for resource_type in [
163            "build",
164            "network",
165            "remote-stack-management",
166            "service-account",
167            "service_activation",
168            "azure_resource_group",
169            "azure_storage_account",
170            "azure_container_apps_environment",
171            "azure_service_bus_namespace",
172        ] {
173            let policy = ownership_policy_for_resource_type(resource_type);
174            assert!(policy.allows_lifecycle(ResourceLifecycle::Frozen));
175            assert!(!policy.allows_lifecycle(ResourceLifecycle::Live));
176            assert!(policy.should_emit_in_setup(ResourceLifecycle::Frozen));
177        }
178    }
179}