Azure Bicep template deployment failure with error: "The value of parameter linuxConfiguration.ssh.publicKeys.path is invalid.\" - azure-resource-manager

I created a bicep templated to deploy on Azure (using bash) a linux vm with the associated resources (nic, vnet, subnet, publicIP). Part of the deployment fails; where all the associated resources are deployed but the vm itself fails to deploy.
The error is as follows:
{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"{\r\n "error": {\r\n "code": "InvalidParameter",\r\n "message": "Destination path for SSH public keys is currently limited to its default value /home/user/.ssh/authorized_keys due to a known issue in Linux provisioning agent.",\r\n "target": "linuxConfiguration.ssh.publicKeys.path"\r\n }\r\n}"}]}}
The bicep template provided by microsoft uses the path: '/home/${adminUsername}/.ssh/authorized_keys'
I can't seem to figure out a way for it to deploy. Any assistance would greatly appreciated.
Here is the bicep file that causes the error:
#description('Name of the VM')
param vmName string = 'stagingLinuxVM'
#description('location for all resources')
param location string = resourceGroup().location
#description('vm sizes allowed RAM & temp storage in GiB per tier (respectively): 0.5/4; 1/4; 2/4; 4/8; 8/16')
#allowed([
'Standard_B1s'
'Standard_B1ms'
'Standard_B2s'
'Standard_B2ms'
])
param vmSize string = 'Standard_B1s'
#description('Username for the VM')
param adminUsername string
#description('SSH Key for the Virtual Machine')
#secure()
param adminPasswordKey string
#description('name of VNET')
param virtualNetworkName string = 'vnet'
#description('name of the subnet in the virtual network')
param subnetName string = 'Subnet'
param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id)}')
var osDiskType = 'Standard_LRS'
var networkInterfaceName = '${vmName}nic'
var addressPrefix = '10.1.0.0/16'
var publicIPAddressName = '${vmName}PublicIP'
var subnetAddressPrefix = '10.1.0.0/24'
var linuxConfiguration = {
disablePasswordAuthentication: true
provisionVMAgent: true
ssh: {
publicKeys: [
{
path: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: adminPasswordKey
}
]
}
}
resource nic 'Microsoft.Network/networkInterfaces#2021-08-01' = {
name: networkInterfaceName
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
subnet: {
id: subnet.id
}
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: publicIP.id
}
}
}
]
}
}
resource vnet 'Microsoft.Network/virtualNetworks#2021-08-01' = {
name: virtualNetworkName
location: location
properties: {
addressSpace: {
addressPrefixes: [
addressPrefix
]
}
}
}
resource subnet 'Microsoft.Network/virtualNetworks/subnets#2021-08-01' = {
parent: vnet
name: subnetName
properties: {
addressPrefix: subnetAddressPrefix
privateEndpointNetworkPolicies: 'Enabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
}
resource publicIP 'Microsoft.Network/publicIPAddresses#2021-08-01' = {
name: publicIPAddressName
location: location
sku: {
name: 'Basic'
}
properties: {
publicIPAllocationMethod: 'Dynamic'
publicIPAddressVersion: 'IPv4'
dnsSettings: {
domainNameLabel: dnsLabelPrefix
}
idleTimeoutInMinutes: 4
}
}
resource vm 'Microsoft.Compute/virtualMachines#2021-11-01' = {
name: vmName
location: location
properties: {
hardwareProfile: {
vmSize: vmSize
}
osProfile: {
adminPassword: adminPasswordKey
adminUsername: adminUsername
computerName: vmName
linuxConfiguration: linuxConfiguration
}
storageProfile: {
imageReference: {
offer: 'UbuntuServer'
publisher: 'Canonical'
sku: '18.04-LTS'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
deleteOption: 'Delete'
diskSizeGB: 32
osType: 'Linux'
managedDisk: {
storageAccountType: osDiskType
}
}
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
}
]
}
}
}
output adminUsername string = adminUsername
output hostname string = publicIP.properties.dnsSettings.fqdn
output sshComand string = 'ssh ${adminUsername}#${publicIP.properties.dnsSettings.fqdn}'

Related

MSAL redirecturi for vue3 app with vue router hash mode resolving as my_host/#/code=....rest-of-aad-response

