Azure资源管理器精简版Kusto如何模拟DUAL表实现常量查询?
问题
在Kusto中,是否可以无需源表直接选择常量值?例如类似Oracle中使用DUAL表(或其他多数查询语言中无FROM子句的SELECT语句)的方式?
示例:() | project colA = 'hello', colB = 'world'……但该语句无法运行。
注:我需要的是适用于Azure资源管理器中Kusto精简版的解决方案。
背景
注:这是一个XY问题,上述问题的解决方案可作为我实际问题的变通方案……以下是我要解决的真实问题。
我有一个查询用于判断给定CIDR是否与Azure中现有虚拟网络(VNet)重叠,以便在分配新CIDR前进行测试,或查找给定IP所属的VNet:
resources | where type =~ 'Microsoft.Network/virtualNetworks' | project id, subscriptionId, resourceGroup, name, addressPrefixes = properties['addressSpace'].['addressPrefixes'] | mv-expand addressPrefixes | extend cidrSplit = array_concat(split(split(addressPrefixes, '/')[0],'.'), split(split(addressPrefixes, '/')[1],'x')) | extend firstIpVal = toint(cidrSplit[0]) * 16777216 + toint(cidrSplit[1]) * 65536 + toint(cidrSplit[2]) * 256 + toint(cidrSplit[3]) | extend lastIpVal = firstIpVal + pow(2,32-cidrSplit[4])-1 | project-away cidrSplit // 10.11.12.13/28 defined in both rows below: | where firstIpVal <= 10 * 16777216 + 11 * 65536 + 12 * 256 + 13 + pow(2,32-28)-1 and lastIpVal >= 10 * 16777216 + 11 * 65536 + 12 * 256 + 13 | project subscriptionId, resourceGroup, name, addressPrefixes, firstIpVal, lastIpVal | order by firstIpVal, lastIpVal
但上述查询难以针对不同CIDR进行更新,也不方便阅读者识别当前查询的CIDR。
我更希望采用如下形式,但Azure资源管理器不支持变量定义:
let newCidr = "10.11.12.13/28"; let newCidrSplit = array_concat(split(split(newCidr, '/')[0],'.'), split(split(newCidr, '/')[1],'x')) let newCidrFirst = toint(newCidrSplit[0]) * 16777216 + toint(newCidrSplit[1]) * 65536 + toint(newCidrSplit[2]) * 256 + toint(newCidrSplit[3]); let newCidrLast = newCidrFirst + pow(2,32-newCidrSplit[4])-1; resources | where type =~ 'Microsoft.Network/virtualNetworks' | project id, subscriptionId, resourceGroup, name, addressPrefixes = properties['addressSpace'].['addressPrefixes'] | mv-expand addressPrefixes | extend cidrSplit = array_concat(split(split(addressPrefixes, '/')[0],'.'), split(split(addressPrefixes, '/')[1],'x')) | extend firstIpVal = toint(cidrSplit[0]) * 16777216 + toint(cidrSplit[1]) * 65536 + toint(cidrSplit[2]) * 256 + toint(cidrSplit[3]) | extend lastIpVal = firstIpVal + pow(2,32-cidrSplit[4])-1 | project-away cidrSplit | where firstIpVal <= newCidrLast and lastIpVal >= newCidrFirst | project subscriptionId, resourceGroup, name, addressPrefixes, firstIpVal, lastIpVal | order by firstIpVal, lastIpVal
因此我希望找到无需定义变量即可实现“变量”功能的方法;例如若存在dual表(确保始终仅有一行的表),我可以采用如下方式(虽略显繁琐,但便于修改查询的IP,且易于阅读):
dual // i.e. a table with one row, where we don't really care about the row's contents | project testCidr = "10.11.12.13/28" // set the "variable" here; one place in an easy to read format, near the top so it's easy to spot | extend testCidrSplit = array_concat(split(split(testCidr, '/')[0],'.'), split(split(testCidr, '/')[1],'x')) | extend testCidrFirstIp = toint(testCidrSplit[0]) * 16777216 + toint(testCidrSplit[1]) * 65536 + toint(testCidrSplit[2]) * 256 + toint(testCidrSplit[3]) | extend testCidrLastIp = testCidrFirstIp + pow(2,32-testCidrSplit[4])-1 | extend joinhack = 1 | join kind = inner ( resources | where type =~ 'Microsoft.Network/virtualNetworks' | project id, subscriptionId, resourceGroup, name, addressPrefixes = properties['addressSpace'].['addressPrefixes'], joinhack = 1 | mv-expand addressPrefixes | extend cidrSplit = array_concat(split(split(addressPrefixes, '/')[0],'.'), split(split(addressPrefixes, '/')[1],'x')) | extend firstIpVal = toint(cidrSplit[0]) * 16777216 + toint(cidrSplit[1]) * 65536 + toint(cidrSplit[2]) * 256 + toint(cidrSplit[3]) | extend lastIpVal = firstIpVal + pow(2,32-cidrSplit[4])-1 | project-away cidrSplit ) on joinhack | where firstIpVal <= testCidrLastIp and lastIpVal >= testCidrfirstIp | project subscriptionId, resourceGroup, name, addressPrefixes, firstIpVal, lastIpVal | order by firstIpVal, lastIpVal
注:我当然可以用查询订阅的方式替代上述dual(假设查询时至少存在一个订阅),再用limit获取一行……但这种方式过于繁琐,我希望从语言层面找到解决方案。
resourcecontainers | where type == "microsoft.resources/subscriptions" | limit 1 | project colA = 'hello', colB = 'world'
解决方案
直接获取常量值的方法
在Kusto(包括Azure资源管理器中的精简版)中,可使用print语句直接生成包含常量值的单行结果,无需依赖任何源表,效果等同于Oracle的DUAL表:
print colA = 'hello', colB = 'world'
针对CIDR重叠检测的优化查询
利用print语句替代设想的dual表,可实现集中管理测试CIDR的需求,同时兼容Azure资源管理器的Kusto精简版:
// 只需修改此处的testCidr值即可 print testCidr = "10.11.12.13/28" | extend testCidrParts = split(testCidr, '/') | extend testIpParts = split(testCidrParts[0], '.') | extend testPrefixLen = toint(testCidrParts[1]) | extend testCidrFirstIp = toint(testIpParts[0]) * 16777216 + toint(testIpParts[1]) * 65536 + toint(testIpParts[2]) * 256 + toint(testIpParts[3]) | extend testCidrLastIp = testCidrFirstIp + pow(2, 32 - testPrefixLen) - 1 | extend joinhack = 1 | join kind=inner ( resources | where type =~ 'Microsoft.Network/virtualNetworks' | project subscriptionId, resourceGroup, name, addressPrefixes = properties['addressSpace'].['addressPrefixes'] | mv-expand addressPrefixes | extend cidrParts = split(addressPrefixes, '/') | extend ipParts = split(cidrParts[0], '.') | extend prefixLen = toint(cidrParts[1]) | extend firstIpVal = toint(ipParts[0]) * 16777216 + toint(ipParts[1]) * 65536 + toint(ipParts[2]) * 256 + toint(ipParts[3]) | extend lastIpVal = firstIpVal + pow(2, 32 - prefixLen) - 1 | project-away cidrParts, ipParts, prefixLen | extend joinhack = 1 ) on joinhack | where firstIpVal <= testCidrLastIp and lastIpVal >= testCidrFirstIp | project subscriptionId, resourceGroup, name, addressPrefixes, firstIpVal, lastIpVal | order by firstIpVal, lastIpVal
该查询做了以下优化:
- 用
print直接定义测试CIDR,无需依赖其他表 - 拆分CIDR的逻辑更清晰,避免嵌套split导致的可读性问题
- 明确转换前缀长度为整数类型,避免潜在的类型错误
- 移除了不必要的字段投影,简化查询结构
内容的提问来源于stack exchange,提问作者JohnLBevan

