add openhack files

This commit is contained in:
Ryan Peters
2022-11-03 16:41:13 -04:00
commit b2c9f7e29f
920 changed files with 118861 additions and 0 deletions

124
support/resources/KUSTO.md Normal file
View File

@ -0,0 +1,124 @@
# Kusto tutorial with Log Analytics
This tutorial will guide you through the first steps with the Kusto query language in the context of the DevOps OpenHack.
You create a graph that display how may trips have been completed by the simulator each half hour during the last 24 hours.
## Pre-requisites
In order to walk through this tutorial, it is expected that you have created and configured an Azure Log Analytics workspace to collect the logs from your AKS cluster.
## Your first query
Open the query editor in your analytics workspace by selecting **Logs** in the log analytics menu and enter the following code:
```kusto
ContainerLog
| search "simulator"
```
Click the **Run** button.
This query uses **ContainerLog** as data source and searches for the entries that contain the word "simulator". The rows matching the criteria are returned.
Expand the first entry by clicking on the arrow on the left of the line. The key/value pairs will help understand the fields of each returned row.
Look more specifically at the following fields:
- TimeGenerated\[UTC\]: This is the time at which the log entry has been generated
- Image: This is the name of the container image that has generated the entry, copy the name of the image we will use it in the next step. It should be similar to this "openhackcj19acr.azurecr.io/devopsoh/simulator:latest"
- LogEntry: The text that was written on the stdout of the container
## Filter the data
The command `where` allows to filter the data based on specific criteria like the generation time. The following query will apply a first filter on the data.
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
```
Let's now filter the content to only have the entries generated by the simulator container.
Replace the query with the following and click **Run** :
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
```
When the simulator completes a trip an entry similar to the following is generated:
```
Trip Completed at : 11/01/2018 04:42:03.
```
Let's update our query to select only those entries:
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
```
Click **Run** to see the result.
The `where` clause also understands regular expressions(RE). REs can be used to extract a specific value from a log entry and write this value into an additional column using `extend`. More information on the use of `extend` is available on this page: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-queries?toc=/azure/azure-monitor/toc.json#project-and-extend-select-and-compute-columns
## Reduce the number of columns
Update the query to get only the information that interest us: time of generation, the log entry and the containerId.
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
| project TimeGenerated, LogEntry, ContainerID
```
The `project` command will display only the comma seperated list of column names in the result of the query.
Click **Run** to see the result.
## Count the number of entries per time slot
We will use the `summarize` command to perform the aggregation according to the time of generation.
The `bin` function will round a value to its bin size; `bin(TimeGenerated, 1m)` round the TimeGenerated to the minute.
Our query becomes:
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
| project TimeGenerated, LogEntry, ContainerID
| summarize count(LogEntry) by bin(TimeGenerated, 30m)
```
Click **Run** to see the result.
## A picture worth thousand words
To represent the data on a graph we will use the `render` function and define the format, in our case we want a `timechart`
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
| project TimeGenerated, LogEntry, ContainerID
| summarize count(LogEntry) by bin(TimeGenerated, 30m)
| render timechart
```
[Render operator](https://docs.microsoft.com/en-us/azure/kusto/query/renderoperator)
[Creating Charts and Diagrams From Log Analytics](https://docs.microsoft.com/en-us/azure/log-analytics/query-language/charts?toc=/azure/azure-monitor/toc.json)
Click **Run** to render the graph.
## Reference documents
- Getting stated with log analytics portal: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-analytics-portal
- Getting started with query: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-analytics-portal
- String operations with Kusto: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/string-operations
- Search queries in Log Analytics: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/search-queries
- Add or select new column in a query: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-queries?toc=/azure/azure-monitor/toc.json#project-and-extend-select-and-compute-columns

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1 r1853635">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="MyDriving Load Test" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="UserJavaUri" elementType="Argument">
<stringProp name="Argument.name">UserJavaUri</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("UserJavaUri"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="UserProfileUri" elementType="Argument">
<stringProp name="Argument.name">UserProfileUri</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("UserProfileUri"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="TripsURI" elementType="Argument">
<stringProp name="Argument.name">TripsURI</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("TripsURI"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="PoiURI" elementType="Argument">
<stringProp name="Argument.name">PoiURI</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("PoiURI"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</Arguments>
<hashTree/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">-1</intProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">5</stringProp>
<stringProp name="ThreadGroup.ramp_time">10</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">120</stringProp>
<stringProp name="ThreadGroup.delay">5</stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="POI Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value"></stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain">${PoiURI}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/poi/</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Trips Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${TripsURI}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/trips</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="UserJava Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${UserJavaUri}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/user-java</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="UserProfile Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${UserProfileUri}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/user</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@ -0,0 +1,25 @@
#!/bin/bash
# Set AZURE_DEVOPS_EXT_PAT with your PAT befor running this script
# export export AZURE_DEVOPS_EXT_PAT="YourPat"
# ./generic_endpoint.sh AdoOrganization AdoProject SvcEndpointName SvcEndpointUrl
AZURE_DEVOPS_ORGANIZATION=$1 # $(System.CollectionUri)
AZURE_DEVOPS_PROJECT=$2 # $(System.TeamProject)
SVC_ENDPOINT_NAME=$3
SVC_ENDPOINT_URL=$4
az devops configure --defaults organization="${AZURE_DEVOPS_ORGANIZATION}" project="${AZURE_DEVOPS_PROJECT}"
id=$(az devops service-endpoint list --query "[?name == '${SVC_ENDPOINT_NAME}'].id | join(', ', @)" --output tsv)
if [[ ${#id} == 0 ]]; then
payload=$(cat generic_endpoint_template.json)
echo $payload | jq -c -r '.name = "'${SVC_ENDPOINT_NAME}'" | .url = "'${SVC_ENDPOINT_URL}'"' > _endpoint.temp.json
id=$(az devops service-endpoint create --service-endpoint-configuration _endpoint.temp.json --output tsv --query id)
rm -f _endpoint.temp.json
az devops service-endpoint update --id ${id} --enable-for-all true > /dev/null
echo "${SVC_ENDPOINT_NAME} service endpoint creadted! id: ${id}"
else
echo "${SVC_ENDPOINT_NAME} service endpoint already exists!"
fi

View File

@ -0,0 +1,22 @@
{
"administratorsGroup": null,
"authorization": {
"scheme": "UsernamePassword",
"parameters": {
"username": "",
"password": ""
}
},
"createdBy": null,
"data": {},
"description": "",
"groupScopeId": null,
"name": "NAME",
"operationStatus": null,
"readersGroup": null,
"serviceEndpointProjectReferences": [],
"type": "generic",
"url": "URL",
"isShared": false,
"owner": "library"
}

View File

@ -0,0 +1,59 @@
#!/bin/bash
declare -i duration=5
declare endpoint
declare key
declare value
usage() {
cat <<END
healthcheck.sh endpoint key value
Report the health status of the endpoint. Exit 0 then OK.
END
}
if [[ $1 ]]; then
endpoint=$1
else
echo "Please specify the endpoint to scan"
usage
exit 1
fi
if [[ $2 ]]; then
key=$2
else
echo "Please specify the key that has to be queried"
usage
exit 1
fi
if [[ $3 ]]; then
value=$3
else
echo "Please specify the value that has to be expected"
usage
exit 1
fi
query() {
local endpoint=$1
local key=$2
result=$(curl --max-time 5 --silent --location "${endpoint}")
if jq -e . >/dev/null 2>&1 <<<"${result}"; then
echo "${result}" | jq -c -r '.'"${key}"''
fi
}
while [[ true ]]; do
result=$(query "${endpoint}" "${key}")
if [[ "${result}" == "${value}" ]]; then
echo true
exit 0
fi
sleep ${duration}
done

View File

@ -0,0 +1,64 @@
#!/bin/bash
declare -i duration=1
declare hasUrl=""
declare endpoint
usage() {
cat <<END
polling.sh [-i] [-h] endpoint
Report the health status of the endpoint
-i: include Uri for the format
-h: help
END
}
while getopts "ih" opt; do
case $opt in
i)
hasUrl=true
;;
h)
usage
exit 0
;;
\?)
echo "Unknown option: -${OPTARG}" >&2
exit 1
;;
esac
done
shift $((OPTIND -1))
if [[ $1 ]]; then
endpoint=$1
else
echo "Please specify the endpoint."
usage
exit 1
fi
healthcheck() {
declare url=$1
result=$(curl --silent --location --head --output /dev/null --write-out "%{http_code}" "${url}")
echo $result
}
while [[ true ]]; do
result=`healthcheck ${endpoint}`
declare status
if [[ -z ${result} ]]; then
status="N/A"
else
status=${result}
fi
timestamp=$(date "+%Y%m%d-%H%M%S")
if [[ -z ${hasUrl} ]]; then
echo "${timestamp} | ${status} "
else
echo "${timestamp} | ${status} | ${endpoint} "
fi
sleep ${duration}
done

View File

@ -0,0 +1,60 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
usage() { echo "Usage: send_msg -e <recipientEmail> -c <chatConnectionString> -q <chatMessageQueue> -m <message>" 1>&2; exit 1; }
declare recipientEmail=""
declare chatConnectionString=""
declare chatMessageQueue=""
declare message=""
# Initialize parameters specified from command line
while getopts ":e:c:q:m:" arg; do
case "${arg}" in
e)
recipientEmail=${OPTARG}
;;
c)
chatConnectionString=${OPTARG}
;;
q)
chatMessageQueue=${OPTARG}
;;
m)
message=${OPTARG}
;;
esac
done
shift $((OPTIND-1))
if [[ -z "$recipientEmail" ]]; then
echo "recipientEmail was not set properly"
read recipientEmail
fi
if [[ -z "$chatConnectionString" ]]; then
echo "chatConnectionString was not set properly"
read chatConnectionString
fi
if [[ -z "$chatMessageQueue" ]]; then
echo "chatMessageQueue was not set properly"
read chatMessageQueue
fi
if [[ -z "$message" ]]; then
echo "message was not set properly"
read message
fi
cd /home/azureuser/openhack-devops-proctor/provision-team/svcbusclient
# Restore the ServiceBus Package
dotnet add package Microsoft.Azure.ServiceBus --version 3.1.0
# build the servicebus client app
dotnet build
# send the message to servicebus
dotnet run $chatConnectionString $chatMessageQueue $recipientEmail $message

View File

@ -0,0 +1,85 @@
#!/bin/bash
# set -euo pipefail
IFS=$'\n\t'
usage() { echo "Usage: service_check.sh -d <dns host Url> -n <teamName> " 1>&2; exit 1; }
declare dnsUrl=""
declare teamName=""
# Initialize parameters specified from command line
while getopts ":d:n:" arg; do
case "${arg}" in
d)
dnsUrl=${OPTARG}
;;
n)
teamName=${OPTARG}
;;
esac
done
shift $((OPTIND-1))
#Prompt for parameters is some required parameters are missing
if [[ -z "$dnsUrl" ]]; then
echo "Public DNS address where the API will be hosted behind."
echo "Enter public DNS name."
read dnsUrl
[[ "${dnsUrl:?}" ]]
fi
if [[ -z "$teamName" ]]; then
echo "Enter a team name to be used in app provisioning:"
read teamName
fi
echo "Checking services for ([X] = PASSED):"
echo "Team Name:" $teamName
echo -e "DNS Url:" $dnsUrl"\n"
poi_URL=$dnsUrl"/api/healthcheck/poi"
user_URL=$dnsUrl"/api/healthcheck/user"
trips_URL=$dnsUrl"/api/healthcheck/trips"
user_java_URL=$dnsUrl"/api/healthcheck/user-java"
echo -e "Checking POI:\t"$poi_URL
echo -e "Checking USER:\t"$user_URL
echo -e "Checking TRIPS:\t"$trips_URL
echo -e "Checking USER JAVA:\t"$user_java_URL"\n"
status_code_poi=`curl -sL -w "%{http_code}\\n" "$poi_URL" -o /dev/null`
if [[ "$status_code_poi" == "200" ]]; then
echo "poi [X]"
else
echo "poi [ ]"
fi
status_code_user=`curl -sL -w "%{http_code}\\n" "$user_URL" -o /dev/null`
if [[ "$status_code_user" == "200" ]]; then
echo "user [X]"
else
echo "user [ ]"
fi
status_code_trips=`curl -sL -w "%{http_code}\\n" "$trips_URL" -o /dev/null`
if [[ "$status_code_trips" == "200" ]]; then
echo "trips [X]"
else
echo "trips [ ]"
fi
status_code_user_java=`curl -sL -w "%{http_code}\\n" "$user_java_URL" -o /dev/null`
if [[ "$status_code_user_java" == "200" ]]; then
echo "user-java [X]"
else
echo "user-java [ ]"
fi
if [[ "$status_code_poi" == "200" ]] && [[ "$status_code_user" == "200" ]] && [[ "$status_code_trips" == "200" ]] && [[ "$status_code_user_java" == "200" ]]; then
echo "All checks passed"
fi