Since fragments are not supported in aad redirect_uris, I made the redirect_uri my homepage with navigateToLoginRequestUrl. After sign-in, instead of being directed to my_host/#code=...reest-of-aad-response, vue router seems to jump in and hashbang the url to my_host/#/code=...rest-of-aad-response which 404s.
Do I need to switch to history or is there something I am missing and a way to accomplish this in hash mode? Should I use loginPopup instead of loginRedirect?
msal service
import * as msal from '#azure/msal-browser';
export default class msalAuth {
constructor(config) {
const msalConfig = {
auth : {
clientId : config.clientId,
authority : config.authority,
redirectUri : config.redirectUrl,
navigateToLoginRequestUrl : true
},
cache : {
cacheLocation : 'localStorage',
storeAuthStateInCookie : true
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case msal.LogLevel.Error:
console.error(message);
return;
case msal.LogLevel.Info:
console.info(message);
return;
case msal.LogLevel.Verbose:
console.debug(message);
return;
case msal.LogLevel.Warning:
console.warn(message);
return;
}
}
}
}
};
let graphScopes = Object.values(config.graphScopes);
let state = window.location.origin;
let postLogoutRedirectUri = config.logoutRedirect;
let graphUrl = config.graphUrl;
this.msalAppConfig = {
graphScopes,
state,
loginRequest: {
scopes: graphScopes,
state
},
postLogoutRedirectUri,
graphUrl
};
this.app = new msal.PublicClientApplication(msalConfig);
}
login() {
this.app.loginRedirect(this.msalAppConfig.loginRequest);
}
logout(userName) {
const logoutRequest = {
account : this.app.getAccountByUsername(userName),
postLogoutRedirectUri : this.msalAppConfig.postLogoutRedirectUri,
mainWindowRedirectUri : this.msalAppConfig.postLogoutRedirectUri
}
this.app.logoutPopup(logoutRequest);
}
async handleRedirectPromise() {
return await this.app.handleRedirectPromise();
}
processRedirectResponse(response) {
let accountId = '';
console.log('processRedirectResponse', response);
if (response) {
accountId = response.account.homeAccountId;
// Display signed-in user content, call API, etc.
} else {
// In case multiple accounts exist, you can select
const currentAccounts = this.app.getAllAccounts();
if (currentAccounts.length === 0) {
// no accounts signed-in, attempt to sign a user in
//this.loginRedirect();
} else if (currentAccounts.length > 1) {
// Add choose account code here
accountId = currentAccounts[0].homeAccountId;
} else if (currentAccounts.length === 1) {
accountId = currentAccounts[0].homeAccountId;
}
}
return accountId;
}
}
redirectUri is http://localhost:8080 as am still developing
Thanks!
I switched vue router mode to history instead of hash, and it resolved the issue for anyone coming here with the same problem
Edit: for anyone coming to this and being dismayed that I switched to history mode and are using Azure static webapps. I added a staticwebapp.config.json to my public folder (or anywhere which will place it in root of output when built). This file lets you provide some configuration to the static web app. You can read about it in the ms docs but mine was the following which you can edit / build off of
{
"routes": [
{
"route": "/*",
"serve": "/index.html",
"statusCode": 200
}
],
"navigationFallback": {
"rewrite": "/index.html",
"exclude": [
"/icons/*.{png,jpg,gif,webp,svg}",
"/css/*",
"favicon.ico",
"/fonts/*"
]
},
"mimeTypes": {
".woff2": "font/woff2",
".woff": "font/woff",
".json": "text/json",
".ico": "image/x-icon"
}
}

Spring Cloud Contract with multiple requestparts

