Skip to content

Commit b51d3ea

Browse files
authored
Add webapi controller for devops POST webhook (#8167)
1 parent 9e7f6fc commit b51d3ea

File tree

5 files changed

+90
-4
lines changed

5 files changed

+90
-4
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System.Text.Json;
2+
using System.Threading.Tasks;
3+
using Azure.Sdk.Tools.PipelineWitness.Configuration;
4+
using Azure.Storage.Queues;
5+
using Azure.Storage.Queues.Models;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.AspNetCore.Mvc;
8+
using Microsoft.Extensions.Logging;
9+
using Microsoft.Extensions.Options;
10+
11+
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
12+
13+
namespace Azure.Sdk.Tools.PipelineWitness.Controllers
14+
{
15+
[Route("api/devopsevents")]
16+
[ApiController]
17+
public class DevopsEventsController : ControllerBase
18+
{
19+
private readonly QueueClient queueClient;
20+
private readonly ILogger<DevopsEventsController> logger;
21+
22+
public DevopsEventsController(ILogger<DevopsEventsController> logger, QueueServiceClient queueServiceClient, IOptions<PipelineWitnessSettings> options)
23+
{
24+
this.queueClient = queueServiceClient.GetQueueClient(options.Value.BuildCompleteQueueName);
25+
this.logger = logger;
26+
}
27+
28+
// POST api/devopsevents
29+
[HttpPost]
30+
public async Task PostAsync([FromBody] JsonDocument value)
31+
{
32+
if (value == null) {
33+
throw new BadHttpRequestException("Missing payload", 400);
34+
}
35+
36+
this.logger.LogInformation("Message received in DevopsEventsController.PostAsync");
37+
string message = value.RootElement.GetRawText();
38+
39+
if (value.RootElement.TryGetProperty("resource", out var resource)
40+
&& resource.TryGetProperty("url", out var url)
41+
&& url.GetString().StartsWith("https://dev.azure.com/azure-sdk/"))
42+
{
43+
SendReceipt response = await this.queueClient.SendMessageAsync(message);
44+
this.logger.LogInformation("Message added to queue with id {MessageId}", response.MessageId);
45+
}
46+
else
47+
{
48+
this.logger.LogError("Message content invalid: {Content}", message);
49+
throw new BadHttpRequestException("Invalid payload", 400);
50+
}
51+
}
52+
}
53+
}

tools/pipeline-witness/Azure.Sdk.Tools.PipelineWitness/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public static async Task Main(params string[] args)
1919
// Add services to the container.
2020
builder.Services.AddControllers();
2121
builder.Services.AddHealthChecks();
22+
builder.Services.AddHttpLogging(options => { });
2223

2324
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
2425
builder.Services.AddEndpointsApiExplorer();
@@ -43,6 +44,8 @@ public static async Task Main(params string[] args)
4344

4445
app.UseHealthChecks("/");
4546

47+
app.UseHttpLogging();
48+
4649
await app.RunAsync();
4750
}
4851
}

tools/pipeline-witness/Azure.Sdk.Tools.PipelineWitness/appsettings.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"LogLevel": {
44
"Default": "Warning",
55
"Microsoft.Hosting": "Information",
6-
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information",
76
"Azure.Sdk.Tools.PipelineWitness": "Debug",
87
"Azure.Core": "Error"
98
},

tools/pipeline-witness/infrastructure/Assign-StoragePermissions.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ try {
1818
$subscriptionName = $target -eq 'test' ? 'Azure SDK Developer Playground' : 'Azure SDK Engineering System'
1919
Write-Host "Setting subscription to '$subscriptionName'"
2020
Invoke "az account set --subscription '$subscriptionName' --output none"
21+
$subscriptionId = az account show --query id -o tsv
2122

2223
$parametersFile = "./bicep/parameters.$target.json"
2324
Write-Host "Reading parameters from $parametersFile"
@@ -30,7 +31,7 @@ try {
3031

3132
Write-Host "Adding Azure SDK Engineering System Team RBAC access to storage resources:`n" + `
3233
" Blob: $logsResourceGroupName/$logsStorageAccountName`n" + `
33-
" Queue: `n" + `
34+
" Queue: $appResourceGroupName/$appStorageAccountName`n" + `
3435
" Cosmos: $appResourceGroupName/$cosmosAccountName`n"
3536

3637
Write-Host "Getting group id for Azure SDK Engineering System Team"

tools/pipeline-witness/infrastructure/bicep/logsResourceGroup.bicep

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,16 @@ resource kustoDataConnections 'Microsoft.Kusto/Clusters/Databases/DataConnection
249249
dataFormat: 'JSON'
250250
blobStorageEventType: 'Microsoft.Storage.BlobCreated'
251251
databaseRouting: 'Single'
252+
managedIdentityResourceId: kustoCluster.id
252253
}
253254
dependsOn: [ kustoScriptInvocation ]
254255
}]
255256

256-
// Assign Storage Blob Data Contributor role for the Web App on the Logs Storage Account
257+
// Assign roles to the Kusto cluster and App Service
257258
resource blobContributorRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
258259
scope: subscription()
259-
// This is the Storage Blob Data Contributor role, which is the minimum role permission we can give.
260+
// This is the Storage Blob Data Contributor role.
261+
// Read, write, and delete Azure Storage containers and blobs
260262
// See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#storage
261263
name: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
262264
}
@@ -270,3 +272,31 @@ resource storageRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-
270272
description: 'Blob Contributor for PipelineWitness'
271273
}
272274
}
275+
276+
resource kustoStorageAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
277+
name: guid(blobContributorRoleDefinition.id, kustoClusterName, logsStorageAccount.id)
278+
scope: logsStorageAccount
279+
properties:{
280+
principalId: kustoCluster.identity.principalId
281+
roleDefinitionId: blobContributorRoleDefinition.id
282+
description: 'Blob Contributor for Kusto ingestion'
283+
}
284+
}
285+
286+
resource eventHubsDataReceiverRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
287+
scope: subscription()
288+
// This is the Event Hubs Data Receiver role
289+
// Allows receive access to Azure Event Hubs resources.
290+
// see https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#analytics
291+
name: 'a638d3c7-ab3a-418d-83e6-5f17a39d4fde'
292+
}
293+
294+
resource kustoEventHubsAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
295+
name: guid(blobContributorRoleDefinition.id, kustoClusterName, eventHubNamespace.id)
296+
scope: eventHubNamespace
297+
properties:{
298+
principalId: kustoCluster.identity.principalId
299+
roleDefinitionId: eventHubsDataReceiverRoleDefinition.id
300+
description: 'Blob Contributor for Kusto ingestion'
301+
}
302+
}

0 commit comments

Comments
 (0)