Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -71,24 +71,21 @@ def resolve_template_expressions(template):
|
|
71 |
|
72 |
# Function to estimate the cost of resources
|
73 |
def estimate_cost(resources):
|
74 |
-
# This is a simplified cost estimation. In a real scenario, you'd need to
|
75 |
-
# integrate with Azure's pricing API or use a more comprehensive pricing model.
|
76 |
cost_estimates = {
|
77 |
-
"Microsoft.Storage/storageAccounts": 10,
|
78 |
-
"Microsoft.Compute/virtualMachines": 50,
|
79 |
-
"Microsoft.Web/sites": 30,
|
80 |
-
"Microsoft.Sql/servers": 40,
|
81 |
-
# Add more resource types and their estimated costs
|
82 |
}
|
83 |
-
|
84 |
total_cost = 0
|
85 |
for resource in resources:
|
86 |
resource_type = resource.get('type')
|
87 |
if resource_type in cost_estimates:
|
88 |
total_cost += cost_estimates[resource_type]
|
89 |
else:
|
90 |
-
total_cost += 5
|
91 |
-
|
92 |
return total_cost
|
93 |
|
94 |
# Function to create a dependency graph of resources
|
@@ -108,8 +105,6 @@ def plot_dependency_graph(G):
|
|
108 |
pos = nx.spring_layout(G)
|
109 |
nx.draw(G, pos, with_labels=True, node_color='lightblue',
|
110 |
node_size=3000, font_size=8, font_weight='bold')
|
111 |
-
edge_labels = nx.get_edge_attributes(G, 'weight')
|
112 |
-
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
|
113 |
plt.title("Resource Dependency Graph")
|
114 |
return plt
|
115 |
|
@@ -117,41 +112,29 @@ def plot_dependency_graph(G):
|
|
117 |
def lint_template(template):
|
118 |
lint_results = []
|
119 |
|
120 |
-
# Check 1: Ensure all resources have tags
|
121 |
for resource in template.get('resources', []):
|
122 |
if 'tags' not in resource:
|
123 |
lint_results.append(f"Warning: Resource '{resource.get('name')}' does not have any tags.")
|
124 |
-
|
125 |
-
# Check 2: Ensure parameters have descriptions
|
126 |
for param_name, param_value in template.get('parameters', {}).items():
|
127 |
if 'metadata' not in param_value or 'description' not in param_value['metadata']:
|
128 |
lint_results.append(f"Warning: Parameter '{param_name}' does not have a description.")
|
129 |
-
|
130 |
-
# Check 3: Warn about hardcoded values in resource properties
|
131 |
-
for resource in template.get('resources', []):
|
132 |
-
for prop, value in resource.get('properties', {}).items():
|
133 |
-
if isinstance(value, (str, int, float)) and not isinstance(value, bool):
|
134 |
-
lint_results.append(f"Info: Consider using a parameter for the hardcoded value in resource '{resource.get('name')}', property '{prop}'.")
|
135 |
-
|
136 |
return lint_results
|
137 |
|
138 |
# Function to generate a system diagram
|
139 |
def generate_system_diagram(resources):
|
140 |
-
# Create a new Graphviz graph
|
141 |
dot = graphviz.Digraph()
|
142 |
-
dot.attr(rankdir='TB')
|
143 |
|
144 |
-
# Create nodes for each resource
|
145 |
for i, resource in enumerate(resources):
|
146 |
resource_type = resource['type'].split('/')[-1]
|
147 |
node_id = f"R{i}"
|
148 |
dot.node(node_id, f"{resource_type}\n{resource['name']}")
|
149 |
|
150 |
-
# Create connections based on dependencies
|
151 |
for resource in resources:
|
152 |
if 'dependsOn' in resource:
|
153 |
for dependency in resource['dependsOn']:
|
154 |
-
# Find the node id for the dependency
|
155 |
dep_id = next((f"R{j}" for j, r in enumerate(resources) if r['name'] == dependency), None)
|
156 |
if dep_id:
|
157 |
dot.edge(dep_id, f"R{resources.index(resource)}")
|
@@ -163,12 +146,10 @@ def simulate_deployment(arm_template):
|
|
163 |
try:
|
164 |
template = json.loads(arm_template)
|
165 |
|
166 |
-
# Validate template
|
167 |
is_valid, validation_message = validate_template(template)
|
168 |
if not is_valid:
|
169 |
return [], [], [], [], 0, None, [], None, validation_message
|
170 |
|
171 |
-
# Resolve expressions
|
172 |
resolved_template = resolve_template_expressions(template)
|
173 |
|
174 |
resources_to_create = []
|
@@ -205,16 +186,12 @@ def simulate_deployment(arm_template):
|
|
205 |
if resource_name not in [r.get('name') for r in resolved_template.get('resources', [])]:
|
206 |
resources_to_delete.append(resource_name)
|
207 |
|
208 |
-
# Estimate cost
|
209 |
estimated_cost = estimate_cost(resource_details)
|
210 |
|
211 |
-
# Create dependency graph
|
212 |
dependency_graph = create_dependency_graph(resolved_template.get('resources', []))
|
213 |
|
214 |
-
# Lint template
|
215 |
lint_results = lint_template(template)
|
216 |
|
217 |
-
# Generate system diagram
|
218 |
system_diagram = generate_system_diagram(resource_details)
|
219 |
|
220 |
return resources_to_create, resources_to_update, resources_to_delete, resource_details, estimated_cost, dependency_graph, lint_results, system_diagram, "Simulation completed successfully."
|
@@ -225,64 +202,44 @@ def simulate_deployment(arm_template):
|
|
225 |
st.title("Comprehensive ARM Template Simulator")
|
226 |
st.subheader("Upload your ARM template or paste it below to simulate its deployment.")
|
227 |
|
228 |
-
# File uploader
|
229 |
uploaded_file = st.file_uploader("Choose an ARM template file", type=["json"])
|
230 |
|
231 |
-
# Input box for ARM template
|
232 |
template_input = st.text_area("Or paste ARM Template JSON here:", height=300)
|
233 |
|
234 |
-
# Function to read file contents
|
235 |
def read_file_contents(file):
|
236 |
return file.getvalue().decode("utf-8")
|
237 |
|
238 |
-
# Button to simulate the evaluation
|
239 |
if st.button("Simulate Template"):
|
240 |
-
# Check if a file was uploaded
|
241 |
if uploaded_file is not None:
|
242 |
-
# Read the contents of the uploaded file
|
243 |
file_contents = read_file_contents(uploaded_file)
|
244 |
-
# Use the file contents for simulation
|
245 |
template_to_simulate = file_contents
|
246 |
elif template_input:
|
247 |
-
# Use the pasted input for simulation
|
248 |
template_to_simulate = template_input
|
249 |
else:
|
250 |
st.error("Please either upload a file or paste an ARM template to simulate.")
|
251 |
st.stop()
|
252 |
|
253 |
-
# Proceed with simulation
|
254 |
resources_to_create, resources_to_update, resources_to_delete, resource_details, estimated_cost, dependency_graph, lint_results, system_diagram, message = simulate_deployment(template_to_simulate)
|
255 |
-
|
256 |
st.subheader("Simulation Results:")
|
257 |
st.write(message)
|
258 |
|
259 |
if resources_to_create or resources_to_update or resources_to_delete:
|
260 |
st.write("### Resources to be Created:")
|
261 |
-
|
262 |
-
st.write(resources_to_create)
|
263 |
-
else:
|
264 |
-
st.write("No new resources will be created.")
|
265 |
|
266 |
st.write("### Resources to be Updated:")
|
267 |
-
|
268 |
-
st.write(resources_to_update)
|
269 |
-
else:
|
270 |
-
st.write("No resources will be updated.")
|
271 |
|
272 |
st.write("### Resources to be Deleted:")
|
273 |
-
|
274 |
-
st.write(resources_to_delete)
|
275 |
-
else:
|
276 |
-
st.write("No resources will be deleted.")
|
277 |
|
278 |
st.write("### Detailed Resource Information:")
|
279 |
for resource in resource_details:
|
280 |
st.write(f"**Name:** {resource['name']}")
|
281 |
st.write(f"**Type:** {resource['type']}")
|
282 |
st.write(f"**Location:** {resource['location']}")
|
283 |
-
st.write("**Properties:**")
|
284 |
st.json(resource['properties'])
|
285 |
-
st.write("---")
|
286 |
|
287 |
st.write(f"### Estimated Monthly Cost: ${estimated_cost}")
|
288 |
|
@@ -290,20 +247,13 @@ if st.button("Simulate Template"):
|
|
290 |
if dependency_graph:
|
291 |
fig = plot_dependency_graph(dependency_graph)
|
292 |
st.pyplot(fig)
|
293 |
-
else:
|
294 |
-
st.write("No dependencies found between resources.")
|
295 |
|
296 |
st.write("### System Diagram:")
|
297 |
if system_diagram:
|
298 |
st.graphviz_chart(system_diagram)
|
299 |
-
else:
|
300 |
-
st.write("Unable to generate system diagram.")
|
301 |
|
302 |
st.write("### Template Lint Results:")
|
303 |
-
|
304 |
-
|
305 |
-
st.write(result)
|
306 |
-
else:
|
307 |
-
st.write("No linting issues found.")
|
308 |
else:
|
309 |
-
st.write("No changes detected in the simulation.")
|
|
|
71 |
|
72 |
# Function to estimate the cost of resources
|
73 |
def estimate_cost(resources):
|
|
|
|
|
74 |
cost_estimates = {
|
75 |
+
"Microsoft.Storage/storageAccounts": 10,
|
76 |
+
"Microsoft.Compute/virtualMachines": 50,
|
77 |
+
"Microsoft.Web/sites": 30,
|
78 |
+
"Microsoft.Sql/servers": 40,
|
|
|
79 |
}
|
80 |
+
|
81 |
total_cost = 0
|
82 |
for resource in resources:
|
83 |
resource_type = resource.get('type')
|
84 |
if resource_type in cost_estimates:
|
85 |
total_cost += cost_estimates[resource_type]
|
86 |
else:
|
87 |
+
total_cost += 5
|
88 |
+
|
89 |
return total_cost
|
90 |
|
91 |
# Function to create a dependency graph of resources
|
|
|
105 |
pos = nx.spring_layout(G)
|
106 |
nx.draw(G, pos, with_labels=True, node_color='lightblue',
|
107 |
node_size=3000, font_size=8, font_weight='bold')
|
|
|
|
|
108 |
plt.title("Resource Dependency Graph")
|
109 |
return plt
|
110 |
|
|
|
112 |
def lint_template(template):
|
113 |
lint_results = []
|
114 |
|
|
|
115 |
for resource in template.get('resources', []):
|
116 |
if 'tags' not in resource:
|
117 |
lint_results.append(f"Warning: Resource '{resource.get('name')}' does not have any tags.")
|
118 |
+
|
|
|
119 |
for param_name, param_value in template.get('parameters', {}).items():
|
120 |
if 'metadata' not in param_value or 'description' not in param_value['metadata']:
|
121 |
lint_results.append(f"Warning: Parameter '{param_name}' does not have a description.")
|
122 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
return lint_results
|
124 |
|
125 |
# Function to generate a system diagram
|
126 |
def generate_system_diagram(resources):
|
|
|
127 |
dot = graphviz.Digraph()
|
128 |
+
dot.attr(rankdir='TB')
|
129 |
|
|
|
130 |
for i, resource in enumerate(resources):
|
131 |
resource_type = resource['type'].split('/')[-1]
|
132 |
node_id = f"R{i}"
|
133 |
dot.node(node_id, f"{resource_type}\n{resource['name']}")
|
134 |
|
|
|
135 |
for resource in resources:
|
136 |
if 'dependsOn' in resource:
|
137 |
for dependency in resource['dependsOn']:
|
|
|
138 |
dep_id = next((f"R{j}" for j, r in enumerate(resources) if r['name'] == dependency), None)
|
139 |
if dep_id:
|
140 |
dot.edge(dep_id, f"R{resources.index(resource)}")
|
|
|
146 |
try:
|
147 |
template = json.loads(arm_template)
|
148 |
|
|
|
149 |
is_valid, validation_message = validate_template(template)
|
150 |
if not is_valid:
|
151 |
return [], [], [], [], 0, None, [], None, validation_message
|
152 |
|
|
|
153 |
resolved_template = resolve_template_expressions(template)
|
154 |
|
155 |
resources_to_create = []
|
|
|
186 |
if resource_name not in [r.get('name') for r in resolved_template.get('resources', [])]:
|
187 |
resources_to_delete.append(resource_name)
|
188 |
|
|
|
189 |
estimated_cost = estimate_cost(resource_details)
|
190 |
|
|
|
191 |
dependency_graph = create_dependency_graph(resolved_template.get('resources', []))
|
192 |
|
|
|
193 |
lint_results = lint_template(template)
|
194 |
|
|
|
195 |
system_diagram = generate_system_diagram(resource_details)
|
196 |
|
197 |
return resources_to_create, resources_to_update, resources_to_delete, resource_details, estimated_cost, dependency_graph, lint_results, system_diagram, "Simulation completed successfully."
|
|
|
202 |
st.title("Comprehensive ARM Template Simulator")
|
203 |
st.subheader("Upload your ARM template or paste it below to simulate its deployment.")
|
204 |
|
|
|
205 |
uploaded_file = st.file_uploader("Choose an ARM template file", type=["json"])
|
206 |
|
|
|
207 |
template_input = st.text_area("Or paste ARM Template JSON here:", height=300)
|
208 |
|
|
|
209 |
def read_file_contents(file):
|
210 |
return file.getvalue().decode("utf-8")
|
211 |
|
|
|
212 |
if st.button("Simulate Template"):
|
|
|
213 |
if uploaded_file is not None:
|
|
|
214 |
file_contents = read_file_contents(uploaded_file)
|
|
|
215 |
template_to_simulate = file_contents
|
216 |
elif template_input:
|
|
|
217 |
template_to_simulate = template_input
|
218 |
else:
|
219 |
st.error("Please either upload a file or paste an ARM template to simulate.")
|
220 |
st.stop()
|
221 |
|
|
|
222 |
resources_to_create, resources_to_update, resources_to_delete, resource_details, estimated_cost, dependency_graph, lint_results, system_diagram, message = simulate_deployment(template_to_simulate)
|
223 |
+
|
224 |
st.subheader("Simulation Results:")
|
225 |
st.write(message)
|
226 |
|
227 |
if resources_to_create or resources_to_update or resources_to_delete:
|
228 |
st.write("### Resources to be Created:")
|
229 |
+
st.write(resources_to_create or "No new resources will be created.")
|
|
|
|
|
|
|
230 |
|
231 |
st.write("### Resources to be Updated:")
|
232 |
+
st.write(resources_to_update or "No resources will be updated.")
|
|
|
|
|
|
|
233 |
|
234 |
st.write("### Resources to be Deleted:")
|
235 |
+
st.write(resources_to_delete or "No resources will be deleted.")
|
|
|
|
|
|
|
236 |
|
237 |
st.write("### Detailed Resource Information:")
|
238 |
for resource in resource_details:
|
239 |
st.write(f"**Name:** {resource['name']}")
|
240 |
st.write(f"**Type:** {resource['type']}")
|
241 |
st.write(f"**Location:** {resource['location']}")
|
|
|
242 |
st.json(resource['properties'])
|
|
|
243 |
|
244 |
st.write(f"### Estimated Monthly Cost: ${estimated_cost}")
|
245 |
|
|
|
247 |
if dependency_graph:
|
248 |
fig = plot_dependency_graph(dependency_graph)
|
249 |
st.pyplot(fig)
|
|
|
|
|
250 |
|
251 |
st.write("### System Diagram:")
|
252 |
if system_diagram:
|
253 |
st.graphviz_chart(system_diagram)
|
|
|
|
|
254 |
|
255 |
st.write("### Template Lint Results:")
|
256 |
+
for result in lint_results:
|
257 |
+
st.write(result)
|
|
|
|
|
|
|
258 |
else:
|
259 |
+
st.write("No changes detected in the simulation.")
|