I'm trying to write a contract to test the following providers endpoint
#PostMapping(value = "/api/{id}/addFiles", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<Void> addFiles(#PathVariable(value = "id") String id, #RequestPart("name") String name, #RequestPart("test") String test, #RequestPart("files") MultiPartFile[] files)
I'm struggling to write a contract that works with multiple RequestParts such as this. If I change the two String RequestParts to RequestParams I can get the test to pass with the following contract:
Contract.make {
description "Add Files"
request {
urlPath("/api/idString/addFiles") {
queryParameters {
parameter 'name': value(consumer(regex(nonEmpty())), producer('name'))
parameter 'test': value(consumer(regex(nonEmpty())), producer('test'))
}
}
method POST()
headers {
contentType multipartFormData()
}
multipart(
files: named(
name: value(consumer(regex(nonEmpty())), producer('fileName')),
content: value(consumer(regex(nonEmpty())), producer('fileContent'))
)
)
}
response {
status ACCEPTED()
}
}
But is there a way of writing this contract whilst keeping everything as RequestParts? Nothing I've tried so far has come close to working!
Answering my own question since I realised the small error I had been making. The following contract appears to work, I had tried something similar but had not included the square brackets inside the multipart:
Contract.make {
description "Add Files"
request {
urlPath("/api/idString/addFiles")
method POST()
headers {
contentType multipartFormData()
}
multipart([
name: named(
name: value(consumer(regex(nonEmpty())), producer('name')),
content: value(consumer(regex(nonEmpty())), producer('name'))
),
test: named(
name: value(consumer(regex(nonEmpty())), producer('test')),
content: value(consumer(regex(nonEmpty())), producer('testName'))
),
files: named(
name: value(consumer(regex(nonEmpty())), producer('fileName')),
content: value(consumer(regex(nonEmpty())), producer('fileContent'))
)
])
}
response {
status ACCEPTED()
}
}

Bicep Pass storage account connection string to key vault

