Azure deployment via SDK - c#

I'm running out of time to get this done, but I just can't seem to find my issue.
I'm trying to deploy an ARM template that creates a new MCA subscription. The template works when deployed via Azure PowerShell, but when using the Azure SDK it gives the following error:
Microsoft.Rest.Azure.CloudException: 'Deployment template validation failed: 'The resource 'Microsoft.Subscription/aliases/devtestdeployasp22' referenced in output is not defined in the template. Please specify resource identifier and api version if the resource is outside of the template. Please see https://aka.ms/arm-template-expressions/#reference for usage details.'.'
var subscription = azure.Deployments
.Define("deployment_temp")
.WithNewResourceGroup("temprg", Region.USEast)
.WithTemplate(Utils.GetArmTemplate("<path_to_file_removed_for_privacy>"))
.WithParameters("{}")
.WithMode(Microsoft.Azure.Management.ResourceManager.Fluent.Models.DeploymentMode.Incremental)
.Create();
The template used with this contains:
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"subscriptionAliasName": {
"type": "string",
"metadata": {
"description": "Provide a name for the alias. This name will also be the display name of the subscription."
}
},
"billingScope": {
"type": "string",
"defaultValue": "<Removed>",
"metadata": {
"description": "Provide the full resource ID of billing scope to use for subscription creation."
}
},
"mgName": {
"type": "string",
"defaultValue": "mg-mission-default-dev",
"metadata": {
"description": "management group name"
}
}
},
"variables": {
"mgId": "[concat('Microsoft.Management/managementGroups/',parameters('mgName'))]"
},
"resources": [
{
"scope": "[variables('mgId')]",
"name": "[parameters('subscriptionAliasName')]",
"type": "Microsoft.Subscription/aliases",
"apiVersion": "2021-04-01",
"properties": {
"workLoad": "Production",
"displayName": "[parameters('subscriptionAliasName')]",
"billingScope": "[parameters('billingScope')]"
}
}
],
"outputs": {
"subscriptionID": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Subscription/aliases', parameters('subscriptionAliasName'))).subscriptionId]"
}
}
}
Any help would be appreciated, or even an alternate path I could take but the goal is to create a new MCA subscription (with some resources) using C#.

You need to fetch the Subscription ID by using tenantResourceId -
tenantResourceId - Returns the unique identifier for a resource deployed at the tenant level.
"outputs": {
"subscriptionId": {
"type": "string",
"value": "[reference(tenantResourceId('Microsoft.Subscription/aliases', parameters('subscriptionAliasName'))).subscriptionId]"
}
}
Please refer this documentation.

Related

web api post dynamic type and validation

I developing a method that accepts various messages and returns the some result. The main goal is that message formats can be added without rebuilding the project. Two types of the messages is below:
{
"PushToken": "ksjdfhskfhskdjfhskjdfhk",
"Alertе": "ssffsdfsdfsdfsdfsdfsfs sfsdfsdf sfsdfsdfs",
"Priority": 5,
"IsBackground": false
}
and
{
"DeviceToken": "ksjdfhskfhskdjfhskjdfhkkh7khsdfjk8sdfsdfsddddddddddddddd",
"Message": "ssffsdfsdfsdfsdfsdfsfs sfsdfsdf sfsdfsdfs",
"Title": "asdasdas",
"Condition": "asfdasf"
}
I thinked how to validate messages and decided using json schema's. They are below:
{
"title":"IOS",
"description": "IOS Message",
"type": "object",
"properties": {
"PushToken": { "type": "string", "maxLength": 50 },
"Alert": { "type": "string", "maxLength": 2000 },
"Priority": { "type": "number", "default": 10 },
"IsBackground": { "type": "boolean", "default": true }
},
"required":[
"PushToken",
"Alert"
],
"additionalProperties": false
}
and
{
"title":"Android",
"description": "Android message",
"type": "object",
"properties": {
"DeviceToken": { "type": "string", "maxLength": 50 },
"Message": { "type": "string", "maxLength": 2000 },
"Title": { "type": "string", "maxLength": 255 },
"Condition": { "type": "string", "maxLength": 2000 }
},
"required":[
"DeviceToken",
"Message",
"Title"
],
"additionalProperties": false
}
For validating I using thomething like that:
JSchema schema = JSchema.Parse(iosJsonSchema);
IList<string> errorMessages;
bool valid = iosJsonMessage.IsValid(schema, out errorMessages); //iosJsonMessage - JObject type
In IList<string> messages I receive all errors. In bool valid variable I receive validation result.
Is there a way to check only properties names of the json request? And only those names that are declare in required section of the json schema. I want to do this for understanding the type of the message.
And a more general question. Is this an acceptable solution for task that I described above?
Thanks.

