Skip to content

Commit 70d0d0d

Browse files
authored
Merge pull request Azure#62 from MaxHorstmann/maxhorstmann/deployment-stacks-runner
Add DeploymentStacks runner
2 parents 284df70 + 10dc113 commit 70d0d0d

File tree

6 files changed

+248
-0
lines changed

6 files changed

+248
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
ARG BASE_IMAGE=mcr.microsoft.com/deployment-environments/runners/core
5+
ARG IMAGE_VERSION=latest
6+
7+
FROM ${BASE_IMAGE}:${IMAGE_VERSION}
8+
WORKDIR /
9+
10+
ARG IMAGE_VERSION
11+
12+
# Metadata as defined at http://label-schema.org
13+
ARG BUILD_DATE
14+
15+
# install bicep
16+
RUN az bicep install
17+
18+
# suppress warnings (temp solution until we can snap to Azure Linux)
19+
RUN az config set core.only_show_errors=true
20+
21+
# Grab all .sh files from scripts, copy to
22+
# root scripts, replace line-endings and make them all executable
23+
COPY scripts/* /scripts/
24+
RUN find /scripts/ -type f -iname "*.sh" -exec dos2unix '{}' '+'
25+
RUN find /scripts/ -type f -iname "*.sh" -exec chmod +x {} \;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/bash
2+
3+
# Copyright (c) Microsoft Corporation.
4+
# Licensed under the MIT License.
5+
source "/shared/commands.sh"
6+
7+
trackDeployment() {
8+
9+
trace="$( echo "$1" | jq --raw-output '.[] | [.operationId, .properties.timestamp, .properties.provisioningOperation, .properties.provisioningState, .properties.targetResource.id // ""] | @tsv' )"
10+
11+
echo "$trace" | while read -r line; do
12+
if [[ ! -z "$line" ]]; then
13+
14+
operationId="$( echo "$line" | cut -f 1 )"
15+
operationTimestamp="$( echo "$line" | cut -f 2 | cut -d . -f 1 | sed 's/T/ /g' )"
16+
operationType="$( echo "$line" | cut -f 3 )"
17+
operationState="$( echo "$line" | cut -f 4 )"
18+
operationTarget="$( echo "$line" | cut -f 5 )"
19+
operationHash="$( echo "$operationId|$operationState" | md5sum | cut -d ' ' -f 1 )"
20+
21+
if ! grep -q "$operationHash" /tmp/hashes 2>/dev/null ; then
22+
23+
echo -e "\n$operationTimestamp\t$operationId - $operationType ($operationState)"
24+
25+
if [[ ! -z "$operationTarget" ]]; then
26+
echo -e "\t\t\t$operationTarget"
27+
fi
28+
29+
echo "$operationHash" >> /tmp/hashes
30+
31+
fi
32+
fi
33+
done
34+
}
35+
36+
outputDeploymentErrors() {
37+
echo -e "Deployment failed with the following errors:\n" 1>&2
38+
readarray errors -t <<< $(echo $1 | jq -c '.[] | .properties | select(has("statusMessage") and (.statusMessage | has("error")))')
39+
echo -e "Number of errors: ${#errors[@]}\n" 1>&2
40+
for item in "${errors[@]}"; do
41+
echo -e "Target Resource ID: $( echo $item | jq '. | .targetResource.id' )\nError Code: $( echo $item | jq '.statusMessage.error.code' )\nError Message: $( echo $item | jq '.statusMessage.error.message' )\n" 1>&2
42+
readarray errorDetails -t <<< $(echo $item | jq -c '.statusMessage.error.details')
43+
44+
if [[ -z $errorDetails ]]; then
45+
for detail in "${errorDetails[@]}"; do
46+
echo -e "Error Detail Code: $( echo $detail | jq '.[] | .code')\nError Detail Message: $(echo $detail | jq '.[] | .message')\n" 1>&2
47+
done
48+
fi
49+
done
50+
}
51+
52+
#below - used for deployment stack deletion -> not given deployment info, so use deployment stack resource
53+
outputDeletionErrors() {
54+
echo "Deletion failed with the following resources:\n"
55+
failedResources=$(az stack group show --name $ADE_ENVIRONMENT_NAME --resource-group $ADE_RESOURCE_GROUP_NAME --query "failedResources" )
56+
readarray errors -t <<< $(echo $1)
57+
echo "Number of failed resources: ${#errors[@]}\n" 1>&2
58+
for item in ${errors[@]}; do
59+
echo "Resource ID: $( echo $item | jq '.id')\nError Code: $( echo $item | jq '.error.code')\nError Message: $(echo $item | jq '.error.message')" 1>&2
60+
done
61+
}
62+
63+
setOutputs() {
64+
outputs=$1
65+
outputs=$(jq 'walk(if type == "object" then
66+
if .type == "Bool" then .type = "boolean"
67+
elif .type == "Int" then .type = "number"
68+
else .
69+
end
70+
else .
71+
end)' <<< "$outputs")
72+
echo "{\"outputs\": $outputs}" > $ADE_OUTPUTS
73+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
# Copyright (c) Microsoft Corporation.
4+
# Licensed under the MIT License.
5+
set -e # exit on error
6+
7+
DIR=$(dirname "$0")
8+
. $DIR/_common.sh
9+
10+
echo "Deleting resource group: $ADE_RESOURCE_GROUP_NAME"
11+
12+
echo "Signing into Azure using MSI"
13+
while true; do
14+
# managed identity isn't available immediately
15+
# we need to do retry after a short nap
16+
az login --identity --only-show-errors --output none && {
17+
echo "Successfully signed into Azure"
18+
az account set --subscription $ADE_SUBSCRIPTION_ID
19+
break
20+
} || sleep 5
21+
done
22+
23+
echo -e "\n>>> Beginning Deletion ...\n"
24+
25+
az stack group delete --resource-group "$ADE_RESOURCE_GROUP_NAME" \
26+
--name "$ADE_ENVIRONMENT_NAME" \
27+
--yes \
28+
--action-on-unmanage deleteResources
29+
30+
if [ $? -eq 0 ]; then # deployment successfully created
31+
echo "Successfully Deleted Resources"
32+
else
33+
echo "Failed to Delete Resources"
34+
outputDeletionErrors
35+
exit 1
36+
fi
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/bin/bash
2+
3+
# Copyright (c) Microsoft Corporation.
4+
# Licensed under the MIT License.
5+
set -e # exit on error
6+
7+
DIR=$(dirname "$0")
8+
source $DIR/_common.sh
9+
10+
deploymentOutput=""
11+
12+
# format the parameters as arm parameters
13+
deploymentParameters=$(echo "$ADE_OPERATION_PARAMETERS" | jq --compact-output '{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": (to_entries | if length == 0 then {} else (map( { (.key): { "value": .value } } ) | add) end) }' )
14+
15+
16+
# We can resolve linked templates with
17+
# relativePaths before submitting the deployment to ARM by:
18+
#
19+
# 1. Use `bicep decompile` to transpile the ARM template into
20+
# bicep modules. During this process bicep will resolve the linked
21+
# templates locally and convert them each into bicep modules.
22+
#
23+
# 2. Then run `bicep build` to transpile those bicep modules back
24+
# into ARM. This will output a new, single ARM template with the
25+
# linked templates embedded as nested templates
26+
if [[ $ADE_TEMPLATE_FILE == *.json ]]; then
27+
28+
hasRelativePath=$( cat $ADE_TEMPLATE_FILE | jq '[.. | objects | select(has("templateLink") and (.templateLink | has("relativePath")))] | any' )
29+
30+
if [ "$hasRelativePath" = "true" ]; then
31+
echo "Resolving linked ARM templates"
32+
33+
bicepTemplate="${ADE_TEMPLATE_FILE/.json/.bicep}"
34+
generatedTemplate="${ADE_TEMPLATE_FILE/.json/.generated.json}"
35+
36+
az bicep decompile --file "$ADE_TEMPLATE_FILE"
37+
az bicep build --file "$bicepTemplate" --outfile "$generatedTemplate"
38+
39+
# Correctly reassign ADE_TEMPLATE_FILE without the $ prefix during assignment
40+
ADE_TEMPLATE_FILE="$generatedTemplate"
41+
else
42+
echo "Not linked template"
43+
fi
44+
fi
45+
46+
47+
echo "Signing into Azure using MSI"
48+
while true; do
49+
# managed identity isn't available immediately
50+
# we need to do retry after a short nap
51+
az login --identity --only-show-errors --output none && {
52+
echo "Successfully signed into Azure"
53+
az account set --subscription $ADE_SUBSCRIPTION_ID
54+
break
55+
} || sleep 5
56+
done
57+
58+
echo -e "\n>>>Deploying ARM/Bicep template...\n"
59+
az stack group create --subscription $ADE_SUBSCRIPTION_ID \
60+
--resource-group "$ADE_RESOURCE_GROUP_NAME" \
61+
--name "$ADE_ENVIRONMENT_NAME" \
62+
--deny-settings-mode "none" \
63+
--no-wait --yes \
64+
--template-file "$ADE_TEMPLATE_FILE" \
65+
--parameters "$deploymentParameters" \
66+
--action-on-unmanage deleteResources
67+
68+
if [ $? -eq 0 ]; then # deployment successfully created
69+
sleep 30 # sleep for 30 seconds to ensure deployment ID is set correctly
70+
while true; do
71+
72+
sleep 1
73+
74+
deploymentId=$(az stack group show --resource-group "$ADE_RESOURCE_GROUP_NAME" --name "$ADE_ENVIRONMENT_NAME" --query "deploymentId" -o tsv)
75+
deploymentName=$(echo "$deploymentId" | cut -d '/' -f 9)
76+
ProvisioningState=$(az deployment group show --resource-group "$ADE_RESOURCE_GROUP_NAME" --name "$deploymentName" --query "properties.provisioningState" -o tsv)
77+
ProvisioningDetails=$(az deployment operation group list --resource-group "$ADE_RESOURCE_GROUP_NAME" --name "$deploymentName")
78+
79+
trackDeployment "$ProvisioningDetails"
80+
81+
if [[ "CANCELED|FAILED|SUCCEEDED" == *"${ProvisioningState^^}"* ]]; then
82+
83+
echo "\nDeployment $deploymentName: $ProvisioningState"
84+
85+
if [[ "CANCELED|FAILED" == *"${ProvisioningState^^}"* ]]; then
86+
outputDeploymentErrors "$ProvisioningDetails"
87+
exit 1
88+
else
89+
break
90+
fi
91+
fi
92+
93+
done
94+
95+
echo -e "\n>>> Generating outputs for ADE...\n"
96+
deploymentOutput=$(az deployment group show -g "$ADE_RESOURCE_GROUP_NAME" -n "$deploymentName" --query properties.outputs)
97+
if [ -z "$deploymentOutput" ]; then
98+
echo "No outputs found for deployment"
99+
else
100+
setOutputs "$deploymentOutput"
101+
echo "Outputs successfully generated for ADE"
102+
fi
103+
else
104+
echo "Deployment failed to create."
105+
fi
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {},
5+
"variables": {},
6+
"resources": [],
7+
"outputs": {}
8+
}

Runner-Images/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Featured Repos
44
+ Core: Core ADE Image
55
+ ARM-Bicep: ADE Image for ARM/Bicep Deployments/Deletions
6+
+ DeploymentStacks: ADE Image for Azure [Deployment stacks](https://github.com/Azure/deployment-stacks)
67

78
## About Azure Deployment Environments
89
Azure Deployment Environments empowers development teams to quickly and easily spin up app infrastructure with project-based templates that establish consistency and best practices while maximizing security. This on-demand access to secure environments accelerates the stages of the software development lifecycle in a compliant and cost-efficient way.

0 commit comments

Comments
 (0)