I have 2 resource groups as follow:
rg-shared
rg-storage-accounts
in resource group one I am trying to create a storage account and get its connection string and pass it to resourcegroup2 on which I have a key vault.
my actual code is as follow.
Shared.bicep
targetScope = 'resourceGroup'
param deploymentIdOne string = newGuid()
param deploymentIdTwo string = newGuid()
output deploymentIdOne string = '${deploymentIdOne}-${deploymentIdTwo}'
output deploymentIdTwo string = deploymentIdTwo
param keyvaultmain string = 'Name-keyvault'
param keyvaultshared string = 'Name-keyvault'
param sharedManagedIdentity string = 'Name-Managed-identity'
param storageAccountString string
var storagePrefix = 'sttesteur'
var clientDataKeyPrefix = 'Key-Data-'
var learnersguidsecrets = 'Guidtest'
param tenantCodes array = [
'tste'
]
resource keyVaultClients 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultmain
}
resource keyVaultShared 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultshared
}
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities#2018-11-30' = {
name: sharedManagedIdentity
location: resourceGroup().location
}
resource kvClientsKey 'Microsoft.KeyVault/vaults/keys#2021-06-01-preview' = [for code in tenantCodes: {
name: '${keyVaultClients.name}/${clientDataKeyPrefix}${toUpper(code)}'
properties: {
keySize: 2048
kty: 'RSA'
// Assign the least permission
keyOps: [
'unwrapKey'
'wrapKey'
]
}
}]
resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies#2021-06-01-preview' = {
name: '${keyVaultClients.name}/add'
properties: {
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: managedIdentity.properties.principalId
permissions: {
// minimum required permission
keys: [
'get'
'unwrapKey'
'wrapKey'
]
}
}
]
}
}
resource clientLearnersGuid 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
name: '${keyVaultClients.name}/${tenant}${learnersguidsecrets}'
properties: {
contentType: 'GUID Key'
value: '${deploymentIdOne}-${deploymentIdTwo}'
}
}]
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
name: '${keyVaultShared.name}${storagePrefix}${tenant}'
properties:{
contentType: '${tenant} Storage Account Connection String'
value: storageAccountString
}
}]
And this is my storage-account.bicep
param tenantCodes array = [
'tste'
]
param tenantManagedIdentity string = 'Manage-identity-Name'
param secondresource string = 'rg-sec-eur-shared'
var keyVaultKeyPrefix = 'Key-Data-'
var storagePrefix = 'sthritesteur'
// Create a managed identity
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities#2018-11-30' = {
name: tenantManagedIdentity
location: resourceGroup().location
}
// Create storage accounts
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-04-01' = [for tenantCode in tenantCodes: {
name: '${storagePrefix}${tenantCode}'
location: resourceGroup().location
kind: 'StorageV2'
sku: {
name: 'Standard_RAGRS'
}
// Assign the identity
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
properties: {
allowCrossTenantReplication: true
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
allowSharedKeyAccess: true
networkAcls: {
bypass: 'AzureServices'
virtualNetworkRules: []
ipRules: []
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
identity: {
// specify which identity to use
userAssignedIdentity: managedIdentity.id
}
keySource: 'Microsoft.Keyvault'
keyvaultproperties: {
keyname: '${keyVaultKeyPrefix}${toUpper(tenantCode)}'
// keyvaulturi: keyVault.properties.vaultUri
keyvaulturi:'https://keyvaultclient.vault.azure.net'
}
services: {
file: {
keyType: 'Account'
enabled: true
}
blob: {
keyType: 'Account'
enabled: true
}
}
}
accessTier: 'Hot'
}
}]
resource storage_Accounts_name_default 'Microsoft.Storage/storageAccounts/blobServices#2021-04-01' = [ for (storageName, i) in tenantCodes :{
parent: storageAccount[i]
name: 'default'
properties: {
changeFeed: {
enabled: false
}
restorePolicy: {
enabled: false
}
containerDeleteRetentionPolicy: {
enabled: true
days: 7
}
cors: {
corsRules: []
}
deleteRetentionPolicy: {
enabled: true
days: 30
}
isVersioningEnabled: true
}
}]
module connectionString 'shared.bicep' = [for (storageName, i) in tenantCodes :{
scope: resourceGroup(secondresource)
name: storageName
params: {
storageAccountString: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount[i].name};AccountKey=${listKeys(storageAccount[i].id, storageAccount[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
}
}]
This is the details of this workflow.
in the resource group rg-sharedi have 2 key vaults, keyvault-sharedand keyvaultstorage. And their purpose is as follow:
keyvault-shared => Store StorageAccount Connection String as Secret
keyvault-storage => Generate a Key Name based on the `tenantCode` in the key section, and in secret, generate a GUID and store it
while in the other resource-group rg-storage I want to create a storage account, encrypt the storage account with the key I have generated in the keyault earlier, and pass the connection string of this storageAccount to the shared key vault.
Following your advice, I used the module from shared.bicep and called it in my storage account.bicep.
Based on my command:
az deployment group what-if -f ./storage-account.bicep -g rg-storage-accounts
the output It shows that will create only the resource in the storage-account.bicep:
user identity
storageAccount
container
How to reproduce:
Create 2 resource groups (shared and storage accounts)
in Shared create 2 key vaults
Update the bicep files with the correct key vault names.
In both bicep scripts in tenantCode put a random name to create a storage account or multiple storage accounts.
and run the above bicep command.
I tried to explain as clear as I could this issue, as its driving me crazy and have no idea what I am doing wrong and this stage.
Please please, if you need anymore information about this issue, just ask and will be glad to clarify any doubt
UPDATE:
To generate the key before hand, I moved the key creation into the storage.bicep as follow:
resource keyVaultClients 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultmain
scope: resourceGroup(secondresource)
}
resource kvClientsKey 'Microsoft.KeyVault/vaults/keys#2021-06-01-preview' = [for code in tenantCodes: {
name: '${keyVaultClients.name}-${clientDataKeyPrefix}${toUpper(code)}'
properties: {
keySize: 2048
kty: 'RSA'
// Assign the least permission
keyOps: [
'unwrapKey'
'wrapKey'
]
}
}]
but I get this error:
{"error":{"code":"InvalidTemplate","message":"Deployment template validation failed: 'The template resource 'keyvault-Key-Data-ORNX' for type 'Microsoft.KeyVault/vaults/keys' at line '54' and column '46' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name. Please see https://aka.ms/arm-template/#resources for usage details.'.","additionalInfo":[{"type":"TemplateViolation","info":{"lineNumber":54,"linePosition":46,"path":"properties.template.resources[1].type"}}]}}
Which I don't understand exactly to what refers.
UPDATE:
This is an interesting output. So according to the last update (and thank you so so much for your help) I realised that at the code is creating all the correct resource, but at the very end it throws this error:
{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"Conflict","message":"{\r\n \"status\": \"Failed\",\r\n \"error\": {\r\n \"code\": \"ResourceDeploymentFailure\",\r\n \"message\": \"The resource operation completed with terminal provisioning state 'Failed'.\",\r\n \"details\": [\r\n {\r\n \"code\": \"DeploymentFailed\",\r\n \"message\": \"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.\",\r\n \"details\": [\r\n {\r\n \"code\": \"Conflict\",\r\n \"message\": \"{\\r\\n \\\"error\\\": {\\r\\n \\\"code\\\": \\\"StorageAccountOperationInProgress\\\",\\r\\n \\\"message\\\": \\\"An operation is currently performing on this storage account that requires exclusive access.\\\"\\r\\n }\\r\\n}\"\r\n },\r\n {\r\n \"code\": \"Conflict\",\r\n \"message\": \"{\\r\\n \\\"error\\\": {\\r\\n \\\"code\\\": \\\"StorageAccountOperationInProgress\\\",\\r\\n \\\"message\\\": \\\"An operation is currently performing on this storage account that requires exclusive access.\\\"\\r\\n }\\r\\n}\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n}"}]}}
For testing , I used nested template module for creating a single Storage account and then stored the connection string in the key vault present in the another resource group.
Scenario:
Keyvaultclient.bicep>>nested(storage.bicep)>>nested(shared.bicep)
Code:
Keyvaultclient.bicep:
param deploymentIdOne string = newGuid()
param deploymentIdTwo string = newGuid()
output deploymentIdOne string = '${deploymentIdOne}-${deploymentIdTwo}'
output deploymentIdTwo string = deploymentIdTwo
param storagerg string = 'rgnamewherestorageaccountistobecreated'
param sharedManagedIdentity string = 'identityforkeyvault'
param keyvaultmain string = 'keyvaultclienttes1234'
param tenantCodes array = [
'tste'
]
var clientDataKeyPrefix = 'Key-Data-'
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities#2018-11-30' = {
name: sharedManagedIdentity
location: resourceGroup().location
}
resource keyVaultClients 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultmain
}
resource kvClientsKey 'Microsoft.KeyVault/vaults/keys#2021-06-01-preview' = [for code in tenantCodes: {
parent:keyVaultClients
name: '${keyVaultClients.name}-${clientDataKeyPrefix}${toUpper(code)}'
properties: {
keySize: 2048
kty: 'RSA'
// Assign the least permission
keyOps: [
'unwrapKey'
'wrapKey'
]
}
}]
resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies#2021-06-01-preview' = {
parent:keyVaultClients
name: 'add'
properties: {
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: managedIdentity.properties.principalId
permissions: {
// minimum required permission
keys: [
'get'
'unwrapKey'
'wrapKey'
]
}
}
]
}
}
resource clientLearnersGuid 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
parent:keyVaultClients
name: '${keyVaultClients.name}${tenant}'
properties: {
contentType: 'GUID Key'
value: '${deploymentIdOne}-${deploymentIdTwo}'
}
dependsOn:kvClientsKey
}]
module StorageAccount './storage.bicep' = [for (storageName, i) in tenantCodes :{
scope: resourceGroup(storagerg)
name: storageName
params: {
ManagedIdentityid:managedIdentity.id
kvname:keyVaultClients.name
uri:keyVaultClients.properties.vaultUri
}
dependsOn:clientLearnersGuid
}]
Storage.bicep:
param tenantCodes array = [
'tste'
]
param ManagedIdentityid string
param uri string
param kvname string
param keyvaultrg string = 'rgwherethekeyvaultsarepresent'
var keyVaultKeyPrefix = 'Key-Data-'
var storagePrefix = 'sthritesteur'
// Create storage accounts
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-04-01' = [for tenantCode in tenantCodes: {
name: '${storagePrefix}${tenantCode}'
location: resourceGroup().location
kind: 'StorageV2'
sku: {
name: 'Standard_RAGRS'
}
// Assign the identity
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${ManagedIdentityid}':{}
}
}
properties: {
allowCrossTenantReplication: true
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
allowSharedKeyAccess: true
networkAcls: {
bypass: 'AzureServices'
virtualNetworkRules: []
ipRules: []
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
identity: {
// specify which identity to use
userAssignedIdentity: ManagedIdentityid
}
keySource: 'Microsoft.Keyvault'
keyvaultproperties: {
keyname: '${kvname}-${keyVaultKeyPrefix}${toUpper(tenantCode)}'
keyvaulturi:uri
}
services: {
file: {
keyType: 'Account'
enabled: true
}
blob: {
keyType: 'Account'
enabled: true
}
}
}
accessTier: 'Hot'
}
}]
resource storage_Accounts_name_default 'Microsoft.Storage/storageAccounts/blobServices#2021-04-01' = [ for (storageName, i) in tenantCodes :{
parent: storageAccount[i]
name: 'default'
properties: {
changeFeed: {
enabled: false
}
restorePolicy: {
enabled: false
}
containerDeleteRetentionPolicy: {
enabled: true
days: 7
}
cors: {
corsRules: []
}
deleteRetentionPolicy: {
enabled: true
days: 30
}
isVersioningEnabled: true
}
}]
module connectionString './shared.bicep' = [for (storageName, i) in tenantCodes :{
scope: resourceGroup(keyvaultrg)
name: storageName
params: {
storageAccountString: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount[i].name};AccountKey=${listKeys(storageAccount[i].id, storageAccount[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
}
}]
shared.bicep:
param keyvaultshared string = 'keyvaultsharedtest12345'
param storageAccountString string
param tenantCodes array = [
'tste'
]
resource keyVaultShared 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultshared
}
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
parent:keyVaultShared
name: '${keyVaultShared.name}-test${tenant}'
properties:{
contentType: '${tenant} Storage Account Connection String'
value: storageAccountString
}
}]
Output:
keyvaultclient.bicep will be deployed to the kvresourcegroup:
az deployment group create -n TestDeployment -g keyvaultrg --template-file "path\to\keyvaultclient.bicep"