C# How to get exact error message from Logic App triggered by HttpRequest instead of default error message?

I have a simple console application and it calls a Logic App by HttpRequest.
When the Logic App fails at any step I want to get exact the error message saying why it fails.
In the Logic App I can see the error.
Example: in the image, it fails at step 2 which it can't convert a string into an int. It's saying:
InvalidTemplate. Unable to process template language expressions in action 'Parse_JSON' inputs at line '0' and column '0': 'Required property 'content' expects a value but got null. Path ''.'.
which is what's I expect.
Here is my Logic App design:
But when I debug in a console application, it gives me a message "The server did not receive a response from an upstream server. Request tracking id 'some random Ids'." which is not very useful.
Here is my console application:
var obj = new
{
Age = "Twenty",
Name = "James"
};
using (var client = new HttpClient())
{
var content = new StringContent(JsonConvert.SerializeObject(obj));
content.Headers.ContentType.MediaType = "application/json";
var response = await client.PostAsync(url, content);
var errorMessage = await response.Content.ReadAsStringAsync();
//errorMessage: {"error":{"code":"NoResponse","message":"The server did not receive a response from an upstream server. Request tracking id 'some random Ids'."}}
}
So is there anyway to make the C# response return the error message in the step 2 of the Logic App?
What I expect is:
InvalidTemplate. Unable to process template language expressions in action 'Parse_JSON' inputs at line '0' and column '0': 'Required property 'content' expects a value but got null. Path ''.'.
Not:
{"error":{"code":"NoResponse","message":"The server did not receive a response from an upstream server. Request tracking id 'some random Ids'."}}
Thank you in advanced.
You can use actions('<Your_Previous_Step>')['error'] in your case actions('Parse_JSON')['error'] doing so you can able to retrieve the error message of that particular action.
Here is my logic app
I'm testing this through postman. Below is the response I received in postman.
Make sure you set Configure run after options to make the flow work even after it gets failed.
Updated Answer (General Solution)
In this case you can initialise a string variable and then add Append to string variable for each step so that it can catch the previous steps error. Below is the screenshot of my logic app.
Response in my postman
NOTE: Make sure you set Configure run after property for each action.
You can use the Scope action to encase the vast majority of other actions and then if something fails, you can catch the step for which it fails at.
You can load this JSON definition into your own tenant and see a working version.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Filter_array": {
"inputs": {
"from": "#variables('Result')",
"where": "#equals(item()['status'], 'Failed')"
},
"runAfter": {
"Initialize_Result": [
"Succeeded"
]
},
"type": "Query"
},
"Initialize_Error_Message": {
"inputs": {
"variables": [
{
"name": "Error Message",
"type": "string",
"value": "#{body('Filter_array')[0]['error']['message']}"
}
]
},
"runAfter": {
"Filter_array": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Integer_Variable": {
"inputs": {
"variables": [
{
"name": "Integer Variable",
"type": "integer",
"value": 1
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Initialize_Result": {
"inputs": {
"variables": [
{
"name": "Result",
"type": "array",
"value": "#result('Scope')"
}
]
},
"runAfter": {
"Scope": [
"Succeeded",
"FAILED"
]
},
"type": "InitializeVariable"
},
"Scope": {
"actions": {
"Set_Integer_Variable_(Step_1)": {
"inputs": {
"name": "Integer Variable",
"value": 2
},
"runAfter": {},
"type": "SetVariable"
},
"Set_Integer_Variable_(Step_2)": {
"inputs": {
"name": "Integer Variable",
"value": "#string('Test')"
},
"runAfter": {
"Set_Integer_Variable_(Step_1)": [
"Succeeded"
]
},
"type": "SetVariable"
},
"Set_Integer_Variable_(Step_3)": {
"inputs": {
"name": "Integer Variable",
"value": 3
},
"runAfter": {
"Set_Integer_Variable_(Step_2)": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"runAfter": {
"Initialize_Integer_Variable": [
"Succeeded"
]
},
"type": "Scope"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"Recurrence": {
"evaluatedRecurrence": {
"frequency": "Month",
"interval": 12
},
"recurrence": {
"frequency": "Month",
"interval": 12
},
"type": "Recurrence"
}
}
},
"parameters": {}
}
Naturally, it's a little more intensive and follows the same principals as a normal flow for continuing to the next step after a failure but this will help you with larger flows.
This is what the test flow looks like ...
To explain it quickly, the middle steps are simple Set Variable actions that can be changed to cause the failure.
In the definition I've given you, step 2 will fail but you can change it to step 1 or 3 and you should still see the error come out at the end regardless of the step in the scope action that fails.
I suggest playing with it and looking at the output to the scope action, which is written to variable Result in the Initialize Result step.
For reference, this is the sort of information that comes out of the Scope action that you can use to determine what has failed.
{
"variables": [
{
"name": "Result",
"type": "Array",
"value": [
{
"name": "Set_Integer_Variable_(Step_1)",
"inputs": {
"name": "Integer Variable",
"value": 2
},
"outputs": {
"body": {
"name": "Integer Variable",
"value": 2
}
},
"startTime": "2022-04-22T06:55:57.8965917Z",
"endTime": "2022-04-22T06:55:57.9281959Z",
"trackingId": "0c93fa70-a552-4776-bce1-8ac889933de9",
"clientTrackingId": "08585509963278112157168286283CU11",
"status": "Succeeded"
},
{
"name": "Set_Integer_Variable_(Step_2)",
"startTime": "2022-04-22T06:55:57.9434709Z",
"endTime": "2022-04-22T06:55:57.9434709Z",
"trackingId": "f82b494b-0ecd-412b-887a-d4b08f4a5751",
"clientTrackingId": "08585509963278112157168286283CU11",
"code": "BadRequest",
"status": "Failed",
"error": {
"code": "BadRequest",
"message": "The variable 'Integer Variable' of type 'Integer' cannot be initialized or updated with value of type 'String'. The variable 'Integer Variable' only supports values of types 'Integer'."
}
},
{
"name": "Set_Integer_Variable_(Step_3)",
"startTime": "2022-04-22T06:55:57.9590957Z",
"endTime": "2022-04-22T06:55:57.9590957Z",
"trackingId": "f761d71f-8ec0-4a29-9a8a-a39a81faf660",
"clientTrackingId": "08585509963278112157168286283CU11",
"code": "ActionSkipped",
"status": "Skipped",
"error": {
"code": "ActionConditionFailed",
"message": "The execution of template action 'Set_Integer_Variable_(Step_3)' is skipped: the 'runAfter' condition for action 'Set_Integer_Variable_(Step_2)' is not satisfied. Expected status values 'Succeeded' and actual value 'Failed'."
}
}
]
}
]
}
Take note, you still need to apply the Configure run after properties to ensure it continues on after the Scope action finishes ...
You'd need to put some more error checking in but my suggestion would be to wrap all of that functionality into another LogicApp that you can reuse across your tenant. That's the thinking anyway.

Simple ARM template not working in Azure Cli

I have a simple ARM deployment script
az deployment group create \
--name <NAME> \
--resource-group <ResourceGroup> \
--template-file template.json \
--parameters #parameters.json
This has a template file
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"connections_ftp_name": {
"defaultValue": "ftp",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[parameters('connections_ftp_name')]",
"location": "ukwest",
"kind": "V1",
"properties": {
"displayName": "[parameters('connections_ftp_name')]",
"customParameterValues": {},
"api": {
"id": "[concat('/subscriptions/SUBSCRIPTION/providers/Microsoft.Web/locations/ukwest/managedApis/', parameters('connections_ftp_name'))]"
}
}
}
]
}
And a parameter file
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"connections_ftp_name": {
"value": "my-name"
}
}
}
When I run this via Azure CLI I get the error
az deployment group create \
> --name DeployMonitorFtp5 \
> --resource-group middleware.prod.rg \
> --template-file template.json \
> --parameters #parameters.json
←[K←[K←[91mDeployment failed. Correlation ID: 1f5b34ad-3105-4dfd-b4ca-d38a98fb800a. {
"error": {
"code": "ApiNotFound",
"message": "The API 'my-name' could not be found."
}
}←[0m
This makes no sense at all given I want to create the resource!
Can someone help please?
Paul
IT is not related to Az Cli.
The api element should not referenced the parameter connections_ftp_name. it should be :
"api": {
"id": "[concat('/subscriptions/SUBSCRIPTION/providers/Microsoft.Web/locations/ukwest/managedApis/ftp')]"
}
When creating a logic app connector, you should also specify the connector, here is a complete sample to create a ftp connector:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"ftpConnectionAPIName": {
"type": "string",
"metadata": {
"description": "The name of the connection api to access the ftp."
}
},
"ftpServerAddress": {
"type": "string",
"metadata": {
"description": "The name of the ftp server address."
}
},
"ftpUsername": {
"type": "string",
"metadata": {
"description": "The name of the ftp user name."
}
},
"ftpPassword": {
"type": "securestring",
"metadata": {
"description": "The name of the ftp password."
}
}
},
"resources": [
{
"type": "Microsoft.Web/connections",
"name": "[parameters('ftpConnectionAPIName')]",
"apiVersion": "2016-06-01",
"location": "[resourceGroup().location]",
"scale": null,
"properties": {
"displayName": "[parameters('ftpConnectionAPIName')]",
"parameterValues": {
"serverAddress": "[parameters('ftpServerAddress')]",
"userName": "[parameters('ftpUsername')]",
"password": "[parameters('ftpPassword')]"
},
"api": {
"id": "[concat('subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/ftp')]"
}
}
}
]
}

Getting an error of Existing Resource while using function ARM template

I am wrting a Function ARM template for CI/CD the function is already hosted on the Azure portal Now I decided to create an ARM function template and am getting the below error. It saying I cannot create a resource which already exists. I know the resource already exists but I want to create a CI/CD pipline based on the template. I have tried the incremental mode but it seems I am missing something. Is there any guidance online? I have taken the Azure Function Template from the AZURE Git.
C:\Program Files\Microsoft SDKs\Azure.NET SDK\v2.9> az group deployment validate --mode Incremental --resource-group cloud-shell-storage-southeastasia --template-file azuredeploy.json
Please provide string value for 'appName' (? for help): SchedulerHttpFunctionSample
azuredeploy.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appName": {
"type": "string",
"metadata": {
"description": "The name of the function app that you wish to create."
}
},
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"runtime": {
"type": "string",
"defaultValue": "node",
"allowedValues": [
"node",
"dotnet",
"java"
],
"metadata": {
"description": "The language worker runtime to load in the function app."
}
}
},
"variables": {
"functionAppName": "[parameters('appName')]",
"hostingPlanName": "[parameters('appName')]",
"applicationInsightsName": "[parameters('appName')]",
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]",
"storageAccountid": "[concat(resourceGroup().id,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"functionWorkerRuntime": "[parameters('runtime')]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "2018-12-01",
"location": "[parameters('location')]",
"kind": "Storage",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"properties":{
"mode":"Incremental"
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-02-01",
"name": "[variables('hostingPlanName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"properties": {
"mode":"Incremental",
"name": "[variables('hostingPlanName')]",
"computeMode": "Dynamic"
}
},
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Web/sites",
"name": "[variables('functionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"mode":"Incremental",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(variables('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "~10"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', variables('applicationInsightsName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "[variables('functionWorkerRuntime')]"
}
]
}
}
},
{
"apiVersion": "2018-02-01",
"name": "[variables('applicationInsightsName')]",
"type": "microsoft.insights/components",
"location": "East US",
"tags": {
"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', variables('applicationInsightsName'))]": "Resource"
},
"properties": {
"ApplicationId": "[variables('applicationInsightsName')]",
"Request_Source": "IbizaWebAppExtensionCreate",
"mode":"Incremental"
}
}
]
}
Azure Error: InvalidResourceLocation
Message: The resource 'SchedulerHttpFunctionSample' already exists in location 'southcentralus' in resource group 'cloud-shell-storage-southeastasia'. A resource with the same name cannot be created in location 'southeastasia'. Please select a new resource name.
It's because that name is already taken. Function App name need to be globally unique.
I would suggest using a suffix. In the variables section create some variables:
"variables": {
"suffix": "[uniqueString(resourceGroup().id, resourceGroup().location)]",
"functionAppName": "[concat(parameters('appName'), variables('suffix'))]"
}
The function uniqueString will generate a unique string base on the information received. So if you redeploy in the same resource group and region the suffix will be the same.
Have a look to this post: http://www.frankysnotes.com/2019/05/how-to-make-your-deployment-successful.html or this video https://www.youtube.com/watch?v=dnb-f4C052w

