fakecloud_cloudformation/
xml_responses.rs1use crate::state::{Stack, StackResource};
2
3use fakecloud_aws::xml::xml_escape;
4
5pub fn create_stack_response(stack_id: &str, request_id: &str) -> String {
6 format!(
7 r#"<CreateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
8 <CreateStackResult>
9 <StackId>{stack_id}</StackId>
10 </CreateStackResult>
11 <ResponseMetadata>
12 <RequestId>{request_id}</RequestId>
13 </ResponseMetadata>
14</CreateStackResponse>"#,
15 stack_id = xml_escape(stack_id),
16 request_id = xml_escape(request_id),
17 )
18}
19
20pub fn update_stack_response(stack_id: &str, request_id: &str) -> String {
21 format!(
22 r#"<UpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
23 <UpdateStackResult>
24 <StackId>{stack_id}</StackId>
25 </UpdateStackResult>
26 <ResponseMetadata>
27 <RequestId>{request_id}</RequestId>
28 </ResponseMetadata>
29</UpdateStackResponse>"#,
30 stack_id = xml_escape(stack_id),
31 request_id = xml_escape(request_id),
32 )
33}
34
35pub fn delete_stack_response(request_id: &str) -> String {
36 format!(
37 r#"<DeleteStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
38 <ResponseMetadata>
39 <RequestId>{request_id}</RequestId>
40 </ResponseMetadata>
41</DeleteStackResponse>"#,
42 request_id = xml_escape(request_id),
43 )
44}
45
46pub fn describe_stacks_response(stacks: &[Stack], request_id: &str) -> String {
47 let members: String = stacks
48 .iter()
49 .map(stack_member_xml)
50 .collect::<Vec<_>>()
51 .join("\n");
52
53 format!(
54 r#"<DescribeStacksResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
55 <DescribeStacksResult>
56 <Stacks>
57{members}
58 </Stacks>
59 </DescribeStacksResult>
60 <ResponseMetadata>
61 <RequestId>{request_id}</RequestId>
62 </ResponseMetadata>
63</DescribeStacksResponse>"#,
64 request_id = xml_escape(request_id),
65 )
66}
67
68fn stack_member_xml(stack: &Stack) -> String {
69 let tags_xml = if stack.tags.is_empty() {
70 String::new()
71 } else {
72 let tags: String = stack
73 .tags
74 .iter()
75 .map(|(k, v)| {
76 format!(
77 " <member>\n <Key>{}</Key>\n <Value>{}</Value>\n </member>",
78 xml_escape(k),
79 xml_escape(v),
80 )
81 })
82 .collect::<Vec<_>>()
83 .join("\n");
84 format!("\n <Tags>\n{tags}\n </Tags>")
85 };
86
87 let params_xml = if stack.parameters.is_empty() {
88 String::new()
89 } else {
90 let params: String = stack
91 .parameters
92 .iter()
93 .map(|(k, v)| {
94 format!(
95 " <member>\n <ParameterKey>{}</ParameterKey>\n <ParameterValue>{}</ParameterValue>\n </member>",
96 xml_escape(k),
97 xml_escape(v),
98 )
99 })
100 .collect::<Vec<_>>()
101 .join("\n");
102 format!("\n <Parameters>\n{params}\n </Parameters>")
103 };
104
105 let description_xml = stack
106 .description
107 .as_ref()
108 .map(|d| format!("\n <Description>{}</Description>", xml_escape(d)))
109 .unwrap_or_default();
110
111 format!(
112 r#" <member>
113 <StackName>{name}</StackName>
114 <StackId>{id}</StackId>
115 <StackStatus>{status}</StackStatus>
116 <CreationTime>{created}</CreationTime>{description_xml}{tags_xml}{params_xml}
117 </member>"#,
118 name = xml_escape(&stack.name),
119 id = xml_escape(&stack.stack_id),
120 status = xml_escape(&stack.status),
121 created = stack.created_at.format("%Y-%m-%dT%H:%M:%SZ"),
122 )
123}
124
125pub fn list_stacks_response(stacks: &[Stack], request_id: &str) -> String {
126 let summaries: String = stacks
127 .iter()
128 .map(|s| {
129 format!(
130 r#" <member>
131 <StackName>{name}</StackName>
132 <StackId>{id}</StackId>
133 <StackStatus>{status}</StackStatus>
134 <CreationTime>{created}</CreationTime>
135 </member>"#,
136 name = xml_escape(&s.name),
137 id = xml_escape(&s.stack_id),
138 status = xml_escape(&s.status),
139 created = s.created_at.format("%Y-%m-%dT%H:%M:%SZ"),
140 )
141 })
142 .collect::<Vec<_>>()
143 .join("\n");
144
145 format!(
146 r#"<ListStacksResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
147 <ListStacksResult>
148 <StackSummaries>
149{summaries}
150 </StackSummaries>
151 </ListStacksResult>
152 <ResponseMetadata>
153 <RequestId>{request_id}</RequestId>
154 </ResponseMetadata>
155</ListStacksResponse>"#,
156 request_id = xml_escape(request_id),
157 )
158}
159
160pub fn list_stack_resources_response(resources: &[StackResource], request_id: &str) -> String {
161 let summaries: String = resources
162 .iter()
163 .map(stack_resource_summary_xml)
164 .collect::<Vec<_>>()
165 .join("\n");
166
167 format!(
168 r#"<ListStackResourcesResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
169 <ListStackResourcesResult>
170 <StackResourceSummaries>
171{summaries}
172 </StackResourceSummaries>
173 </ListStackResourcesResult>
174 <ResponseMetadata>
175 <RequestId>{request_id}</RequestId>
176 </ResponseMetadata>
177</ListStackResourcesResponse>"#,
178 request_id = xml_escape(request_id),
179 )
180}
181
182fn stack_resource_summary_xml(resource: &StackResource) -> String {
183 format!(
184 r#" <member>
185 <LogicalResourceId>{logical_id}</LogicalResourceId>
186 <PhysicalResourceId>{physical_id}</PhysicalResourceId>
187 <ResourceType>{resource_type}</ResourceType>
188 <ResourceStatus>{status}</ResourceStatus>
189 </member>"#,
190 logical_id = xml_escape(&resource.logical_id),
191 physical_id = xml_escape(&resource.physical_id),
192 resource_type = xml_escape(&resource.resource_type),
193 status = xml_escape(&resource.status),
194 )
195}
196
197pub fn describe_stack_resources_response(
198 resources: &[StackResource],
199 stack_name: &str,
200 request_id: &str,
201) -> String {
202 let members: String = resources
203 .iter()
204 .map(|r| {
205 format!(
206 r#" <member>
207 <StackName>{stack_name}</StackName>
208 <LogicalResourceId>{logical_id}</LogicalResourceId>
209 <PhysicalResourceId>{physical_id}</PhysicalResourceId>
210 <ResourceType>{resource_type}</ResourceType>
211 <ResourceStatus>{status}</ResourceStatus>
212 </member>"#,
213 stack_name = xml_escape(stack_name),
214 logical_id = xml_escape(&r.logical_id),
215 physical_id = xml_escape(&r.physical_id),
216 resource_type = xml_escape(&r.resource_type),
217 status = xml_escape(&r.status),
218 )
219 })
220 .collect::<Vec<_>>()
221 .join("\n");
222
223 format!(
224 r#"<DescribeStackResourcesResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
225 <DescribeStackResourcesResult>
226 <StackResources>
227{members}
228 </StackResources>
229 </DescribeStackResourcesResult>
230 <ResponseMetadata>
231 <RequestId>{request_id}</RequestId>
232 </ResponseMetadata>
233</DescribeStackResourcesResponse>"#,
234 request_id = xml_escape(request_id),
235 )
236}
237
238pub fn get_template_response(template_body: &str, request_id: &str) -> String {
239 format!(
240 r#"<GetTemplateResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
241 <GetTemplateResult>
242 <TemplateBody>{template_body}</TemplateBody>
243 </GetTemplateResult>
244 <ResponseMetadata>
245 <RequestId>{request_id}</RequestId>
246 </ResponseMetadata>
247</GetTemplateResponse>"#,
248 template_body = xml_escape(template_body),
249 request_id = xml_escape(request_id),
250 )
251}