Skip to content

Commit

Permalink
Merge pull request #10 from chris-kruining/feature/container-apps
Browse files Browse the repository at this point in the history
Feature/container apps
  • Loading branch information
chris-kruining authored Nov 27, 2024
2 parents e05e193 + 52b99a7 commit e080515
Show file tree
Hide file tree
Showing 28 changed files with 6,562 additions and 88 deletions.
13 changes: 8 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ jobs:
name: Calculate next version
runs-on: ubuntu-latest
outputs:
semver: ${{ steps.gitversion.outputs.SemVer }}
major: ${{ steps.gitversion.outputs.Major }}
minor: ${{ steps.gitversion.outputs.Minor }}
patch: ${{ steps.gitversion.outputs.Patch }}
Expand Down Expand Up @@ -88,14 +87,18 @@ jobs:
name=${x#"./"}
name=${name%".bicep"}
name="br:${{ secrets.ACR_LOGIN_SERVER }}/$name"
label="${{ fromJson('{"true": "latest","false":"next"}')[github.ref == 'refs/heads/main'] }}"
major="${{needs.prepare.outputs.major}}"
minor="${{needs.prepare.outputs.minor}}"
patch="${{needs.prepare.outputs.patch}}"
az bicep publish --file "$x" --target "$name:latest" --with-source --force
az bicep publish --file "$x" --target "$name:$major" --with-source --force
az bicep publish --file "$x" --target "$name:$major.$minor" --with-source --force
az bicep publish --file "$x" --target "$name:$major.$minor.$patch" --with-source
az bicep publish --file "$x" --target "$name:$label" --with-source --force
if ["${{github.ref}}" = "refs/heads/main"]; then
az bicep publish --file "$x" --target "$name:$major" --with-source --force
az bicep publish --file "$x" --target "$name:$major.$minor" --with-source --force
az bicep publish --file "$x" --target "$name:$major.$minor.$patch" --with-source
fi
done
81 changes: 80 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,81 @@
# tricep
common templates for bicep
A library of compositional functions to aid in the creation of config for resources.

This library, by design, does not create any resouces for you.

## Examples
See the `example` directory for some use cases on how to utilize Tricep

## Design
*TODO*

## Limitations / Known errors / Gotcha's

### composition with dynamic bicep functions
Bicep has a bunch of functions that need to run during "runtime".
For example `reference`, `listKeys`, or `listCallbackUrl`.

The use of such a function causes the whole expression tree to be hoisted to the generated ARM template.
For a resources `properties` this is a-ok. The `name`, `locaton`, and `tags` however
need to be resolved when generating the ARM template.

This means that we need to split the code that created the `name`, `locaton`, and `tags` properties from the code that creates the `properties` property.

This is where the `__dynamic` function from the utilities comes in. This function replicates the composition normally done in an internal function in Tricep, but just retruns the `properties`'s value.

An example to illustrate what I mean:

**Don't do this**
```bicep
import { Context } from '../../../src/types.bicep'
import { action_group, with_receiver } from '../../../src/recommended/insights/action-group.bicep'
targetScope = 'resourceGroup'
param context Context
param alertLogicAppId string
var actionGroupConfig = action_group(context, 'Alerts', [
with_receiver('logicApp', {
name: 'Alert messages logic app'
resourceId: alertLogicAppId
callbackUrl: listCallbackUrl(alertLogicAppId, '2019-05-01').value
useCommonAlertSchema: true
})
])
resource actionGroup 'microsoft.insights/actionGroups@2023-09-01-preview' = {
name: actionGroupConfig.name
location: actionGroupConfig.location
tags: actionGroupConfig.tags
properties: actionGroupConfig.properties
}
```

**Instead do this**
```bicep
import { Context } from '../../../src/types.bicep'
import { __dynamic } from '../../../src/utilities.bicep'
import { action_group, with_receiver } from '../../../src/recommended/insights/action-group.bicep'
targetScope = 'resourceGroup'
param context Context
param alertLogicAppId string
var actionGroupConfig = action_group(context, 'Alerts', [])
resource actionGroup 'microsoft.insights/actionGroups@2023-09-01-preview' = {
name: actionGroupConfig.name
location: actionGroupConfig.location
tags: actionGroupConfig.tags
properties: __dynamic(actionGroupConfig, [
with_receiver('logicApp', {
name: 'Alert messages logic app'
resourceId: alertLogicAppId
callbackUrl: listCallbackUrl(alertLogicAppId, '2019-05-01').value
useCommonAlertSchema: true
})
])
}
```
14 changes: 7 additions & 7 deletions bicepconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"experimentalFeaturesEnabled": {
"assertions": true,
"testFramework": true,
"extensibility": true,
"resourceDerivedTypes": true,
"resourceTypedParamsAndOutputs": true,
"sourceMapping": true,
"symbolicNameCodegen": true
// "assertions": true,
// "testFramework": true,
// "extensibility": true,
// "resourceDerivedTypes": true,
// "resourceTypedParamsAndOutputs": true,
// "sourceMapping": true,
// "symbolicNameCodegen": true
}
}
5 changes: 5 additions & 0 deletions example/containerApps/bicepconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"experimentalFeaturesEnabled": {
"resourceTypedParamsAndOutputs": true
}
}
201 changes: 201 additions & 0 deletions example/containerApps/environment/alert-app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
{
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Initialize_variable": {
"type": "InitializeVariable",
"inputs": {
"variables": [
{
"name": "AffectedResource",
"type": "array",
"value": "@split(triggerBody()?['data']?['essentials']?['alertTargetIDs'][0], '/')"
}
]
},
"runAfter": {}
},
"Read_a_resource": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"referenceName": "arm"
}
},
"method": "get",
"path": "/subscriptions/@{encodeURIComponent(variables('AffectedResource')[2])}/resourcegroups/@{encodeURIComponent(variables('AffectedResource')[4])}/providers/@{encodeURIComponent(variables('AffectedResource')[6])}/@{encodeURIComponent(concat(variables('AffectedResource')[7], '/', variables('AffectedResource')[8]))}",
"queries": {
"x-ms-api-version": "@outputs('Api_version')"
}
},
"runAfter": {
"Api_version": [
"SUCCEEDED"
]
},
"runtimeConfiguration": {
"staticResult": {
"name": "Read_a_resource0",
"staticResultOptions": "Disabled"
}
}
},
"Post_message_in_a_chat_or_channel": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"referenceName": "teams"
}
},
"method": "post",
"body": {
"recipient": "19:[email protected]",
"messageBody": "<p class=\"editor-paragraph\">Alert: @{triggerBody()?['data']?['essentials']?['alertRule']}, with severity: @{triggerBody()?['data']?['essentials']?['severity']}, was fired at @{triggerBody()?['data']?['essentials']?['firedDateTime']}</p><br><p class=\"editor-paragraph\">Monitoring service: @{triggerBody()?['data']?['essentials']?['monitoringService']}</p><p class=\"editor-paragraph\">Condition: @{triggerBody()?['data']?['essentials']?['monitorCondition']}</p><p class=\"editor-paragraph\">Type: @{triggerBody()?['data']?['essentials']?['signalType']}</p><p class=\"editor-paragraph\">Alert ID: @{triggerBody()?['data']?['essentials']?['alertId']}</p>"
},
"path": "/beta/teams/conversation/message/poster/Flow bot/location/@{encodeURIComponent('Group chat')}"
},
"runAfter": {
"Read_a_resource": [
"SUCCEEDED"
]
}
},
"Post_message_(V2)": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"referenceName": "slack-1"
}
},
"method": "post",
"body": {
"channel": "C07VDDCU2FJ",
"text": "Alert: @{triggerBody()?['data']?['essentials']?['alertRule']}, with severity: @{triggerBody()?['data']?['essentials']?['severity']}, was fired at @{triggerBody()?['data']?['essentials']?['firedDateTime']}\n\nMonitoring service: @{triggerBody()?['data']?['essentials']?['monitoringService']}\nCondition: @{triggerBody()?['data']?['essentials']?['monitorCondition']}\nType: @{triggerBody()?['data']?['essentials']?['signalType']}\nAlert ID: @{triggerBody()?['data']?['essentials']?['alertId']}",
"username": "Azure alerts"
},
"path": "/v2/chat.postMessage"
},
"runAfter": {
"Read_a_resource": [
"SUCCEEDED"
]
}
},
"Read_resource_provider": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"referenceName": "arm"
}
},
"method": "get",
"path": "/subscriptions/@{encodeURIComponent(variables('AffectedResource')[2])}/providers/@{encodeURIComponent(variables('AffectedResource')[6])}",
"queries": {
"x-ms-api-version": "2016-06-01"
}
},
"runAfter": {
"Initialize_variable": [
"SUCCEEDED"
]
}
},
"Api_version": {
"type": "JavaScriptCode",
"inputs": {
"code": "try {\r\n const providers = workflowContext.actions.Read_resource_provider.outputs.body.resourceTypes;\r\n const affectedResource = workflowContext.actions.Initialize_variable.inputs.variables[0].value;\r\n const givenResourceType = affectedResource[7];\r\n // const givenResourceType = `${affectedResource[7]}/${affectedResource[8]}`;\r\n\r\n const provider = providers.find(\r\n ({ resourceType }) => resourceType === givenResourceType\r\n );\r\n\r\n return provider\r\n ? provider.apiVersions.at(0)\r\n : JSON.stringify(providers);\r\n}\r\ncatch(e) {\r\n return `an error occurred: ${e.message}`;\r\n}"
},
"runAfter": {
"Read_resource_provider": [
"SUCCEEDED"
]
}
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"triggers": {
"When_a_HTTP_request_is_received": {
"type": "Request",
"kind": "Http",
"inputs": {
"method": "POST",
"schema": {
"type": "object",
"properties": {
"schemaId": {
"type": "string"
},
"data": {
"type": "object",
"properties": {
"essentials": {
"type": "object",
"properties": {
"alertId": {
"type": "string"
},
"alertRule": {
"type": "string"
},
"severity": {
"type": "string"
},
"signalType": {
"type": "string"
},
"monitorCondition": {
"type": "string"
},
"monitoringService": {
"type": "string"
},
"alertTargetIDs": {
"type": "array",
"items": {
"type": "string"
}
},
"originAlertId": {
"type": "string"
},
"firedDateTime": {
"type": "string"
},
"resolvedDateTime": {
"type": "string"
},
"description": {
"type": "string"
},
"essentialsVersion": {
"type": "string"
},
"alertContextVersion": {
"type": "string"
}
}
},
"alertContext": {
"type": "object",
"properties": {}
}
}
}
}
}
}
}
},
"staticResults": {
"Read_a_resource0": {
"status": "Succeeded",
"outputs": {
"statusCode": "OK"
}
}
}
}
21 changes: 21 additions & 0 deletions example/containerApps/environment/alert-logic-app.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Context } from '../../../src/types.bicep'
import { with_managed_identity } from '../../../src/common/identity.bicep'
import { workflow } from '../../../src/recommended/logic/workflow.bicep'

targetScope = 'resourceGroup'

param context Context

var workflowConfig = workflow(context, loadJsonContent('./alert-app.json'), [
with_managed_identity()
])

resource logicApp 'Microsoft.Logic/workflows@2019-05-01' = {
name: workflowConfig.name
location: workflowConfig.location
tags: workflowConfig.tags
identity: workflowConfig.identity
properties: workflowConfig.properties
}

output logicApp resource'Microsoft.Logic/workflows@2019-05-01' = logicApp
Loading

0 comments on commit e080515

Please sign in to comment.