How to change a schema key?

I have a schema defined below and how can I change the predefined schema key (summary: key) via meteor template?
Schemas.Books = new SimpleSchema(
{
summary: {
type: String
}
}
);
For instance, I want to change this key through a session variable that was defined by router or through a user input.
Not Sure, Try this
If your schema is like this
Books = new SimpleSchema(
{
summary: {
type: String
}
}
);
then in tempalte helpers,
Books._schema.summary.type = function() {
return Session.get("typeValue");
};
In my project I have schema like this
RegisterSchema = new SimpleSchema({
name: {
type: String
},
email: {
type: String,
regEx: SimpleSchema.RegEx.Email
},
password: {
type: String,
label: "Password",
min: 8
},
confirmPassword: {
type: String,
label: "Confirm Password",
min: 8,
custom: function () {
if (this.value !== this.field('password').value) {
return "passwordMismatch";
}
}
}
});
and I'm dynamically setting optional value for email like
RegisterSchema._schema.email.optional = function() { return true };
this worked for me.
All d best
This is not the thing that I'm trying to do but I have learned a new trick : )
I want to change the schema key that I described above like this.
Books = new SimpleSchema(
{
bookName: {
type: String
}
}
);
Changing summary: with bookName:
Actually I want to define schema keys dynamically with respect to user information (userId, userName etc.).

