Skip to content

Commit 6cd8f3d

Browse files
committed
Updating project structure
1 parent 6b29cf6 commit 6cd8f3d

File tree

4 files changed

+123
-205
lines changed

4 files changed

+123
-205
lines changed

.github/workflows/main.yml

+48-202
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: 'DevOps Practices for Azure Cosmos DB - GitHub Actions Workflow'
1+
name: 'DevOps Practices for Azure Cosmos DB'
22
on:
33
workflow_dispatch:
44
push:
@@ -10,7 +10,7 @@ on:
1010

1111
jobs:
1212
Build:
13-
name: 'Build Web App'
13+
name: 'Build .NET Web App'
1414
runs-on: ubuntu-latest
1515
steps:
1616
- name: Repository checkout
@@ -37,7 +37,7 @@ jobs:
3737
path: publish
3838

3939
Testing:
40-
name: 'Testing'
40+
name: 'Testing with Cosmos DB Emulator'
4141
runs-on: windows-latest # Azure Cosmos DB Emulator only supports Windows, although you can run it in a Docker container. https://learn.microsoft.com/azure/cosmos-db/local-emulator#run-on-linux-macos
4242
steps:
4343
- name: Repository checkout
@@ -69,79 +69,19 @@ jobs:
6969
uses: actions/setup-node@v3
7070
with:
7171
node-version: latest
72-
- name: Install NPM Azure Cosmos dependency
72+
73+
- name: Install Azure Cosmos dependency
7374
run: npm install @azure/cosmos
75+
76+
# The following steps are optional and are only used to demonstrate how to create and test Stored Procedures and Triggers with the Azure Cosmos DB Emulator.
7477
- name: Create and test Stored Procedure with Azure Cosmos DB Emulator
75-
uses: actions/github-script@v6
76-
with:
77-
script: | # This is the default connection string for the Azure Cosmos DB Emulator and TLS Reject is disabled for the emulator self-certificate.
78-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
79-
async function createSP() {
80-
const { CosmosClient } = require("@azure/cosmos");
81-
const endpoint = "https://localhost:8081";
82-
const key = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
83-
const client = new CosmosClient({ endpoint, key });
84-
const { database } = await client.databases.createIfNotExists({ id: 'SampleDatabase' });
85-
const { container } = await database.containers.createIfNotExists({ id: 'WebAppContext' });
86-
const { sampleStoredProcedure } = require('./StoredProcedures/SampleStoredProcedure.js');
87-
try {
88-
await container.scripts.storedProcedures.create(sampleStoredProcedure)
89-
} catch (e) {
90-
if (e.code === 409) {
91-
console.log('Stored procedure already exists replacing it with new version.')
92-
await container.scripts.storedProcedure(sampleStoredProcedure.id).replace(sampleStoredProcedure)
93-
} else {
94-
throw(e)
95-
}
96-
}
97-
finally{
98-
const { resource: results } = await container.scripts.storedProcedure(sampleStoredProcedure.id).execute();
99-
console.log(results);
100-
}
101-
}
102-
createSP().catch(error => {
103-
console.error("An error occurred: ", error);
104-
});
78+
run: node Scripts/createSP.js https://localhost:8081 C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== SampleDatabase WebAppContext StoredProcedures/SampleStoredProcedure.js 1
10579

106-
- name: Create and test Trigger
107-
uses: actions/github-script@v6
108-
with:
109-
script: | # This is the default connection string for the Azure Cosmos DB Emulator and TLS Reject is disabled for the emulator self-certificate.
110-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
111-
async function createTrigger() {
112-
const { CosmosClient } = require("@azure/cosmos");
113-
const endpoint = "https://localhost:8081";
114-
const key = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
115-
const client = new CosmosClient({ endpoint, key });
116-
const { database } = await client.databases.createIfNotExists({ id: 'SampleDatabase' });
117-
const { container } = await database.containers.createIfNotExists({ id: 'WebAppContext' });
118-
const { sampleTrigger } = require('./Triggers/SampleTrigger.js')
119-
try {
120-
await container.scripts.triggers.create(sampleTrigger)
121-
} catch (e) {
122-
if (e.code === 409) {
123-
console.log('Trigger already exists replacing it with new version.')
124-
await container.scripts.trigger(sampleTrigger.id).replace(sampleTrigger)
125-
} else {
126-
throw(e)
127-
}
128-
}
129-
finally {
130-
const newItem = {
131-
id: Math.floor(Math.random() * 10000).toString(),
132-
name: 'Sample Item'
133-
};
134-
const options = { preTriggerInclude: ['SampleTrigger'] };
135-
const { resource: trigger_result } = await container.items.create(newItem, options)
136-
console.log(trigger_result)
137-
}
138-
}
139-
createTrigger().catch(error => {
140-
console.error("An error occurred: ", error);
141-
});
80+
- name: Create and test Trigger with Azure Cosmos DB Emulator
81+
run: node Scripts/createTrigger.js https://localhost:8081 C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== SampleDatabase WebAppContext Triggers/SampleTrigger.js 1
14282

