Skip to content

Commit 304f10c

Browse files
enhancement: support private networking (#87)
<!-- Thank you for submitting a Pull Request. Please fill out the template below.--> ## Overview/Summary This PR adds the capabilities for self-hosted agent and private networking for GitHub and Azure DevOps. The user can choose between: - Microsoft-hosted agents, public endpoint (no VNET) - self-hosted agents, public endpoint (no VNET) - self-hosted agents, private endpoint (yes VNET) ## This PR fixes/adds/changes/removes 1. #14 2. #38 3. #28 ### Breaking Changes This will be a major version and various variables have been updated and removed. ## Testing Evidence e2e tests run. These tests have now been extended to run the pipelines and actions, so now provide full coverage of all functionality. ## As part of this Pull Request I have - [x] Checked for duplicate [Pull Requests](https://github.com/Azure/alz-terraform-accelerator/pulls) - [x] Associated it with relevant [issues](https://github.com/Azure/alz-terraform-accelerator/issues), for tracking and closure. - [x] Ensured my code/branch is up-to-date with the latest changes in the `main` [branch](https://github.com/Azure/alz-terraform-accelerator/tree/main) - [x] Performed testing and provided evidence. - [x] Updated relevant and associated documentation.
1 parent 13013b4 commit 304f10c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1296
-247
lines changed
File renamed without changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This file can be used to clean up GitHub repositories if there has been an issue with the End to End tests.
2+
# CAUTION: Make sure you are connected to the correct organization before running this script!
3+
$repos = gh repo list microsoft-azure-landing-zones-cd-tests --json name,owner | ConvertFrom-Json
4+
5+
$repos | ForEach-Object -Parallel {
6+
$match = "*229*"
7+
$repoName = "$($_.owner.login)/$($_.name)"
8+
9+
if($repoName -like $match)
10+
{
11+
Write-Host "Deleting repo: $repoName"
12+
gh repo delete $repoName --yes
13+
14+
}
15+
} -ThrottleLimit 10
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# This file can be used to clean up Resource Groups if there has been an issue with the End to End tests.
2+
# CAUTION: Make sure you are connected to the correct subscription before running this script!
3+
az account show
4+
$resourceGroups = az group list --query "[?contains(name, '254-')]" | ConvertFrom-Json
5+
6+
$resourceGroups | ForEach-Object -Parallel {
7+
Write-Host "Deleting resource group: $($_.name)"
8+
az group delete --name $_.name --yes
9+
} -ThrottleLimit 10
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
param (
2+
[string]$organizationName,
3+
[string]$projectName,
4+
[string]$personalAccessToken,
5+
[string]$pipelineNamePart = "Continuous Delivery",
6+
[switch]$skipDestroy = $false,
7+
[int]$maximumRetries = 10,
8+
[int]$retryCount = 0,
9+
[int]$retryDelay = 10000
10+
)
11+
12+
function Invoke-Pipeline {
13+
param (
14+
[string]$organizationName,
15+
[string]$projectName,
16+
[int]$pipelineId,
17+
[string]$pipelineAction = "",
18+
[hashtable]$headers
19+
)
20+
$pipelineDispatchUrl = "https://dev.azure.com/$organizationName/$projectName/_apis/pipelines/$pipelineId/runs?api-version=7.2-preview.1"
21+
Write-Host "Pipeline Dispatch URL: $pipelineDispatchUrl"
22+
23+
$pipelineDispatchBody = @{}
24+
if($pipelineAction -eq "") {
25+
$pipelineDispatchBody = @{
26+
"resources" = @{
27+
"repositories" = @{
28+
"self" = @{
29+
"refName" = "refs/heads/main"
30+
}
31+
}
32+
}
33+
} | ConvertTo-Json -Depth 100
34+
} else {
35+
$pipelineDispatchBody = @{
36+
"resources" = @{
37+
"repositories" = @{
38+
"self" = @{
39+
"refName" = "refs/heads/main"
40+
}
41+
}
42+
}
43+
"templateParameters" = @{
44+
"terraform_action" = $pipelineAction
45+
}
46+
} | ConvertTo-Json -Depth 100
47+
}
48+
49+
$result = Invoke-RestMethod -Method POST -Uri $pipelineDispatchUrl -Headers $headers -Body $pipelineDispatchBody -StatusCodeVariable statusCode -ContentType "application/json"
50+
if ($statusCode -ne 200) {
51+
throw "Failed to dispatch the pipeline."
52+
}
53+
54+
# Get the pipeline run id
55+
$pipelineRunId = $result.id
56+
Write-Host "Pipeline Run ID: $pipelineRunId"
57+
return [int]$pipelineRunId
58+
}
59+
60+
function Wait-ForPipelineRunToComplete {
61+
param (
62+
[string]$organizationName,
63+
[string]$projectName,
64+
[int]$pipelineId,
65+
[int]$pipelineRunId,
66+
[hashtable]$headers
67+
)
68+
69+
$pipelineRunUrl = "https://dev.azure.com/$organizationName/$projectName/_apis/pipelines/$pipelineId/runs/$($pipelineRunId)?api-version=7.2-preview.1"
70+
Write-Host "Pipeline Run URL: $pipelineRunUrl"
71+
72+
$pipelineRunStatus = ""
73+
$pipelineRunResult = ""
74+
while($pipelineRunStatus -ne "completed") {
75+
Start-Sleep -Seconds 10
76+
$pipelineRun = Invoke-RestMethod -Method GET -Uri $pipelineRunUrl -Headers $headers -StatusCodeVariable statusCode
77+
if ($statusCode -lt 300) {
78+
$pipelineRunStatus = $pipelineRun.state
79+
$pipelineRunResult = $pipelineRun.result
80+
Write-Host "Pipeline Run Status: $pipelineRunStatus - Conclusion: $pipelineRunResult"
81+
} else {
82+
Write-Host "Failed to find the pipeline run. Status Code: $statusCode"
83+
throw "Failed to find the pipeline run."
84+
}
85+
}
86+
87+
if($pipelineRunResult -ne "succeeded") {
88+
throw "The pipeline run did not complete successfully. Conclusion: $pipelineRunResult"
89+
}
90+
}
91+
92+
# Setup Variables
93+
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$personalAccessToken"))
94+
$headers = @{
95+
"Authorization" = "Basic $token"
96+
"Accept" = "application/json"
97+
}
98+
99+
# Run the Module in a retry loop
100+
$success = $false
101+
102+
do {
103+
$retryCount++
104+
try {
105+
# Get the pipeline id
106+
Write-Host "Getting the pipeline id"
107+
$pipelinesUrl = "https://dev.azure.com/$organizationName/$projectName/_apis/pipelines?api-version=7.2-preview.1"
108+
Write-Host "Pipelines URL: $pipelinesUrl"
109+
$pipelines = Invoke-RestMethod -Method GET -Uri $pipelinesUrl -Headers $headers -StatusCodeVariable statusCode
110+
if ($statusCode -ne 200) {
111+
throw "Failed to find the pipelines."
112+
}
113+
$pipeline = $pipelines.value | Where-Object { $_.name -like "*$pipelineNamePart*" }
114+
115+
$pipelineId = $pipeline.id
116+
Write-Host "Pipeline ID: $pipelineId"
117+
118+
$pipelineAction = ""
119+
if(!($skipDestroy)) {
120+
$pipelineAction = "apply"
121+
}
122+
123+
# Trigger the apply pipeline
124+
Write-Host "Triggering the $pipelineAction pipeline"
125+
$pipelineRunId = Invoke-Pipeline -organizationName $organizationName -projectName $projectName -pipelineId $pipelineId -pipelineAction $pipelineAction -headers $headers
126+
Write-Host "$pipelineAction pipeline triggered successfully"
127+
128+
# Wait for the apply pipeline to complete
129+
Write-Host "Waiting for the $pipelineAction pipeline to complete"
130+
Wait-ForPipelineRunToComplete -organizationName $organizationName -projectName $projectName -pipelineId $pipelineId -pipelineRunId $pipelineRunId -headers $headers
131+
Write-Host "$pipelineAction pipeline completed successfully"
132+
133+
if($skipDestroy) {
134+
$success = $true
135+
break
136+
}
137+
138+
$pipelineAction = "destroy"
139+
140+
# Trigger the destroy pipeline
141+
Write-Host "Triggering the $pipelineAction pipeline"
142+
$pipelineRunId = Invoke-Pipeline -organizationName $organizationName -projectName $projectName -pipelineId $pipelineId -pipelineAction "destroy" -headers $headers
143+
Write-Host "$pipelineAction pipeline triggered successfully"
144+
145+
# Wait for the apply pipeline to complete
146+
Write-Host "Waiting for the $pipelineAction pipeline to complete"
147+
Wait-ForPipelineRunToComplete -organizationName $organizationName -projectName $projectName -pipelineId $pipelineId -pipelineRunId $pipelineRunId -headers $headers
148+
Write-Host "$pipelineAction pipeline completed successfully"
149+
150+
$success = $true
151+
} catch {
152+
Write-Host $_
153+
Write-Host "Failed to trigger the pipeline successfully, trying again..."
154+
}
155+
} while ($success -eq $false -and $retryCount -lt $maximumRetries)
156+
157+
if ($success -eq $false) {
158+
throw "Failed to trigger the pipeline after $maximumRetries attempts."
159+
}

tests/scripts/destroy.ps1 renamed to .github/tests/scripts/destroy.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ $success = $false
3131
do {
3232
$retryCount++
3333
try {
34+
$myIp = Invoke-RestMethod -Uri http://ipinfo.io/json | Select-Object -ExpandProperty ip
35+
Write-Host "Runner IP Address: $myIp"
36+
3437
Write-Host "Running Terraform Destroy"
3538
terraform -chdir="$bootstrapDirectoryPath" destroy -auto-approve -var-file="override.tfvars"
3639
if ($LastExitCode -eq 0) {
File renamed without changes.
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
param (
2+
[string]$organizationName,
3+
[string]$repositoryName,
4+
[string]$personalAccessToken,
5+
[string]$workflowFileName = "cd.yaml",
6+
[switch]$skipDestroy = $false,
7+
[int]$maximumRetries = 10,
8+
[int]$retryCount = 0,
9+
[int]$retryDelay = 10000
10+
)
11+
12+
function Invoke-Workflow {
13+
param (
14+
[string]$organizationName,
15+
[string]$repositoryName,
16+
[string]$workflowId,
17+
[string]$workflowAction = "",
18+
[hashtable]$headers
19+
)
20+
$workflowDispatchUrl = "https://api.github.com/repos/$organizationName/$repositoryName/actions/workflows/$workflowId/dispatches"
21+
Write-Host "Workflow Dispatch URL: $workflowDispatchUrl"
22+
23+
$workflowDispatchBody = @{}
24+
if($workflowAction -eq "") {
25+
$workflowDispatchBody = @{
26+
ref = "main"
27+
} | ConvertTo-Json -Depth 100
28+
} else {
29+
$workflowDispatchBody = @{
30+
ref = "main"
31+
inputs = @{
32+
terraform_action = $workflowAction
33+
}
34+
} | ConvertTo-Json -Depth 100
35+
}
36+
37+
$result = Invoke-RestMethod -Method POST -Uri $workflowDispatchUrl -Headers $headers -Body $workflowDispatchBody -StatusCodeVariable statusCode
38+
if ($statusCode -ne 204) {
39+
throw "Failed to dispatch the workflow. $result"
40+
}
41+
}
42+
43+
function Wait-ForWorkflowRunToComplete {
44+
param (
45+
[string]$organizationName,
46+
[string]$repositoryName,
47+
[hashtable]$headers
48+
)
49+
50+
$workflowRunUrl = "https://api.github.com/repos/$organizationName/$repositoryName/actions/runs"
51+
Write-Host "Workflow Run URL: $workflowRunUrl"
52+
53+
$workflowRunStatus = ""
54+
$workflowRunConclusion = ""
55+
while($workflowRunStatus -ne "completed") {
56+
Start-Sleep -Seconds 10
57+
58+
$workflowRun = Invoke-RestMethod -Method GET -Uri $workflowRunUrl -Headers $headers -StatusCodeVariable statusCode
59+
if ($statusCode -lt 300) {
60+
$workflowRunStatus = $workflowRun.workflow_runs[0].status
61+
$workflowRunConclusion = $workflowRun.workflow_runs[0].conclusion
62+
Write-Host "Workflow Run Status: $workflowRunStatus - Conclusion: $workflowRunConclusion"
63+
} else {
64+
Write-Host "Failed to find the workflow run. Status Code: $statusCode"
65+
throw "Failed to find the workflow run."
66+
}
67+
}
68+
69+
if($workflowRunConclusion -ne "success") {
70+
throw "The workflow run did not complete successfully. Conclusion: $workflowRunConclusion"
71+
}
72+
}
73+
74+
# Setup Variables
75+
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$personalAccessToken"))
76+
$headers = @{
77+
"Authorization" = "Basic $token"
78+
"Accept" = "application/vnd.github+json"
79+
}
80+
81+
# Run the Module in a retry loop
82+
$success = $false
83+
84+
do {
85+
$retryCount++
86+
try {
87+
# Get the workflow id
88+
Write-Host "Getting the workflow id"
89+
$workflowUrl = "https://api.github.com/repos/$organizationName/$repositoryName/actions/workflows/$workflowFileName"
90+
Write-Host "Workflow URL: $workflowUrl"
91+
$workflow = Invoke-RestMethod -Method GET -Uri $workflowUrl -Headers $headers -StatusCodeVariable statusCode
92+
if ($statusCode -ne 200) {
93+
throw "Failed to find the workflow."
94+
}
95+
$workflowId = $workflow.id
96+
Write-Host "Workflow ID: $workflowId"
97+
98+
$workflowAction = ""
99+
100+
if(!($skipDestroy)) {
101+
$workflowAction = "apply"
102+
}
103+
104+
# Trigger the apply workflow
105+
Write-Host "Triggering the $workflowAction workflow"
106+
Invoke-Workflow -organizationName $organizationName -repositoryName $repositoryName -workflowId $workflowId -workflowAction $workflowAction -headers $headers
107+
Write-Host "$workflowAction workflow triggered successfully"
108+
109+
# Wait for the apply workflow to complete
110+
Write-Host "Waiting for the $workflowAction workflow to complete"
111+
Wait-ForWorkflowRunToComplete -organizationName $organizationName -repositoryName $repositoryName -headers $headers
112+
Write-Host "$workflowAction workflow completed successfully"
113+
114+
if($skipDestroy) {
115+
$success = $true
116+
break
117+
}
118+
119+
$workflowAction = "destroy"
120+
121+
# Trigger the destroy workflow
122+
Write-Host "Triggering the $workflowAction workflow"
123+
Invoke-Workflow -organizationName $organizationName -repositoryName $repositoryName -workflowId $workflowId -workflowAction $workflowAction -headers $headers
124+
Write-Host "$workflowAction workflow triggered successfully"
125+
126+
# Wait for the apply workflow to complete
127+
Write-Host "Waiting for the $workflowAction workflow to complete"
128+
Wait-ForWorkflowRunToComplete -organizationName $organizationName -repositoryName $repositoryName -headers $headers
129+
Write-Host "$workflowAction workflow completed successfully"
130+
131+
$success = $true
132+
} catch {
133+
Write-Host $_
134+
Write-Host "Failed to trigger the workflow successfully, trying again..."
135+
}
136+
} while ($success -eq $false -and $retryCount -lt $maximumRetries)
137+
138+
if ($success -eq $false) {
139+
throw "Failed to trigger the workflow after $maximumRetries attempts."
140+
}

0 commit comments

Comments
 (0)