How can a Qbs build Rule use a product

I want to use Qbs to compile an existing project. This project already contains a code-transformation-tool (my_tool) that is used heavily in this project.
So far I have (simplified):
import qbs 1.0
Project {
Application {
name: "my_tool"
files: "my_tool/main.cpp"
Depends { name: "cpp" }
}
Application {
name: "my_app"
Group {
files: 'main.cpp.in'
fileTags: ['cpp_in']
}
Depends { name: "cpp" }
Rule {
inputs: ["cpp_in"]
Artifact {
fileName: input.baseName
fileTags: "cpp"
}
prepare: {
var mytool = /* Reference to my_tool */;
var cmd = new Command(mytool, input.fileName, output.fileName);
cmd.description = "Generate\t" + input.baseName;
cmd.highlight = "codegen";
return cmd;
}
}
}
}
How can I get the reference to my_tool for the command?
This answer is based on an email from Qbs author Joerg Bornemann who allowed me to cite it here.
The property usings of Rule allows to add artifacts from products dependencies to the inputs.
In this case we are interested in "application" artifacts.
The list of applications could then be accessed as input.application.
Application {
name: "my_app"
Group {
files: 'main.cpp.in'
fileTags: ['cpp_in']
}
Depends { name: "cpp" }
// we need this dependency to make sure that my_tool exists before building my_app
Depends { name: "my_tool" }
Rule {
inputs: ["cpp_in"]
usings: ["application"] // dependent "application" products appear in inputs
Artifact {
fileName: input.completeBaseName
fileTags: "cpp"
}
prepare: {
// inputs["application"] is a list of "application" products
var mytool = inputs["application"][0].fileName;
var cmd = new Command(mytool, [inputs["cpp_in"][0].fileName, output.fileName]);
cmd.description = "Generate\t" + input.baseName;
cmd.highlight = "codegen";
return cmd;
}
}
}
Unfortunately the usings property in a Rule is deprecated since QBS 1.5.0. At the moment I have the same requirement. Using a product artifact in a non multiplex Rule.
The problem with a multiplex Rule is, if a single file in the input set changes, all input artifacts will be re-processed. Which is rather time consuming in my case.

Resources