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}