View File

@ -0,0 +1,129 @@
<#
.SYNOPSIS
This script can be used to check the status of a classroom after is has been started in the Cloud Sandbox.
This script has specficially been authored to check the lab microsoft-open-hack-devops and will not currently validate any other OpenHack labs.
.DESCRIPTION
To use this script, you will need to navigate to a classroom in the Cloud Sandbox and enter the lab view.
From the lab view, click the List Credentials button, and then export the CSV.
This script will take the path of that script as in input and use the credentials to enumerate all of the subscriptions within it.
.EXAMPLE
./validate-deployment.ps1 -LabCredentialsFilePath $env:HOMEPATH\Downloads\credentials.csv
.NOTES
This script should only be run at one hour after you have initiated the lab. Running it prior to that will certainly lead to results which lead you to believe the lab has not provisioned successfully, when in fact it is probably just still spinning up.
.LINK
https://github.com/Azure-Samples/openhack-devops-proctor/
#>
Param (
[Parameter(Mandatory=$false)]
[String]
$LabCredentialsFilePath = "credentials.csv",
[Parameter(Mandatory=$false)]
[String]
$OutputFilePath = "classroom_checkresults.csv",
[switch]
$Force
)
if (-Not (Test-Path $LabCredentialsFilePath -PathType Leaf)) {
Write-Error -Message "Unable to find CSV at the path provided." -Category InvalidData
}
$InputFile = @(Import-Csv -Path $LabCredentialsFilePath -Header "PortalUsername","PortalPassword","AzureSubscriptionId","AzureDisplayName","AzureUsername","AzurePassword" | Where-Object AzureUserName -like "hacker*" | Sort-Object AzureSubscriptionId -Unique)
if (Test-Path $OutputFilePath -PathType Leaf) {
if ($Force) {
Remove-Item -Path $OutputFilePath
} else {
$_ = Read-Host "Found previous output. Would you like to delete it? (y/n)?"
if ($_.ToLower() -eq "y") {
Remove-Item -Path $OutputFilePath
}
}
}
Write-Host "Storing validation results at $OutputFilePath" -ForegroundColor Green
Add-Content -Path $OutputFilePath -Value '"SiteFound","POIFound","TripsFound","UserFound","UserJavaFound","TripViewerUrl","AzureUsername","AzurePassword","SubscriptionId","TenantURL"'
for ($i = 0; $i -lt $InputFile.Count; $i++) {
$_ = $InputFile[$i]
if ($_.AzureUsername -eq "Azure UserName" -and $_.AzurePassword -eq "Azure Password") {
continue;
}
$PortalUsername = $_.PortalUsername
$PortalPassword = $_.PortalPassword
$AzureUsername = $_.AzureUsername
$AzurePassword = $_.AzurePassword
$AzureSubscriptionId = $_.AzureSubscriptionId
$AzureDisplayName = $_.AzureDisplayName
$AzureSecurePassword = ConvertTo-SecureString $AzurePassword -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($AzureUsername, $AzureSecurePassword)
$TenantDomain = $AzureUsername.Split("@")[1]
$TenantUrl = "https://portal.azure.com/$TenantDomain"
Write-Host "Processing record for $AzureUsername" -ForegroundColor Yellow
$Account = Connect-AzAccount -Credential $Credential -Subscription $AzureSubscriptionId
$ResourceGroup = Get-AzResourceGroup | Where-Object ResourceGroupName -like "openhack*" | Select-Object -first 1
$ResourceGroupName = $ResourceGroup.ResourceGroupName
$TeamName = $ResourceGroupName -Replace ".{2}$"
$RowToAppend = '"True",'
$_poi = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)poi" }
$_trips = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)trips" }
$_userprofile = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)userprofile" }
$_userjava = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)userjava" }
$_tripviewer = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)tripviewer" }
$_status = Invoke-WebRequest "http://$($_poi.DefaultHostName)/api/healthcheck/poi" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$_status = Invoke-WebRequest "http://$($_trips.DefaultHostName)/api/healthcheck/trips" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$_status = Invoke-WebRequest "http://$($_userprofile.DefaultHostName)/api/healthcheck/user" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$_status = Invoke-WebRequest "http://$($_userjava.DefaultHostName)/api/healthcheck/user-java" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$RowToAppend += "`"http://$($_tripviewer.DefaultHostName)`",`"$PortalUsername`",`"$PortalPassword`",`"$AzureSubscriptionId`",`"$TenantUrl`""
Add-Content -Path $OutputFilePath -Value $RowToAppend
Write-Host "Done for $AzureUsername"
}