TFS 2015: Release Definition REST API Issue

Visual Studio 2017 15.7.5
.Net Core 2.1
TFS 2015 Update 3
I'm trying to make a POST request to create a release. This is the documentation I'm referring to. But I get the following error message:
"VS402881: No artifact version is specified corresponding to artifact
source 'example0'. Specify a valid value and try
again.\",\"typeName\":\"Microsoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException,
Microsoft.VisualStudio.Services.ReleaseManagement2.Data,
Version=14.0.0.0, Culture=neutral,
PublicKeyToken=...\",\"typeKey\":\"InvalidRequestException\",\"errorCode\":0,\"eventId\":3000}"
This is an example of my request.
{
"definitionId": 1,
"description": "Creating Sample release",
"artifacts": [
{
"alias": "example0",
"instanceReference": [
{
"id": "39194",
"name": "example"
}
]
},
{
"alias": "example0",
"instanceReference": [
{
"id": "39194",
"name": "example"
}
]
}
]
}
EDIT1: Although the documentation doesn't refer to any "artifact version", I've found the variable through this GET call which returns a "version" under the artifacts. I've updated my Request Body with the version number as seen below but I still receive the same error.
{
"definitionId": 1,
"description": "Creating Sample release",
"artifacts": [
{
"alias": "example0",
"instanceReference": [
{
"id": "123",
"name": "example0_0"
}
],
"version": {
"id": "12345"
}
},
{
"alias": "exmaple1",
"instanceReference": [
{
"id": "1234",
"name": "example1_0"
},
{
"id": "42616",
"name": "example1_1"
},
{
"id": "42617",
"name": "example1_2"
}
],
"version": {
"id": "123456"
}
}
]
}
The REST API to create a release in TFS 2015 is as below, you could check your api:
POST http://TFS2015:8080/tfs/DefaultCollection/{teamproject}/_apis/Release/releases?api-version=2.3-preview.1
{
"definitionId":1,
"description":"",
"artifacts":[
{
"alias":"CAT0604",
"instanceReference":{
"name":"20180621.2",
"id":"57",
"sourceBranch":"$/Scrum-TFVC"
}
}
],
"isDraft":false,
"manualEnvironments":[]
}
You could also press F12 and create a release in web portal to capture the api to see which part of your api is incorrect.
Found a solution to my problem. It turns out for the Instance Reference, you need to refer to the builds not the build artifacts as one of the documentation suggests.

Categories