14383
QA:
144-
name: 'Quality Assurance'
84+
name: 'Quality Assurance in Azure Test Environment'
14585
runs-on: ubuntu-latest
14686
environment: QA
14787
needs: [Build, Testing]
@@ -158,91 +98,35 @@ jobs:
15898
az group create --name ${{ vars.RESOURCEGROUP }} --location eastus
15999
160100
- name: Provisioning Azure resources
161-
id: arm_deployment
101+
id: arm_deploy
162102
uses: azure/arm-deploy@v1
163103
with:
164104
resourceGroupName: ${{ vars.RESOURCEGROUP }}
165105
template: IaC/cosmosdb.json
166106
parameters: IaC/cosmosdb.QA-parameters.json
167107
deploymentMode: 'Complete'
168-
env:
169-
cosmoskey: ::add-mask::${{ steps.arm_deployment.outputs.cosmosDBkey }}
108+
109+
- name: Get CosmosDB Key
110+
id: get_cosmos_key
111+
run: | # Mask the key in the logs
112+
primary_key=$(az cosmosdb keys list --name ${{ steps.arm_deploy.outputs.cosmosDBName }} --resource-group ${{ vars.RESOURCEGROUP }} --query primaryMasterKey --output tsv)
113+
echo "::add-mask::$primary_key"
114+
echo "cosmosDBKey=$primary_key" >> $GITHUB_ENV
170115
171116
- name: Setup Node.js
172117
uses: actions/setup-node@v3
173118
with:
174119
node-version: latest
175120

176-
- name: Install NPM Azure Cosmos and Azure Identity dependencies
121+
- name: Install Azure Cosmos dependency
177122
run: npm install @azure/cosmos
178-
179-
- name: Create and test Stored Procedure in Azure Cosmos DB
180-
uses: actions/github-script@v6
181-
with:
182-
script: | # The Cosmos DB Key never should be accesed as plain text. It is only for demo purposes.
183-
async function createSP() {
184-
const { CosmosClient } = require("@azure/cosmos");
185-
const endpoint = "${{ steps.arm_deployment.outputs.cosmosDBendpoint }}";
186-
const key = "${{ env.cosmoskey }} ";
187-
const client = new CosmosClient({ endpoint, key });
188-
const { database } = await client.databases.createIfNotExists({ id: 'SampleDatabase' });
189-
const { container } = await database.containers.createIfNotExists({ id: 'WebAppContext' });
190-
const { sampleStoredProcedure } = require('./StoredProcedures/SampleStoredProcedure.js');
191-
try {
192-
await container.scripts.storedProcedures.create(sampleStoredProcedure)
193-
} catch (e) {
194-
if (e.code === 409) {
195-
console.log('Stored procedure already exists replacing it with new version.')
196-
await container.scripts.storedProcedure(sampleStoredProcedure.id).replace(sampleStoredProcedure)
197-
} else {
198-
throw(e)
199-
}
200-
}
201-
finally{
202-
const { resource: results } = await container.scripts.storedProcedure(sampleStoredProcedure.id).execute();
203-
console.log(results);
204-
}
205-
}
206-
createSP().catch(error => {
207-
console.error("An error occurred: ", error);
208-
});
209123