View File

@ -0,0 +1,112 @@
#!/bin/bash
# This script verifies the successfull deployment of the resources needed for the DevOps OpenHack.
# You need to provide the CSV file with all the credentials of the Azure subscriptions from the classroom management portal and a private / public SSH keypair that will be used to access the provisioning VMs
# The error log file is where will be logged the informations regarding the failed deployments. If not provided, it defaults to error.log.
#
# EXAMPLE
# ./validate-deployment.sh ./credentials.csv
# ./validate-deployment.sh ./credentials.csv --force
OLD_IFS=$IFS
CREDENTIALS_FILE_PATH=$1
FORCE_OVERWRITE=$2
RESULTS_FILE_PATH="./classcheckresults.csv"
IFS=','
[ ! -f $CREDENTIALS_FILE_PATH ] && { echo "$CREDENTIALS_FILE_PATH file not found"; exit 99; }
[ -f $RESULTS_FILE_PATH ] && {
[ -z $FORCE_OVERWRITE ] && {
echo "Found previous output ($RESULTS_FILE_PATH). Would you like to delete it?"
select yn in "Yes" "No"; do
case $yn in
Yes ) rm $RESULTS_FILE_PATH; break;;
No ) break;;
esac
done
}
[ ! -z $FORCE_OVERWRITE ] && {
rm $RESULTS_FILE_PATH
}
}
echo "Storing validation results at $RESULTS_FILE_PATH"
echo '"SiteFound","POIFound","TripsFound","UserFound","UserJavaFound","TripViewerUrl","AzureUsername","AzurePassword","SubscriptionId","TenantURL"' >> $RESULTS_FILE_PATH
while read PortalUsername PortalPassword AzureSubscriptionId AzureDisplayName AzureUsername AzurePassword
do
if [[ $PortalUsername = *Portal* ]]
then
echo "This is the header, skipping..."
elif [[ $AzureUserName = *hacker* ]]
then
echo "This is a hacker user, skipping..."
else
echo "PortalUsername $PortalUsername"
echo "PortalPassword $PortalPassword"
echo "AzureSubscriptionId $AzureSubscriptionId"
echo "AzureDisplayName $AzureDisplayName"
echo "AzureUsername $AzureUsername"
echo "AzurePassword $AzurePassword"
az login -u $AzureUsername -p $AzurePassword --output none
TENANT_URL="https://portal.azure.com/"
TENANT_URL+=`echo "$AzureUsername" | awk -F"@" '{print $2}'`
RESOURCE_GROUP_NAME=`az group list --query "[?starts_with(name,'openhack')]|[0]" | jq -r '.name'`
TEAM_NAME=${RESOURCE_GROUP_NAME%??}
ROW_TO_APPEND="\"True\","
FQDN_POI=`az webapp show --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}poi" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_TRIPS=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}trips" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_USER_JAVA=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}userjava" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_USER_PROFILE=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}userprofile" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_TRIP_VIEWER=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}tripviewer" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_POI/api/healthcheck/poi)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_TRIPS/api/healthcheck/trips)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_USER_PROFILE/api/healthcheck/user)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_USER_JAVA/api/healthcheck/user-java)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
ROW_TO_APPEND+="\"$FQDN_TRIP_VIEWER\",\"$PortalUsername\",\"$PortalPassword\",\"$AzureSubscriptionId\",\"$TENANT_URL\""
echo $ROW_TO_APPEND >> $RESULTS_FILE_PATH
echo "Done for $AzureUsername"
fi
done < $CREDENTIALS_FILE_PATH
IFS=$OLD_IFS