Merged in feature/redis (pull request #1478)
Distributed cache * cache deleteKey now uses an options object instead of a lonely argument variable fuzzy * merge * remove debug logs and cleanup * cleanup * add fault handling * add fault handling * add pid when logging redis client creation * add identifier when logging redis client creation * cleanup * feat: add redis-api as it's own app * feature: use http wrapper for redis * feat: add the possibility to fallback to unstable_cache * Add error handling if redis cache is unresponsive * add logging for unstable_cache * merge * don't cache errors * fix: metadatabase on branchdeploys * Handle when /en/destinations throws add ErrorBoundary * Add sentry-logging when ErrorBoundary catches exception * Fix error handling for distributed cache * cleanup code * Added Application Insights back * Update generateApiKeys script and remove duplicate * Merge branch 'feature/redis' of bitbucket.org:scandic-swap/web into feature/redis * merge Approved-by: Linus Flood
This commit is contained in:
committed by
Linus Flood
parent
a8304e543e
commit
fa63b20ed0
103
apps/redis-api/ci/azure-pipelines.build.yml
Normal file
103
apps/redis-api/ci/azure-pipelines.build.yml
Normal file
@@ -0,0 +1,103 @@
|
||||
# Docker
|
||||
# Build a Docker image
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker
|
||||
name: 1.0.0-$(SourceBranchName)-$(Rev:r)
|
||||
|
||||
trigger:
|
||||
- main
|
||||
|
||||
parameters:
|
||||
- name: forcePush
|
||||
displayName: Force push
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
resources:
|
||||
- repo: self
|
||||
variables:
|
||||
tag: "$(Build.BuildNumber)"
|
||||
imageName: "redis-api"
|
||||
isMaster: $[eq(variables['Build.SourceBranchName'], 'master')]
|
||||
shouldPush: $[or(eq(${{parameters.forcePush}}, True), eq(variables['isMaster'], True))]
|
||||
tags: |
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
displayName: Set version
|
||||
jobs:
|
||||
- job: CreateArtifact
|
||||
displayName: Create version artifact
|
||||
steps:
|
||||
- task: Bash@3
|
||||
displayName: Write buildnumber
|
||||
inputs:
|
||||
targetType: "inline"
|
||||
script: |
|
||||
echo '$(Build.BuildNumber)' > $(Pipeline.Workspace)/.version
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: "$(Pipeline.Workspace)/.version"
|
||||
artifact: "Version"
|
||||
publishLocation: "pipeline"
|
||||
- task: Bash@3
|
||||
displayName: Add tag main-latest if main branch
|
||||
inputs:
|
||||
targetType: "inline"
|
||||
script: |
|
||||
localTags = $(tag)
|
||||
localTags += "\nlatest"
|
||||
if [ $[isMaster] ]; then
|
||||
localTags += "\nlatest-main"
|
||||
echo -e "##vso[task.setvariable variable=tags;]$localTags"
|
||||
fi
|
||||
echo -e $localTags
|
||||
|
||||
- job: Build
|
||||
displayName: Build
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: "inline"
|
||||
script: |
|
||||
echo "VERSION=$(tag)" >> .env.production
|
||||
echo "ShouldPush=$(shouldPush)"
|
||||
echo "ForcePush=${{ parameters.forcePush }}"
|
||||
echo "isMaster=$(isMaster)"
|
||||
|
||||
- task: AzureCLI@2
|
||||
displayName: Login to ACR
|
||||
inputs:
|
||||
azureSubscription: "mi-devops"
|
||||
scriptType: "bash"
|
||||
scriptLocation: "inlineScript"
|
||||
workingDirectory: "$(build.sourcesDirectory)"
|
||||
inlineScript: az acr login --name acrscandicfrontend
|
||||
|
||||
- task: AzureCLI@2
|
||||
displayName: Build and push to ACR
|
||||
inputs:
|
||||
azureSubscription: "mi-devops"
|
||||
scriptType: "bash"
|
||||
scriptLocation: "inlineScript"
|
||||
workingDirectory: "$(build.sourcesDirectory)"
|
||||
inlineScript: |
|
||||
if [ "$(shouldPush)" != "True" ]; then
|
||||
echo "Not pushing to ACR"
|
||||
noPush="--no-push"
|
||||
else
|
||||
echo "Pushing to ACR"
|
||||
noPush=""
|
||||
fi
|
||||
|
||||
echo "isMaster: $(isMaster)"
|
||||
|
||||
if [ "$(isMaster)" == "True" ]; then
|
||||
echo "Building with latest tag"
|
||||
az acr build . --image $(imageName):latest -r acrscandicfrontend $noPush
|
||||
fi
|
||||
|
||||
echo "Building with $(tag) tag"
|
||||
az acr build . --image $(imageName):$(tag) -r acrscandicfrontend $noPush
|
||||
44
apps/redis-api/ci/azure-pipelines.deploy.yml
Normal file
44
apps/redis-api/ci/azure-pipelines.deploy.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
resources:
|
||||
pipelines:
|
||||
- pipeline: buildPipeline
|
||||
source: "Build App BFF"
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
|
||||
parameters:
|
||||
- name: containerTag
|
||||
displayName: Select tag to deploy
|
||||
type: string
|
||||
default: "latest"
|
||||
|
||||
variables:
|
||||
- name: containerTag
|
||||
value: ${{ parameters.containerTag }}
|
||||
|
||||
stages:
|
||||
- stage: Deploy_test
|
||||
variables:
|
||||
- group: "BFF test"
|
||||
jobs:
|
||||
- template: ./azure-pipelines.deploywebapptemplate.yml
|
||||
parameters:
|
||||
environment: test
|
||||
subscriptionId: 1a126a59-4703-4e36-ad7b-2503d36526c0
|
||||
containerTag: $(containerTag)
|
||||
# - stage: Deploy_prod
|
||||
# variables:
|
||||
# - group: 'BFF prod'
|
||||
# jobs:
|
||||
# - template: ./azure-pipelines.deploywebapptemplate.yml
|
||||
# parameters:
|
||||
# environment: prod
|
||||
# subscriptionId: 1e6ef69e-8719-4924-a311-e66fe00399c7
|
||||
# containerTag: $(containerTag)
|
||||
75
apps/redis-api/ci/bicep/app/containerApp.bicep
Normal file
75
apps/redis-api/ci/bicep/app/containerApp.bicep
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Environment, EnvironmentVar } from '../types.bicep'
|
||||
|
||||
param environment Environment
|
||||
param location string
|
||||
param containerAppName string
|
||||
param containerImage string
|
||||
param containerPort int
|
||||
param minReplicas int = 1
|
||||
param maxReplicas int = 3
|
||||
param envVars EnvironmentVar[] = []
|
||||
param userAssignedIdentityId string
|
||||
|
||||
resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' existing = {
|
||||
name: 'acrscandicfrontend'
|
||||
scope: resourceGroup('1e6ef69e-8719-4924-a311-e66fe00399c7', 'rg-shared')
|
||||
}
|
||||
|
||||
resource containerApp 'Microsoft.App/containerApps@2024-10-02-preview' = {
|
||||
name: containerAppName
|
||||
location: location
|
||||
identity: {
|
||||
type: 'UserAssigned'
|
||||
userAssignedIdentities: {
|
||||
'${userAssignedIdentityId}': {}
|
||||
}
|
||||
}
|
||||
properties: {
|
||||
environmentId: resourceId('Microsoft.App/managedEnvironments', 'cae-redis-api-${environment}')
|
||||
configuration: {
|
||||
activeRevisionsMode: 'Single'
|
||||
registries: [
|
||||
{
|
||||
identity: userAssignedIdentityId
|
||||
server: acr.properties.loginServer
|
||||
}
|
||||
]
|
||||
ingress: {
|
||||
external: true
|
||||
targetPort: containerPort
|
||||
}
|
||||
}
|
||||
template: {
|
||||
containers: [
|
||||
{
|
||||
name: containerAppName
|
||||
image: containerImage
|
||||
imageType: 'ContainerImage'
|
||||
env: [
|
||||
for envVar in envVars: {
|
||||
name: envVar.name
|
||||
value: envVar.value
|
||||
}
|
||||
]
|
||||
probes: [
|
||||
{
|
||||
type: 'Liveness'
|
||||
httpGet: {
|
||||
port: containerPort
|
||||
path: '/health'
|
||||
}
|
||||
}
|
||||
]
|
||||
resources: {
|
||||
cpu: json('0.25')
|
||||
memory: '0.5Gi'
|
||||
}
|
||||
}
|
||||
]
|
||||
scale: {
|
||||
minReplicas: minReplicas
|
||||
maxReplicas: maxReplicas
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
apps/redis-api/ci/bicep/app/main.bicep
Normal file
42
apps/redis-api/ci/bicep/app/main.bicep
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Environment, EnvironmentVar } from '../types.bicep'
|
||||
|
||||
targetScope = 'subscription'
|
||||
|
||||
param environment Environment
|
||||
param containerImageTag string
|
||||
param redisConnection string
|
||||
param primaryApiKey string
|
||||
param secondaryApiKey string
|
||||
|
||||
param timestamp string = utcNow()
|
||||
|
||||
@description('The location for the resource group')
|
||||
param location string = 'westeurope'
|
||||
|
||||
resource rgRedisApi 'Microsoft.Resources/resourceGroups@2021-04-01' existing = {
|
||||
name: 'rg-redis-api-${environment}'
|
||||
}
|
||||
|
||||
resource mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
|
||||
name: 'mi-redis-api-${environment}'
|
||||
scope: rgRedisApi
|
||||
}
|
||||
|
||||
module containerApp 'containerApp.bicep' = {
|
||||
name: 'containerApp'
|
||||
scope: rgRedisApi
|
||||
params: {
|
||||
location: location
|
||||
environment: environment
|
||||
userAssignedIdentityId: mi.id
|
||||
containerAppName: 'ca-redis-api-${environment}'
|
||||
containerImage: 'acrscandicfrontend.azurecr.io/redis-api:${containerImageTag}'
|
||||
containerPort: 3001
|
||||
envVars: [
|
||||
{ name: 'REDIS_CONNECTION', value: redisConnection }
|
||||
{ name: 'PRIMARY_API_KEY', value: primaryApiKey }
|
||||
{ name: 'SECONDARY_API_KEY', value: secondaryApiKey }
|
||||
{ name: 'timestamp', value: timestamp }
|
||||
]
|
||||
}
|
||||
}
|
||||
49
apps/redis-api/ci/bicep/cache/redis.bicep
vendored
Normal file
49
apps/redis-api/ci/bicep/cache/redis.bicep
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Environment } from '../types.bicep'
|
||||
|
||||
param environment Environment
|
||||
|
||||
@description('The location for the resource group')
|
||||
param location string = 'westeurope'
|
||||
|
||||
var testSKU = {
|
||||
name: 'Basic'
|
||||
family: 'C'
|
||||
capacity: 0
|
||||
}
|
||||
|
||||
var prodSKU = {
|
||||
name: 'Standard'
|
||||
family: 'C'
|
||||
capacity: 1
|
||||
}
|
||||
|
||||
var sku = environment == 'prod' ? prodSKU : testSKU
|
||||
|
||||
resource redisResource 'Microsoft.Cache/Redis@2024-11-01' = {
|
||||
name: 'redis-scandic-frontend-${environment}'
|
||||
location: location
|
||||
properties: {
|
||||
redisVersion: '6.0'
|
||||
sku: {
|
||||
name: sku.name
|
||||
family: sku.family
|
||||
capacity: sku.capacity
|
||||
}
|
||||
enableNonSslPort: false
|
||||
minimumTlsVersion: '1.2'
|
||||
publicNetworkAccess: 'Enabled'
|
||||
redisConfiguration: {
|
||||
'aad-enabled': 'false'
|
||||
'maxmemory-reserved': '30'
|
||||
'maxfragmentationmemory-reserved': '30'
|
||||
'maxmemory-delta': '30'
|
||||
}
|
||||
updateChannel: 'Stable'
|
||||
disableAccessKeyAuthentication: false
|
||||
}
|
||||
}
|
||||
|
||||
output hostname string = redisResource.properties.hostName
|
||||
output connectionString string = '${redisResource.properties.hostName}:6380,password=${redisResource.properties.accessKeys.primaryKey},ssl=True,abortConnect=False'
|
||||
|
||||
output primaryAccessKey string = redisResource.properties.accessKeys.primaryKey
|
||||
19
apps/redis-api/ci/bicep/infra/allow-acr-pull.bicep
Normal file
19
apps/redis-api/ci/bicep/infra/allow-acr-pull.bicep
Normal file
@@ -0,0 +1,19 @@
|
||||
param principalId string
|
||||
|
||||
module acrPull '../roles/acr-pull.bicep' = {
|
||||
name: 'acrPull'
|
||||
}
|
||||
|
||||
resource registry 'Microsoft.ContainerRegistry/registries@2023-07-01' existing = {
|
||||
name: 'acrscandicfrontend'
|
||||
}
|
||||
|
||||
resource rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
||||
name: guid(registry.name, 'ServicePrincipal', principalId, acrPull.name)
|
||||
scope: registry
|
||||
properties: {
|
||||
principalType: 'ServicePrincipal'
|
||||
principalId: principalId
|
||||
roleDefinitionId: acrPull.outputs.id
|
||||
}
|
||||
}
|
||||
26
apps/redis-api/ci/bicep/infra/containerEnvironment.bicep
Normal file
26
apps/redis-api/ci/bicep/infra/containerEnvironment.bicep
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Environment } from '../types.bicep'
|
||||
|
||||
param location string = 'westeurope'
|
||||
param environment Environment
|
||||
param userAssignedIdentityId string
|
||||
|
||||
resource containerEnv 'Microsoft.App/managedEnvironments@2024-02-02-preview' = {
|
||||
name: 'cae-redis-api-${environment}'
|
||||
location: location
|
||||
identity: {
|
||||
type: 'UserAssigned'
|
||||
userAssignedIdentities: {
|
||||
'${userAssignedIdentityId}': {}
|
||||
}
|
||||
}
|
||||
properties: {
|
||||
publicNetworkAccess: 'Enabled'
|
||||
workloadProfiles: [
|
||||
{
|
||||
name: 'Consumption'
|
||||
workloadProfileType: 'Consumption'
|
||||
}
|
||||
]
|
||||
zoneRedundant: false
|
||||
}
|
||||
}
|
||||
40
apps/redis-api/ci/bicep/infra/main.bicep
Normal file
40
apps/redis-api/ci/bicep/infra/main.bicep
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Environment } from '../types.bicep'
|
||||
|
||||
targetScope = 'subscription'
|
||||
|
||||
param environment Environment
|
||||
|
||||
var location = deployment().location
|
||||
var productionSubscriptionId = '799cbffe-5209-41fd-adf9-4ffa3d1feead'
|
||||
|
||||
resource rgBff 'Microsoft.Resources/resourceGroups@2021-04-01' = {
|
||||
name: 'rg-redis-api-${environment}'
|
||||
location: location
|
||||
}
|
||||
|
||||
module mi '../managedIdentity.bicep' = {
|
||||
name: 'mi-redis-api-${environment}'
|
||||
scope: rgBff
|
||||
params: {
|
||||
principalName: 'mi-redis-api-${environment}'
|
||||
location: location
|
||||
}
|
||||
}
|
||||
|
||||
module allowAcrPull 'allow-acr-pull.bicep' = {
|
||||
name: 'allowAcrPull'
|
||||
scope: resourceGroup('1e6ef69e-8719-4924-a311-e66fe00399c7', 'rg-shared')
|
||||
params: {
|
||||
principalId: mi.outputs.principalId
|
||||
}
|
||||
}
|
||||
|
||||
module containerEnv 'containerEnvironment.bicep' = {
|
||||
name: 'containerEnv'
|
||||
scope: rgBff
|
||||
params: {
|
||||
location: location
|
||||
environment: environment
|
||||
userAssignedIdentityId: mi.outputs.id
|
||||
}
|
||||
}
|
||||
47
apps/redis-api/ci/bicep/main.bicep
Normal file
47
apps/redis-api/ci/bicep/main.bicep
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Environment, EnvironmentVar } from 'types.bicep'
|
||||
|
||||
targetScope = 'subscription'
|
||||
|
||||
param environment Environment
|
||||
param containerImageTag string = 'latest'
|
||||
|
||||
param primaryApiKey string
|
||||
param secondaryApiKey string
|
||||
|
||||
@description('The location for the resource group')
|
||||
param location string = 'westeurope'
|
||||
|
||||
resource rgRedisApi 'Microsoft.Resources/resourceGroups@2021-04-01' = {
|
||||
name: 'rg-redis-api-${environment}'
|
||||
location: location
|
||||
}
|
||||
|
||||
module mi 'managedIdentity.bicep' = {
|
||||
name: 'mi-redis-api-${environment}'
|
||||
scope: rgRedisApi
|
||||
params: {
|
||||
principalName: 'mi-redis-api-${environment}'
|
||||
location: location
|
||||
}
|
||||
}
|
||||
|
||||
module redis 'cache/redis.bicep' = {
|
||||
name: 'redisCache'
|
||||
scope: rgRedisApi
|
||||
params: {
|
||||
location: location
|
||||
environment: environment
|
||||
}
|
||||
}
|
||||
|
||||
module containerApp 'app/main.bicep' = {
|
||||
name: 'containerApp'
|
||||
params: {
|
||||
location: location
|
||||
environment: environment
|
||||
containerImageTag: containerImageTag
|
||||
redisConnection: 'default:${redis.outputs.primaryAccessKey}@${redis.outputs.hostname}:6380'
|
||||
primaryApiKey: primaryApiKey
|
||||
secondaryApiKey: secondaryApiKey
|
||||
}
|
||||
}
|
||||
10
apps/redis-api/ci/bicep/managedIdentity.bicep
Normal file
10
apps/redis-api/ci/bicep/managedIdentity.bicep
Normal file
@@ -0,0 +1,10 @@
|
||||
param location string = 'westeurope'
|
||||
param principalName string
|
||||
|
||||
resource mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
|
||||
name: principalName
|
||||
location: location
|
||||
}
|
||||
|
||||
output principalId string = mi.properties.principalId
|
||||
output id string = mi.id
|
||||
5
apps/redis-api/ci/bicep/roles/acr-pull.bicep
Normal file
5
apps/redis-api/ci/bicep/roles/acr-pull.bicep
Normal file
@@ -0,0 +1,5 @@
|
||||
@description('Pull artifacts from a container registry. Ref: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/containers#acrpull')
|
||||
resource rd 'Microsoft.Authorization/roleDefinitions@2022-05-01-preview' existing = {
|
||||
name: '7f951dda-4ed3-4680-a7ca-43fe172d538d'
|
||||
}
|
||||
output id string = rd.id
|
||||
9
apps/redis-api/ci/bicep/types.bicep
Normal file
9
apps/redis-api/ci/bicep/types.bicep
Normal file
@@ -0,0 +1,9 @@
|
||||
@export()
|
||||
@description('Type with allowed environments.')
|
||||
type Environment = 'test' | 'prod'
|
||||
|
||||
@export()
|
||||
type EnvironmentVar = {
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
Reference in New Issue
Block a user