210-
- name: Create and test Trigger in Azure Cosmos DB
211-
uses: actions/github-script@v6
212-
with:
213-
script: | # The Cosmos DB Key never should be accesed as plain text. It is only for demo purposes.
214-
async function createTrigger() {
215-
const { CosmosClient } = require("@azure/cosmos");
216-
const endpoint = "${{ steps.arm_deployment.outputs.cosmosDBendpoint }}";
217-
const key = "${{ env.cosmoskey }}";
218-
const client = new CosmosClient({ endpoint, key });
219-
const { database } = await client.databases.createIfNotExists({ id: 'SampleDatabase' });
220-
const { container } = await database.containers.createIfNotExists({ id: 'WebAppContext' });
221-
const { sampleTrigger } = require('./Triggers/SampleTrigger.js')
222-
try {
223-
await container.scripts.triggers.create(sampleTrigger)
224-
} catch (e) {
225-
if (e.code === 409) {
226-
console.log('Trigger already exists replacing it with new version.')
227-
await container.scripts.trigger(sampleTrigger.id).replace(sampleTrigger)
228-
} else {
229-
throw(e)
230-
}
231-
}
232-
finally {
233-
const newItem = {
234-
id: Math.floor(Math.random() * 10000).toString(),
235-
name: 'Sample Item'
236-
};
237-
const options = { preTriggerInclude: ['SampleTrigger'] };
238-
const { resource: trigger_result } = await container.items.create(newItem, options)
239-
console.log(trigger_result)
240-
}
241-
}
242-
createTrigger().catch(error => {
243-
console.error("An error occurred: ", error);
244-
});
245-
124+
- name: Create and test Stored Procedure with Azure Cosmos DB Emulator
125+
run: node Scripts/createSP.js ${{ steps.arm_deploy.outputs.cosmosDBendpoint }} ${{ env.cosmosDBKey }} SampleDatabase WebAppContext StoredProcedures/SampleStoredProcedure.js 1
126+
127+
- name: Create and test Trigger with Azure Cosmos DB Emulator
128+
run: node Scripts/createTrigger.js ${{ steps.arm_deploy.outputs.cosmosDBendpoint }} ${{ env.cosmosDBKey }} SampleDatabase WebAppContext Triggers/SampleTrigger.js 1
129+
246130
- name: Download web app artifact
247131
uses: actions/download-artifact@v3
248132
with:
@@ -252,7 +136,7 @@ jobs:
252136
- name: Deploy web app to Azure Web App
253137
uses: azure/webapps-deploy@v2
254138
with:
255-
app-name: ${{ steps.arm_deployment.outputs.webappname }}
139+
app-name: ${{ steps.arm_deploy.outputs.webAppName }}
256140
package: SampleApp
257141

258142
Production:
@@ -273,78 +157,40 @@ jobs:
273157
az group create --name ${{ vars.RESOURCEGROUP }} --location eastus
274158
275159
- name: Provisioning Azure Cosmos DB resource with ARM
276-
id: arm_deployment
160+
id: arm_deploy
277161
uses: azure/arm-deploy@v1
278162
with:
279163
resourceGroupName: ${{ vars.RESOURCEGROUP }}
280164
template: IaC/cosmosdb.json
281165
parameters: IaC/cosmosdb.Prod-parameters.json
282166
deploymentMode: 'Incremental'
283-
env:
284-
cosmoskey: ::add-mask::${{ steps.arm_deployment.outputs.cosmosDBkey }}
285167

286168
- name: Setup Node.js
287169
uses: actions/setup-node@v3
288170
with:
289171
node-version: latest
290-
291-
- name: Install NPM Azure Cosmos and Azure Identity dependencies
292-
run: npm install @azure/cosmos
172+
173+
- name: Get CosmosDB Key
174+
id: get_cosmos_key
175+
run: | # Mask the key in the logs
176+
primary_key=$(az cosmosdb keys list --name ${{ steps.arm_deploy.outputs.cosmosDBName }} --resource-group ${{ vars.RESOURCEGROUP }} --query primaryMasterKey --output tsv)
177+
echo "::add-mask::$primary_key"
178+
echo "cosmosDBKey=$primary_key" >> $GITHUB_ENV
293179
294-
- name: Create and test Stored Procedure in Azure Cosmos DB
295-
uses: actions/github-script@v6
180+
- name: Setup Node.js
181+
uses: actions/setup-node@v3
296182
with:
297-
script: | # The Cosmos DB Key never should be accesed as plain text. It is only for demo purposes.
298-
async function createSP() {
299-
const { CosmosClient } = require("@azure/cosmos");
300-
const endpoint = "${{ steps.arm_deployment.outputs.cosmosDBendpoint }}";
301-
const key = "${{ env.cosmoskey }}";
302-
const client = new CosmosClient({ endpoint, key });
303-
const { database } = await client.databases.createIfNotExists({ id: 'SampleDatabase' });
304-
const { container } = await database.containers.createIfNotExists({ id: 'WebAppContext' });
305-
const { sampleStoredProcedure } = require('./StoredProcedures/SampleStoredProcedure.js');
306-
try {
307-
await container.scripts.storedProcedures.create(sampleStoredProcedure)
308-
} catch (e) {
309-
if (e.code === 409) {
310-
console.log('Stored procedure already exists replacing it with new version.')
311-
await container.scripts.storedProcedure(sampleStoredProcedure.id).replace(sampleStoredProcedure)
312-
} else {
313-
throw(e)
314-
}
315-
}
316-
}
317-
createSP().catch(error => {
318-
console.error("An error occurred: ", error);
319-
});
183+
node-version: latest
184+
185+
- name: Install Azure Cosmos dependency
186+
run: npm install @azure/cosmos
320187

