From 601da0d3aaf12b4ea77c21c287276ccccafd0fa0 Mon Sep 17 00:00:00 2001 From: Jonathan Idland Olsnes <73334350+Jonathanio123@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:17:58 +0200 Subject: [PATCH] chore: Update summary function app pipelines (#677) - [x] New feature - [ ] Bug fix - [ ] High impact **Description of work:** [AB#55574](https://statoil-proview.visualstudio.com/787035c2-8cf2-4d73-a83e-bb0e6d937eec/_workitems/edit/55574) Creates a deployment pipeline for the summary function app. Also updates the existing summary PR function. **Testing:** - [ ] ~~Can be tested~~ - [ ] ~~Automatic tests created / updated~~ - [ ] ~~Local tests are passing~~ Will need to run the infra pipeline to deploy the function app in ci-> **Checklist:** - [x] Considered automated tests - [x] Considered updating specification / documentation - [x] Considered work items - [x] Considered security - [x] ~~Performed developer testing~~ - [x] Checklist finalized / ready for review --- infrastructure/arm/environment.template.json | 33 +++- pipelines/summary-function-pipeline.yml | 161 ++++++++++++++++++ pipelines/summary-function-pr-pipeline.yml | 6 +- .../deploy-summary-function-pr-template.yml | 8 +- .../deploy-summary-function-template.yml | 100 +++++++++++ src/Fusion.Summary.Functions/Startup.cs | 2 +- 6 files changed, 303 insertions(+), 7 deletions(-) create mode 100644 pipelines/summary-function-pipeline.yml create mode 100644 pipelines/templates/deploy-summary-function-template.yml diff --git a/infrastructure/arm/environment.template.json b/infrastructure/arm/environment.template.json index 8f38d60fc..3e088788e 100644 --- a/infrastructure/arm/environment.template.json +++ b/infrastructure/arm/environment.template.json @@ -14,6 +14,7 @@ "ai-name": "[concat('ai-fap-resources-', variables('env-name'))]", "sb-name": "[concat('sb-fap-resources-', variables('env-name'))]", "function-name": "[concat('func-fap-resources-', variables('env-name'))]", + "summary-function-name": "[concat('func-fap-summary-', variables('env-name'))]", "function-hosting-plan-name": "[concat('fhplan-fap-resources-', variables('env-name'))]" // "id-rg-infra": "[concat('/subscriptions/', subscription().subscriptionId,'/resourcegroups/', 'plant-query-infra')]", }, @@ -148,7 +149,37 @@ } } }, - + /* FUNCTION APP SUMMARY */ + { + "apiVersion": "2015-08-01", + "type": "Microsoft.Web/sites", + "name": "[variables('summary-function-name')]", + "tags": { + "fusion-app": "summary", + "fusion-app-env": "[toLower(parameters('env-name'))]", + "fusion-app-component-type": "azFunc", + "fusion-app-component-id": "[concat('summary-func-', variables('env-name'))]", + "kv-msi-access": "true" + }, + "identity": { + "type": "SystemAssigned" + }, + "location": "[resourceGroup().location]", + "kind": "functionapp", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', variables('function-hosting-plan-name'))]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('function-hosting-plan-name'))]", + "httpsOnly": true, + "siteConfig": { + "phpVersion": "off", + "ftpsState": "FtpsOnly", + "minTlsVersion": "1.2", + "webSocketsEnabled": false + } + } + }, /* SERVICE BUS */ { "type": "Microsoft.ServiceBus/namespaces", diff --git a/pipelines/summary-function-pipeline.yml b/pipelines/summary-function-pipeline.yml new file mode 100644 index 000000000..cfb5cd9ec --- /dev/null +++ b/pipelines/summary-function-pipeline.yml @@ -0,0 +1,161 @@ +name: $(date:yyyyMMdd)$(rev:.r) + +pool: + vmImage: "ubuntu-latest" + +trigger: + branches: + include: + - master + paths: + include: + - src/Fusion.Summary.Functions/* + - src/Fusion.Resources.Functions.Common/* + +pr: none + +variables: + subscriptionServiceNonProd: "FRA Automation Non-Prod" + subscriptionServiceProd: "FRA Automation Prod" + webPackage: "$(Pipeline.Workspace)/drop/Fusion.Summary.Functions.zip" + +stages: + - template: templates/build-summary-function.yml + parameters: + project: "Fusion.Summary.Functions" + + - stage: DeployCI + displayName: CI + dependsOn: BuildFunction + condition: succeeded() + + variables: + environment: "ci" + functionServiceName: func-fap-summary-$(environment) + + jobs: + - deployment: Deploy + + displayName: "Deploy function app" + environment: fusion-ci + + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-summary-function-template.yml + parameters: + envName: $(environment) + clientId: "5a842df8-3238-415d-b168-9f16a6a6031b" + azureSubscription: $(subscriptionServiceNonProd) + + - task: AzureFunctionApp@1 + inputs: + azureSubscription: $(subscriptionServiceNonProd) + appType: "functionApp" + appName: $(functionServiceName) + package: $(webPackage) + deploymentMethod: "runFromPackage" + + - stage: DeployFQA + displayName: FQA + dependsOn: DeployCI + condition: succeeded() + + variables: + environment: "fqa" + functionServiceName: func-fap-summary-$(environment) + + jobs: + - deployment: Deploy + + displayName: "Deploy function app" + environment: fusion-resources-fqa + + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-summary-function-template.yml + parameters: + envName: $(environment) + clientId: "5a842df8-3238-415d-b168-9f16a6a6031b" + fusionEnvironment: fqa + azureSubscription: $(subscriptionServiceNonProd) + + - task: AzureFunctionApp@1 + inputs: + azureSubscription: $(subscriptionServiceNonProd) + appType: "functionApp" + appName: $(functionServiceName) + package: $(webPackage) + deploymentMethod: "runFromPackage" + + - stage: DeployTR + displayName: TR + dependsOn: DeployCI + condition: succeeded() + + variables: + environment: "tr" + functionServiceName: func-fap-summary-$(environment) + + jobs: + - deployment: Deploy + + displayName: "Deploy function app" + environment: fusion-resources-tr + + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-summary-function-template.yml + parameters: + envName: $(environment) + clientId: "5a842df8-3238-415d-b168-9f16a6a6031b" + fusionEnvironment: tr + azureSubscription: $(subscriptionServiceNonProd) + + - task: AzureFunctionApp@1 + inputs: + azureSubscription: $(subscriptionServiceNonProd) + appType: "functionApp" + appName: $(functionServiceName) + package: $(webPackage) + deploymentMethod: "runFromPackage" + + - stage: DeployFPRD + displayName: FPRD + dependsOn: DeployFQA + condition: succeeded() + + variables: + environment: "fprd" + functionServiceName: func-fap-summary-$(environment) + + jobs: + - deployment: Deploy + + displayName: "Deploy function app" + environment: fusion-prod + + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-summary-function-template.yml + parameters: + envName: $(environment) + clientId: "97978493-9777-4d48-b38a-67b0b9cd88d2" + fusionResource: "97978493-9777-4d48-b38a-67b0b9cd88d2" + fusionEnvironment: fprd + azureSubscription: $(subscriptionServiceProd) + + - task: AzureFunctionApp@1 + inputs: + azureSubscription: $(subscriptionServiceProd) + appType: "functionApp" + appName: $(functionServiceName) + package: $(webPackage) + deploymentMethod: "runFromPackage" diff --git a/pipelines/summary-function-pr-pipeline.yml b/pipelines/summary-function-pr-pipeline.yml index eb85008f0..4372913ea 100644 --- a/pipelines/summary-function-pr-pipeline.yml +++ b/pipelines/summary-function-pr-pipeline.yml @@ -12,9 +12,10 @@ pr: paths: include: - src/Fusion.Summary.Functions/* + - src/Fusion.Resources.Functions.Common/* variables: - subscriptionService: 'PROJECT_PORTAL (63b791ae-b2bc-41a1-ac66-806c4e69bffe)' + subscriptionService: 'FRA Automation Non-Prod' webPackage: '$(Pipeline.Workspace)/drop/Fusion.Summary.Functions.zip' prNumber: $(System.PullRequest.PullRequestNumber) @@ -37,7 +38,7 @@ stages: - deployment: Deploy displayName: 'Deploy function app' - environment: fusion-pr + environment: fra-pr strategy: runOnce: @@ -48,6 +49,7 @@ stages: envName: $(environment) clientId: '5a842df8-3238-415d-b168-9f16a6a6031b' pullRequestNumber: $(prNumber) + azureSubscription: $(subscriptionService) - task: AzureFunctionApp@1 inputs: diff --git a/pipelines/templates/deploy-summary-function-pr-template.yml b/pipelines/templates/deploy-summary-function-pr-template.yml index fff734044..b641db472 100644 --- a/pipelines/templates/deploy-summary-function-pr-template.yml +++ b/pipelines/templates/deploy-summary-function-pr-template.yml @@ -12,13 +12,15 @@ parameters: fusionResource: '5a842df8-3238-415d-b168-9f16a6a6031b' templateFile: $(Build.SourcesDirectory)/src/Fusion.Summary.Functions/Deployment/function.template.json disabledFunctionsFile: $(Build.SourcesDirectory)/src/Fusion.Summary.Functions/Deployment/disabled-functions.json + azureSubscription: 'PROJECT_PORTAL (63b791ae-b2bc-41a1-ac66-806c4e69bffe)' + steps: - checkout: self -- task: AzurePowerShell@4 +- task: AzurePowerShell@5 displayName: 'Deploy Function ARM template' inputs: - azureSubscription: 'PROJECT_PORTAL (63b791ae-b2bc-41a1-ac66-806c4e69bffe)' + azureSubscription: ${{ parameters.azureSubscription }} ScriptType: 'InlineScript' FailOnStandardError: true azurePowerShellVersion: 'LatestVersion' @@ -65,7 +67,7 @@ steps: fusion = "${{ parameters.fusionResource }}" } queues = @{ - departmentSummaryWeeklyQueue = "department-summary-weekly-queue" + departmentSummaryWeeklyQueue = "scheduled-weekly-department-report" } } diff --git a/pipelines/templates/deploy-summary-function-template.yml b/pipelines/templates/deploy-summary-function-template.yml new file mode 100644 index 000000000..afc6b8550 --- /dev/null +++ b/pipelines/templates/deploy-summary-function-template.yml @@ -0,0 +1,100 @@ +parameters: + envName: '' + clientId: '' + fusionEnvironment: 'ci' + fusionResource: '5a842df8-3238-415d-b168-9f16a6a6031b' + templateFile: $(Build.SourcesDirectory)/src/Fusion.Summary.Functions/Deployment/function.template.json + disabledFunctionsFile: $(Build.SourcesDirectory)/src/Fusion.Summary.Functions/Deployment/disabled-functions.json + azureSubscription: 'PROJECT_PORTAL (63b791ae-b2bc-41a1-ac66-806c4e69bffe)' + +steps: +- checkout: self +- task: AzurePowerShell@5 + displayName: 'Deploy Function ARM template' + inputs: + azureSubscription: ${{ parameters.azureSubscription }} + ScriptType: 'InlineScript' + FailOnStandardError: true + azurePowerShellVersion: 'LatestVersion' + Inline: | + $environment = "${{ parameters.envName }}" + $fusionEnvironment = "${{ parameters.fusionEnvironment }}" + $functionAppName = "func-fap-summary-$environment" + $envVaultName = "kv-fap-resources-$environment" + $envResourceGroup = Get-AzResourceGroup -Tag @{ "fusion-app-component" = "resources-rg-$environment" } + + if ($envResourceGroup -eq $null) { throw "Cannot locate resource group for environment '$environment'" } + + $resourceGroup = $envResourceGroup.ResourceGroupName + Write-Host "Using resource group $resourceGroup" + + function Get-SecretsId($secret) { + $value = (Get-AzKeyVaultSecret -VaultName $envVaultName -Name $secret) + if ($value.Id -eq $null) { return "" } else { return $value.Id.replace($value.Version,'') } + } + + # + # Generate the app settings + # + # Sett correct resources URI based on environment + $resourcesFunctionUri = "https://resources-api.$environment.fusion-dev.net/" + $summaryFunctionUri = "https://summary-api.$environment.fusion-dev.net/" + + if ($environment -eq "fprd") { + $resourcesFunctionUri = "https://fap-resources-api-fprd.azurewebsites.net/" + $summaryFunctionUri = "https://fap-summary-api-fprd.azurewebsites.net/" + } + + $settings = @{ + clientId = "${{ parameters.clientId }}" + secretIds = @{ + clientSecret = Get-SecretsId -secret AzureAd--ClientSecret + serviceBus = Get-SecretsId -secret Connectionstrings--ServiceBus + } + endpoints = @{ + lineorg = "https://fusion-s-lineorg-$fusionEnvironment.azurewebsites.net" + org = "https://fusion-s-org-$fusionEnvironment.azurewebsites.net" + people = "https://fusion-s-people-$fusionEnvironment.azurewebsites.net" + resources = "$resourcesFunctionUri" + summary = "$summaryFunctionUri" + notifications = "https://fusion-s-notification-$fusionEnvironment.azurewebsites.net" + context = "https://fusion-s-context-$fusionEnvironment.azurewebsites.net" + portal = "https://fusion-s-portal-$fusionEnvironment.azurewebsites.net" + } + resources = @{ + fusion = "${{ parameters.fusionResource }}" + } + queues = @{ + departmentSummaryWeeklyQueue = "scheduled-weekly-department-report" + } + } + + if ($fusionEnvironment -eq "fprd") { + $settings.endpoints.portal = "https://fusion.equinor.com" + } + + New-AzResourceGroupDeployment -Mode Incremental -Name "summary-function" -ResourceGroupName $resourceGroup -TemplateFile "${{ parameters.templateFile }}" ` + -env-name $environment ` + -settings $settings + + $functionApp = Get-AzWebApp -ResourceGroupName $resourceGroup -Name $functionAppName + Set-AzKeyVaultAccessPolicy -VaultName $envVaultName -ResourceGroupName $resourceGroup -ObjectId $functionApp.Identity.PrincipalId -PermissionsToSecrets get + + ## Load disabled functions + $disabledFunctionConfig = ConvertFrom-Json (Get-Content "${{ parameters.disabledFunctionsFile }}" -Raw) + $disabledFunctions = $disabledFunctionConfig | where -Property environment -eq $environment | Select -expandproperty disabledFunctions + + Write-Host "Disabled functions" + $disabledFunctions + + $settings = @{} + ForEach ($kvp in $functionApp.SiteConfig.AppSettings) { + $settings[$kvp.Name] = $kvp.Value + } + + ## Mark functions as disabled + $disabledFunctions | ForEach-Object { $settings["AzureWebJobs.$_.Disabled"] = "true" } + + ## Update web app settings for function app + Set-AzWebApp -ResourceGroupName $resourceGroup -Name $functionAppName -AppSettings $settings + diff --git a/src/Fusion.Summary.Functions/Startup.cs b/src/Fusion.Summary.Functions/Startup.cs index 9c1a95ec9..265692135 100644 --- a/src/Fusion.Summary.Functions/Startup.cs +++ b/src/Fusion.Summary.Functions/Startup.cs @@ -16,7 +16,7 @@ public override void Configure(IFunctionsHostBuilder builder) opts.Secret = cfg.GetValue("AzureAd_Secret"); opts.TenantId = cfg.GetValue("AzureAd_TenantId"); }); - + builder.Services.AddConfigServiceResolver(); builder.Services.AddHttpClients(); }