I am trying to create an instance to boot from cinder volume as root-disk (vda). Flavor is created/defined with 0 on root-disk.
Below heat template, it is clearly mentioned that boot_index = 0 is
device_name: specifies the name of the device. Standard format of disk name is supported, for example /dev/vda. When the boot_index is set to 0, this field is mandatory. When boot_index is set to -1, this field is optional. The chosen devices must match the disk_bus types.
boot_index: specifies the boot identifier. This value is mandatory, 0 is specifies a boot disk, and -1 specifies a non-boot disk.
I am kepting getting this error "Block Device Mapping is Invalid: Boot sequence for the instance and image/block device mapping combination is not valid. (HTTP 400) (Request-ID: req-e31e0dd6-adc1-4f74-b073-84d850c1bd84)"
Can anyone share your views please? Thanks.
I even removed those -1 vdb/vdc and vdd non-bootable volumes and got same error. Thanks.
Andrew
I commented our vda since it complainted "volume cannot be assigned the same device name as the root device vda"
AVA-1:
type: OS::Nova::Server
properties:
availability_zone: { get_param: availability_zone }
name: { str_replace: { template: $prefix_$name, params: { $prefix: { get_param: prefix }, $name: {get_param: ava1_name}}}}
image: { get_param: ava_image_name }
flavor: { get_param: flavor }
key_name: { get_param: ava_key_name }
block_device_mapping_v2:
- volume_id: { get_param: ava1_volume_id_rootdisk }
boot_index: 0
#device_name: vda
- { boot_index: "-1", device_name: "vdb", volume_id: { get_param: ava1_volume_id_amu } }
- { boot_index: "-1", device_name: "vdc", volume_id: { get_param: ava1_volume_id_vmu0 } }
- { boot_index: "-1", device_name: "vdd", volume_id: { get_param: ava1_volume_id_vmu1 } }
Related
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}'
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"
I'm trying to create a stack with a template file and an environment parameter file. Below are my details.
In Template File:
v6_ip:
type: string
description: ipv6 address
constraints:
- length: { min: 1, max: 46 }
default: 0
v6_prefix_len:
type: number
description: ipv6 prefix length
constraints:
- range: { min: 0, max: 128 }
default: 0
v6_gateway:
type: string
description: ipv6 default gateway
constraints:
- length: { min: 1, max: 46 }
default: 0
server:
type: OS::Nova::Server
properties:
name: { get_param : my_name }
metadata:
config_drive: True
user_data:
params:
$IPV4: { get_param: v4_ip }
$V4_NETMASK: { get_param: v4_netmask }
$V4_GW: { get_param: v4_gateway }
$IPV6: { get_param: v6_ip }
$V6_PREFIX: { get_param: v6_prefix_len }
$V6_GW: { get_param: v6_gateway }
The environment file:
v4_ip: 192.168.11.179
v4_netmask: 255.255.240.0
v4_gateway: 192.168.0.254
v6_ip: fd5d:d50a:8c17:2110::2019
v6_prefix_len: 64
v6_gateway: fd5d:d50a:8c17:2110::ff
When I try to create the stack, I'm getting the below error:
ERROR: Parameter 'v6_gateway' is invalid: Invalid default 0 (object of
type 'int' has no len())
I've defined v6_gateway as string and default value is 0. The same thing for v4_gateway it's accepting. Why it's throwing an error for v6_gateway? Also how to resolve it?
PS: I'm using openstack newton version.
The problem is that your default gateway is an number, and not a string. If you really need the default 0 to be valid as-is, you can wrap it with apostrophes.
v6_gateway:
type: string
description: ipv6 default gateway
constraints:
- length: { min: 1, max: 46 }
default: '0'
I am trying to compile a rules.json for the following Blaze YAML file:
functions:
- isLoggedIn(): auth.id !== null
schema:
type: object
properties:
projects:
type: object
$projectId:
type: object
properties:
roles:
type: object
$permissionId:
type: object
$roleId: {type: boolean}
access:
- location: /projects/$projectId/
write: isLoggedIn() && (!next.exists() || next.hasChildren())
When I compile it with blaze I get the following JSON:
{
"rules":{
".write":"false",
".read":"false",
"projects": {
".write":"false",
".read":"false",
"$projectId": {
".write":"(((false)))",
".read":"false",
"roles": {
".write":"((false))",
".read":"false",
"$permissionId": {
".write":"((false))",
".read":"false",
"$roleId": {
".write":"(((!newData.parent().parent().parent().parent().parent().exists()||!(((newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))))&&(!newData.parent().parent().parent().parent().exists()||!(((newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))))&&(!newData.parent().parent().parent().exists()||!(((newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))))&&(!newData.parent().parent().exists()||!(((newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))))&&(!newData.parent().exists()||!(((newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))))&&(!newData.exists()||newData.isBoolean())&&auth.id!==null&&(!newData.parent().parent().parent().exists()||newData.parent().parent().parent().hasChildren())))",
".read":"false"
}
}
}
}
}
}
}
I would have expected the $projectId.write rule to contain the compiled version of isLoggedIn() && (!next.exists() || next.hasChildren()) but instead it contains (((false))).
Is this a bug in blaze or are my YAML rules not constructed correctly? If it is not correct, where have I gone wrong?
its not a bug but some subtleties related to nesting of wildchilds. "The use of a wildchild prevents all ascendents from being writable." [1]
You can use a wilderchild instead on the $projectId by "~$projectId" (note that comes with some security considerations, you won't be able to prevent logged in users from deleting $permissionId records[2])
functions:
- isLoggedIn(): auth.id !== null
schema:
type: object
properties:
projects:
type: object
~$projectId:
type: object
properties:
roles:
type: object
$permissionId:
type: object
$roleId: {type: boolean}
access:
- location: /projects/$projectId/
write: isLoggedIn() && (!next.exists() || next.hasChildren())
[1] https://github.com/firebase/blaze_compiler#wildchild
[2] https://github.com/firebase/blaze_compiler#wilderchild
I'm trying elasticsearch and it looks great!
I noticed, however, a problem very uncomfortable, in a field that contains hello world if I search hello wo returns no result!
Why does this happen?
Place my configuration (FOSElasticaBundle):
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
serializer:
callback_class: FOS\ElasticaBundle\Serializer\Callback
serializer: serializer
indexes:
website:
client: default
settings:
index:
analysis:
analyzer:
custom_search_analyzer:
type: custom
tokenizer: standard
filter : [standard, worddelimiter, stopwords, snowball, lowercase, asciifolding]
custom_index_analyzer:
type: custom
tokenizer: nGram
filter : [standard, worddelimiter, stopwords, snowball, lowercase, asciifolding]
filter:
stopwords:
type: stop
stopwords: [_italian_]
ignore_case : true
worddelimiter :
type: word_delimiter
tokenizer:
nGram:
type: nGram
min_gram: 1
max_gram: 20
types:
structure:
mappings:
name: { boost: 9, search_analyzer: custom_search_analyzer, index_analyzer: custom_index_analyzer, type: string }
Any idea on how to solve?
EDIT
Here my query:
{
query: {
bool: {
must: [ ]
must_not: [ ]
should: [
{
term: {
structure.name: hello wo
}
}
]
}
}
from: 0
size: 10
sort: [ ]
facets: { }
}
EDIT 2
Ok, I don't understand this behavior ...
Now I run this query:
{
query: {
bool: {
must: [
{
term: {
structure.name: hello
}
}
{
term: {
structure.name: wo
}
}
]
must_not: [ ]
should: [ ]
}
}
from: 0
size: 10
sort: [ ]
facets: { }
}
This query is the result I wanted, but I do not understand what is the difference in putting a must with two words and two must have a word with everyone!
I could explain this behavior?
Well i need to explain you probably how its working
When you index text elastic search will try to split it to terms if text is analyzed(as its in your mapping) so in your case "hello world" will be spited to two terms "hello" and "world" when you will do term search you write term hello world which does not fit any of your two terms.
To avoid spiting to terms you can set in mapping that field name is not analyzed, then it will not be spitted to two words and will be handled as one token.
Other solution is you can multiterm query
{
"query": {
"terms": {
"structure.name": [
"world",
"hello"
]
}
}
}
Also when you use query_string it return result since it has different algorithm.
So depends on you needs you should use different queries, but to search by name you should use query_string, term should be used if you want to filter lets say categoryId, tags and stuff like that.