321-
- name: Create and test Trigger in Azure Cosmos DB
322-
uses: actions/github-script@v6
323-
with:
324-
script: | # The Cosmos DB Key never should be accesed as plain text. It is only for demo purposes.
325-
async function createTrigger() {
326-
const { CosmosClient } = require("@azure/cosmos");
327-
const endpoint = "${{ steps.arm_deployment.outputs.cosmosDBendpoint }}";
328-
const key = "${{ env.cosmoskey }}";
329-
const client = new CosmosClient({ endpoint, key });
330-
const { database } = await client.databases.createIfNotExists({ id: 'SampleDatabase' });
331-
const { container } = await database.containers.createIfNotExists({ id: 'WebAppContext' });
332-
const { sampleTrigger } = require('./Triggers/SampleTrigger.js')
333-
try {
334-
await container.scripts.triggers.create(sampleTrigger)
335-
} catch (e) {
336-
if (e.code === 409) {
337-
console.log('Trigger already exists replacing it with new version.')
338-
await container.scripts.trigger(sampleTrigger.id).replace(sampleTrigger)
339-
} else {
340-
throw(e)
341-
}
342-
}
343-
}
344-
createTrigger().catch(error => {
345-
console.error("An error occurred: ", error);
346-
});
347-
188+
- name: Create and test Stored Procedure with Azure Cosmos DB Emulator
189+
run: node Scripts/createSP.js ${{ steps.arm_deploy.outputs.cosmosDBendpoint }} ${{ env.cosmosDBKey }} SampleDatabase WebAppContext StoredProcedures/SampleStoredProcedure.js 0
190+
191+
- name: Create and test Trigger with Azure Cosmos DB Emulator
192+
run: node Scripts/createTrigger.js ${{ steps.arm_deploy.outputs.cosmosDBendpoint }} ${{ env.cosmosDBKey }} SampleDatabase WebAppContext Triggers/SampleTrigger.js 0
193+
348194
- name: Download web app artifact
349195
uses: actions/download-artifact@v3
350196
with:
@@ -354,5 +200,5 @@ jobs:
354200
- name: Deploy web app to Azure Web App
355201
uses: azure/webapps-deploy@v2
356202
with:
357-
app-name: ${{ steps.arm_deployment.outputs.webappname }}
203+
app-name: ${{ steps.arm_deploy.outputs.WebAppName }}
358204
package: SampleApp

IaC/cosmosdb.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,9 @@
8686
"type": "string",
8787
"value": "[concat('https://', variables('cosmosAccountName'),'.documents.azure.com:443')]"
8888
},
89-
// The cosmos db key should never be exposed in a real world scenario. This is just for demo purposes.
90-
"cosmosDBkey": {
89+
"cosmosDBName": {
9190
"type": "string",
92-
"value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosAccountName')), '2022-05-15').primaryMasterKey]"
91+
"value": "[variables('cosmosAccountName')]"
9392
},
9493
"webAppName": {
9594
"type": "string",

Scripts/createSP.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
async function createSP(endpoint, key, databaseId, containerId, storedProcedureFile, includeTest) {
2+
const { CosmosClient } = require("@azure/cosmos");
3+
const client = new CosmosClient({ endpoint, key });
4+
const { database } = await client.databases.createIfNotExists({ id: databaseId });
5+
const { container } = await database.containers.createIfNotExists({ id: containerId });
6+
const { sampleStoredProcedure } = await require('./StoredProcedures/'+storedProcedureFile);
7+
try {
8+
await container.scripts.storedProcedures.create(sampleStoredProcedure);
9+
} catch (e) {
10+
if (e.code === 409) {
11+
await container.scripts.storedProcedure(sampleStoredProcedure.id).replace(sampleStoredProcedure);
12+
} else {
13+
throw(e);
14+
}
15+
}
16+
finally{
17+
if(includeTest>0) {
18+
const { resource: results } = await container.scripts.storedProcedure(sampleStoredProcedure.id).execute();
19+
console.log(results);
20+
}
21+
}
22+
}
23+
24+
const [endpoint, key, databaseId, containerId, storedProcedureFile, includeTest] = process.argv.slice(2);
25+
26+
if (!endpoint || !key || !databaseId || !containerId || !storedProcedureFile || !includeTest) {
27+
console.error('Please provide all the required parameters.');
28+
process.exit(1);
29+
}
30+
31+
createSP(endpoint, key, databaseId, containerId, storedProcedureFile, includeTest).catch((error) => {
32+
console.error(error);
33+
process.exit(1);
34+
});

0 commit comments

Comments
 (0)