運維編排場景系列-----如何使用jq

本文主要講解在OOS如何對任務中的值進行篩選,任務中值的篩選主要依賴模版中兩個常見字段,一個是ValueSelector,另一個是PropertySelector,且這兩個字段必須配合jq表達式使用。那麼接下來就分別講下jq是什麼,兩個篩選字段何時需要定義、在哪定義和作用,以及各場景下jq表達式使用的分析。

jq介紹

jq 是一個開源的數據處理工具,它可處理JSON格式的數據,比如按照您指定的jq表達式,篩選出JSON中你想要的部分。篩選時,jq把JSON格式的數據作爲input,並根據指定的jq表達式進行篩選,然後返回一個output。jq有很多靈活的使用方法,詳見後附的jq語法手冊。

OOS中的篩選字段

先說下OOS任務中值的篩選目的,無非兩種,一種是篩出期待的結果,並將其賦值給某個參數,供其他任務使用該參數;另一種則是篩選出期待的結果,在任務中將結果值與預先指定的值進行比較,用來檢查某種條件。所以OOS中有兩個用來篩選的字段,分別是ValueSelector和PropertySelector,前者用在給參數賦值前,後者用在檢查某個條件前。

當任務有具體Outputs時,需要在Outputs中定義ValueSelector字段,該字段用來篩選任務動作返回的值,並且將篩選結果賦值給Outputs輸出的參數。具體講,如任務的動作爲API類動作,則動作返回值即任務調用API後返回的JSON值;若任務的動作爲事件觸發器,則動作返回值爲觸發器監控事件發生的JSON消息通知體。篩選方式是jq把動作返回值作爲輸入參數,通過字段的jq表達式進行篩選,篩選結果作爲任務的Outputs輸出參數值。

當任務的動作爲ACS::WaitFor 或ACS::CheckFor時,需要在任務的Properties部分定義PropertySelector字段,
該字段用來篩選任務調用API返回的JSON值,篩選方式是jq把API返回的JSON作爲輸入參數,並通過字段的jq表達式進行篩選,最後OOS將篩選結果與Properties中的DesiredValues或NotDesiredValues字段內包含的值進行比較,比較結果作爲任務等待或判斷的參考,進而執行後面的邏輯。

jq在OOS中的使用

下面帶大家分析下一些公共模版中jq表達式的使用。

ValueSelector

場景1

FormatVersion: OOS-2019-06-01
Description: Adds backend servers by specifying tag.
Parameters:
  loadBalancerId:
    Description: The ID of the SLB instance.
    Type: String
    AllowedPattern: lb-[A-Za-z0-9]*
    MaxLength: 30
    MinLength: 1
  tagKey:
    Description: The specific tag key.
    Type: String
    MinLength: 1
  tagValue:
    Description: The specific tag value.
    Type: String
    MaxLength: 30
    MinLength: 1
  OOSAssumeRole:
    Description: The RAM role to be assumed by OOS.
    Type: String
    Default: OOSServiceRole
RamRole: '{{ OOSAssumeRole }}'
Tasks:
- Name: describeRunningInstancesByTag
  Action: ACS::ExecuteApi
  Description: Views the ECS instances by specifying tag.
  Properties:
    Service: ECS
    API: DescribeInstances
    Parameters:
      Status: Running
      Tags:
      - Key: '{{ tagKey }}'
        Value: '{{ tagValue }}'
  Outputs:
    instanceIds:
      Type: List
      ValueSelector: .Instances.Instance[].InstanceId

我們來看下上面的模版,請直接看Tasks部分的describeRunningInstancesByTag任務,該任務是有具體Outputs的,其定義了輸出名稱爲instanceIds的參數,參數Type爲List,同時也定義了ValueSelector字段,並且該字段的jq表達式爲.Instances.Instance[].InstanceId
就如Outputs中參數名 instanceIds 字面意思,其表示輸出API返回結果中所有ECS實例ID,那麼該任務調用的API是DescribeInstances,API返回的JSON結果樣例如下。結合此JSON樣例,我們看下在.Instances.Instance[].InstanceId作用下,instanceIds最終返回值的獲取過程。首先篩選出JSON中Key爲Instances的結果,然後對結果繼續篩選,獲取Key爲Instance的結果,該結果是一個數組,此時又對所得結果進行迭代,並將每個迭代結果中Key爲InstanceId的值以List類型進行返回,於是得到最終返回值["id-001","id-002"],即'{{describeRunningInstancesByTag.instanceIds}}'的值爲["id-001","id-002"]'。

API調用返回樣例(JSON)

{
    "PageNumber":"1",
    "TotalCount":"1",
    "PageSize":"10",
    "RequestId":"14A07460-EBE7-47CA-9757-12CC4761D47A",
    "Instances":{
        "Instance":[
            {
                "ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
                "InnerIpAddress":{
                    "IpAddress":[
                        "10.170.XX.XXX"
                    ]
                },
                "InstanceId":"id-001",
                "EipAddress":{},
                "InternetMaxBandwidthIn":"-1",
                "ZoneId":"cn-shenzhen-a",
                "InstanceNetworkType":"classic",
                "PublicIpAddress":{
                    "IpAddress":[
                        "120.25.XX.XXX"
                    ]
                },
                "InternetChargeType":"PayByTraffic",
                "HostName":"iZ94t3s0j***",
                "InstanceType":"ecs.s2.large",
                "SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
                "IoOptimized":"false",
                "CreationTime":"2015-07-27T07:08Z",
                "Status":"Running",
                "VpcAttributes":{
                    "PrivateIpAddress":{
                        "IpAddress":[]
                    }
                },
                "InternetMaxBandwidthOut":"1",
                "SecurityGroupIds":{
                    "SecurityGroupId":[
                        "sg-94kd0c***"
                    ]
                },
                "RegionId":"cn-shenzhen",
                "OperationLocks":{
                    "LockReason":[]
                },
                "InstanceChargeType":"PostPaid",
                "ExpiredTime":"2011-09-08T16:00Z",
                "InstanceName":"FinanceJoshua1"
            },            
      {
                "ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
                "InnerIpAddress":{
                    "IpAddress":[
                        "10.170.XX.XXX"
                    ]
                },
                "InstanceId":"id-002",
                "EipAddress":{},
                "InternetMaxBandwidthIn":"-1",
                "ZoneId":"cn-shenzhen-a",
                "InstanceNetworkType":"classic",
                "PublicIpAddress":{
                    "IpAddress":[
                        "120.25.XX.XXX"
                    ]
                },
                "InternetChargeType":"PayByTraffic",
                "HostName":"iZ94t3s0j***",
                "InstanceType":"ecs.s2.large",
                "SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
                "IoOptimized":"false",
                "CreationTime":"2015-07-27T07:08Z",
                "Status":"Running",
                "VpcAttributes":{
                    "PrivateIpAddress":{
                        "IpAddress":[]
                    }
                },
                "InternetMaxBandwidthOut":"1",
                "SecurityGroupIds":{
                    "SecurityGroupId":[
                        "sg-94kd0c***"
                    ]
                },
                "RegionId":"cn-shenzhen",
                "OperationLocks":{
                    "LockReason":[]
                },
                "InstanceChargeType":"PostPaid",
                "ExpiredTime":"2011-09-08T16:00Z",
                "InstanceName":"FinanceJoshua2"
            }
        ]
    }
}

場景2

FormatVersion: OOS-2019-06-01
Description: Resets system disks to its initial state by specifying instance IDs.
  The specified ECS instances must be in stopped status.
Parameters:
  instanceIds:
    Description: The ID list of the ECS instance.
    Type: List
  maxErrors:
    Description: The maximum number of errors allowed during task execution.
    Type: Number
    Default: 0
  concurrency:
    Description: Concurrency ratio of task execution.
    Type: Number
    Default: 1
  OOSAssumeRole:
    Description: The RAM role to be assumed by OOS.
    Type: String
    Default: OOSServiceRole
RamRole: '{{ OOSAssumeRole }}'
Tasks:
- Name: checkInstanceReady
  Action: ACS::CheckFor
  Description: Checks ECS instances is in the stopped status.
  Properties:
    Service: ECS
    API: DescribeInstances
    Parameters:
      InstanceIds:
      - '{{ ACS::TaskLoopItem }}'
    DesiredValues:
    - Stopped
    PropertySelector: Instances.Instance[].Status
  Loop:
    MaxErrors: '{{ maxErrors }}'
    Concurrency: '{{ concurrency }}'
    Items: '{{ instanceIds }}'
- Name: querySystemDisks
  Action: ACS::ExecuteAPI
  Description: Views system disk of the ECS instance.
  Properties:
    Service: ECS
    API: DescribeDisks
    Parameters:
      InstanceId: '{{ ACS::TaskLoopItem }}'
      DiskType: system
  Loop:
    Items: '{{ instanceIds }}'
    Outputs:
      diskIds:
        AggregateType: Fn::ListJoin
        AggregateField: diskId
  Outputs:
    diskId:
      Type: String
      ValueSelector: .Disks.Disk[].DiskId

我們來看下上面的模版,請直接看Tasks部分的querySystemDisks任務,該任務是有具體Outputs的,其定義了輸出名稱爲 diskId的參數,參數Type爲 String ,同時也定義了ValueSelector字段,並且該字段的jq表達式爲 .Disks.Disk[].DiskId 。
就如Outputs中參數名diskId字面意思,其表示輸出API返回結果中的磁盤ID,那麼該任務調用的API是DescribeDisks,API返回的JSON結果樣例如下。結合此JSON樣例,我們看下在 .Disks.Disk[].DiskId 作用下,diskId最終返回值的獲取過程。首先篩選出JSON中Key爲Disks的結果,然後對結果繼續篩選,獲取Key爲Disk的結果,該結果是一個數組,此時又對所得結果進行迭代,並將每個迭代結果中Key爲DiskId的值以String類型進行返回,於是得到最終返回值 'd-28m5zb1sz',即'{{querySystemDisks.diskId}}'的值爲'd-28m5zb1sz'。

上面可能有疑問,該場景的jq表達式和場景一的類似,且處理的數據結構也一樣,爲何此處最後只返回了一個String,而不像場景一返回了List。簡單解釋下,其實返回參數的Type是不同的,當Type爲List時,OOS最後會把返回的一個或多個結果裝到List中作爲最終結果返回;當Type爲String時,OOS最後會取返回的一個或多個結果中的第一個來作爲最終結果。

API調用返回樣例(JSON)

{
    "PageNumber":1,
    "TotalCount":9,
    "PageSize":2,
    "RequestId":"ACD9BBB0-A9D1-46D7-9630-B7A69889E110",
    "Disks":{
        "Disk":[
            {
                "ImageId":"",
                "Description":"",
                "Device":"",
                "ProductCode":"",
                "Portable":true,
                "DetachedTime":"2014-07-23T08:28:48Z",
                "Type":"data",
                "InstanceId":"",
                "ZoneId":"cn-qingdao-b",
                "EnableAutoSnapshot":false,
                "DiskName":"",
                "AttachedTime":"2014-07-23T07:47:35Z",
                "SourceSnapshotId":"",
                "CreationTime":"2014-07-23T02:44:07Z",
                "Status":"Available",
                "DeleteAutoSnapshot":true,
                "Category":"cloud",
                "RegionId":"cn-qingdao",
                "DeleteWithInstance":false,
                "OperationLocks":{
                    "OperationLock":[]
                },
                "DiskId":"d-28m5zb1sz",
                "Size":5
            },
            {
                "ImageId":"",
                "Description":"",
                "Device":"",
                "ProductCode":"",
                "Portable":true,
                "DetachedTime":"",
                "Type":"data",
                "InstanceId":"",
                "ZoneId":"cn-qingdao-b",
                "EnableAutoSnapshot":false,
                "DiskName":"",
                "AttachedTime":"",
                "SourceSnapshotId":"",
                "CreationTime":"2014-07-23T02:44:06Z",
                "Status":"Available",
                "DeleteAutoSnapshot":true,
                "Category":"cloud",
                "RegionId":"cn-qingdao",
                "DeleteWithInstance":false,
                "OperationLocks":{
                    "OperationLock":[]
                },
                "DiskId":"d-28zfrmo13",
                "Size":5
            }
        ]
    }
}

場景3

---
FormatVersion: OOS-2019-06-01
Description: Start ECS instance when instance is stopped.
Parameters:
  accessToken:
    Description: Dingtalk access_token to be notified.
    Type: String
    AllowedPattern: '[A-Za-z0-9]*'
  regionId:
    Description: The Region Id of SLB and Instance.
    Type: String
    MinLength: 1
    MaxLength: 30
  OOSAssumeRole:
    Description: The RAM role to be assumed by OOS.
    Type: String
    Default: OOSServiceRole
  loadBalancerId:
    Description: The ID of the SLB instance.
    Type: String
    AllowedPattern: lb-[A-Za-z0-9]*
    MaxLength: 30
    MinLength: 1
RamRole: '{{OOSAssumeRole}}'
Tasks:
  - Name: whenInstanceStopped
    Action: 'ACS::EventTrigger'
    Properties:
      Product: ECS
      Name:
        - 'Instance:StateChange'
      Level:
        - INFO
      Content:
        state:
          - Stopped
    Outputs:
      instanceId:
        ValueSelector: content.resourceId
        Type: String
  - Name: checkNeedRemoveOrNot
    Action: ACS::CheckFor
    Description: check the interrupted Instance is being added on SLB or Not.
    OnError: ACS::END
    OnSuccess: ACS::NEXT
    Properties:
      Service: SLB
      API: DescribeLoadBalancerAttribute
      Parameters:
        RegionId: '{{ regionId }}'
        LoadBalancerId: '{{ loadBalancerId }}'
      DesiredValues:
        - "{{whenInstanceStopped.instanceId}}"
      PropertySelector: 'BackendServers.BackendServer[].ServerId|select(.=="{{whenInstanceStopped.instanceId}}")'
  - Name: queryLoadBalancerAttribute
    Action: ACS::ExecuteApi
    Description: Views ECS instances to backend servers.
    Properties:
      Service: SLB
      API: DescribeLoadBalancerAttribute
      Parameters:
        RegionId: '{{ regionId }}'
        LoadBalancerId: '{{ loadBalancerId }}'
    Outputs:
      removeOrNot:
        Type: List
        ValueSelector: 'BackendServers.BackendServer[]|select(.ServerId=="{{whenInstanceStopped.instanceId}}")'
      backendServersToRemove:
        Type: List
        ValueSelector: 'BackendServers.BackendServer[]|select(.ServerId=="{{whenInstanceStopped.instanceId}}")|del(.Type)'

我們來看下上面的模版,先看Tasks部分的whenInstanceStopped任務,它會輸出一個名爲 instanceId 的參數,關於這個任務知道這些就夠了。然後看Tasks部分的 queryLoadBalancerAttribute 任務,該任務是有具體Outputs的,比如其定義了輸出名稱爲 backendServersToRemove 的參數,參數Type爲 List ,同時也在參數中定義了ValueSelector字段,並且該字段的jq表達式爲 .BackendServers.BackendServer[]|
select(.ServerId=="{{whenInstanceStopped.instanceId}}")|del(.Type) ,表達式好長,沒關係,我們分析完,您就會發現它很簡單。
就如Outputs中參數名backendServersToRemove字面意思,其表示輸出API返回結果中的後端服務器列表,那麼該任務調用的API是DescribeLoadBalancerAttribute,API返回的JSON結果樣例如下。結合此JSON樣例,我們看下在這個很長的jq表達式作用下,backendServersToRemove最終返回值的獲取過程。首先篩選出JSON中Key爲BackendServers的結果,然後對結果繼續篩選,獲取Key爲BackendServer的結果,該結果是一個數組,此時對所得結果進行迭代,然後我們看到的管道符 | ,也就是把迭代獲取的所有結果交到下一段操作,操作是,將每個迭代結果中Key爲ServerId的值與whenInstanceStopped任務輸出參數instanceId的值進行比較。如果比較結果是相等,則拿到該ServerId所在的這個Mapping,並將該Mapping中Key爲的Type的key-val對剔除,再把該Mapping返回;如果比較結果爲不相等,則忽略掉這個ServerId所在的Mapping。比較完後做下整理把所有返回的Mapping放在一個List中返回。假如whenInstanceStopped.instanceId值是"i-bp1234",得到最終返回值則爲 [{"ServerId":"i-bp1234","Weight":100 }] ,即'{{queryLoadBalancerAttribute.backendServersToRemove}}'的值爲[{"ServerId":"i-bp1234","Weight":100 }]

API調用返回樣例(JSON)

{
    "CreateTimeStamp":1541679713000,
    "RegionIdAlias":"cn-hangzhou",
    "HasReservedInfo":"false",
    "BackendServers":{
        "BackendServer":[
            {
                "ServerId":"i-bpxccv123456jo7v",
                "Weight":100,
                "Type":"ecs"
            }
        ]
    },
    "ListenerPorts":{
        "ListenerPort":[]
    },
    "VSwitchId":"vsw-bp1ccv123456jk9bmlj",
    "InternetChargeType":"paybytraffic",
    "VpcId":"vpc-bp1ccv123456j1qc5cm",
    "SlaveZoneId":"cn-hangzhou-d",
    "NetworkType":"vpc",
    "LoadBalancerSpec":"slb.s2.small",
    "ListenerPortsAndProtocol":{
        "ListenerPortAndProtocol":[]
    },
    "PayType":"PayOnDemand",
    "Bandwidth":5120,
    "LoadBalancerName":"abc1",
    "ResourceGroupId":"rg-acfmxazb4ph6aiy",
    "AddressIPVersion":"ipv4",
    "LoadBalancerId":"lb-bp23456jfuca5",
    "EndTimeStamp":32493801600000,
    "MasterZoneId":"cn-hangzhou-b",
    "ListenerPortsAndProtocal":{
        "ListenerPortAndProtocal":[]
    },
    "Address":"192.168.0.6",
    "RegionId":"cn-hangzhou",
    "RequestId":"35D745B3-1567-4855-9EF1-F5CED3C1670C",
    "CreateTime":"2018-11-08T12:21:53Z",
    "EndTime":"2999-09-08T16:00:00Z",
    "AddressType":"intranet",
    "LoadBalancerStatus":"active"
}

PropertySelector

場景1(CheckFor)

FormatVersion: OOS-2019-06-01
Description: Creates a disk and attaches a data disk to an ECS instance.
Parameters:
  diskName:
    Description: The name of the disk.
    Type: String
  zoneId:
    Description: The zone ID that is available in the specified region.
    Type: String
  diskCategory:
    Description: The category of the data disk.
    Type: String
  instanceId:
    Description: Creates a subscription disk and the system automatically attaches
      it to a subscription instance with the InstanceId you specified.
    Type: String
    AllowedPattern: i-[A-Za-z0-9]*
    MinLength: 1
    MaxLength: 30
  size:
    Description: The size of the disk.
    Type: String
Tasks:
- Name: checkInstanceReady
  Action: ACS::CheckFor
  Description: Checks whether the ECS instance status is running or stopped.
  Properties:
    Service: ECS
    API: DescribeInstances
    Parameters:
      InstanceIds:
      - '{{ instanceId }}'
    DesiredValues:
    - Running
    - Stopped
    PropertySelector: .Instances.Instance[].Status

我們來看下上面的模版,請直接看Tasks部分的checkInstanceReady任務,該任務的動作是 ACS::CheckFor ,其Properties部分定義了DesiredValues的值爲 ['Running','Stopped'] ,同時也定義了PropertySelector字段,並且該字段的jq表達式爲 .Instances.Instance[].Status 。
該任務中,DesiredValues和PropertySelector兩個字段會被聯合起來,用來驗證指定的條件即['Running','Stopped'],驗證過程爲先把API返回的JSON結果通過jq表達式篩選處理,再檢查處理得到的篩選結果是否在DesiredValues字段的List中。如果在List中,則該任務執行結果爲Success,否則該任務執行結果爲Failed。
那麼該任務調用的API是DescribeInstances,API返回的JSON結果樣例如下。結合此JSON樣例,我們看下在 .Instances.Instance[].Status 作用下,最終返回值的獲取過程。首先篩選出JSON中Key爲Instances的結果,然後對結果繼續篩選,獲取Key爲Instance的結果,該結果是一個數組,此時對所得結果進行迭代,迭代獲取數組中的第一個元素,並將該元素中Key爲 Status 的值作爲與指定的條件比較的值,即檢查'Running'是否在['Running','Stopped']中。

API調用返回樣例(JSON)

{
    "PageNumber":"1",
    "TotalCount":"1",
    "PageSize":"10",
    "RequestId":"14A07460-EBE7-47CA-9757-12CC4761D47A",
    "Instances":{
        "Instance":[
            {
                "ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
                "InnerIpAddress":{
                    "IpAddress":[
                        "10.170.XX.XXX"
                    ]
                },
                "InstanceId":"id-001",
                "EipAddress":{},
                "InternetMaxBandwidthIn":"-1",
                "ZoneId":"cn-shenzhen-a",
                "InstanceNetworkType":"classic",
                "PublicIpAddress":{
                    "IpAddress":[
                        "120.25.XX.XXX"
                    ]
                },
                "InternetChargeType":"PayByTraffic",
                "HostName":"iZ94t3s0j***",
                "InstanceType":"ecs.s2.large",
                "SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
                "IoOptimized":"false",
                "CreationTime":"2015-07-27T07:08Z",
                "Status":"Running",
                "VpcAttributes":{
                    "PrivateIpAddress":{
                        "IpAddress":[]
                    }
                },
                "InternetMaxBandwidthOut":"1",
                "SecurityGroupIds":{
                    "SecurityGroupId":[
                        "sg-94kd0c***"
                    ]
                },
                "RegionId":"cn-shenzhen",
                "OperationLocks":{
                    "LockReason":[]
                },
                "InstanceChargeType":"PostPaid",
                "ExpiredTime":"2011-09-08T16:00Z",
                "InstanceName":"FinanceJoshua1"
            },            
      {
                "ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
                "InnerIpAddress":{
                    "IpAddress":[
                        "10.170.XX.XXX"
                    ]
                },
                "InstanceId":"id-002",
                "EipAddress":{},
                "InternetMaxBandwidthIn":"-1",
                "ZoneId":"cn-shenzhen-a",
                "InstanceNetworkType":"classic",
                "PublicIpAddress":{
                    "IpAddress":[
                        "120.25.XX.XXX"
                    ]
                },
                "InternetChargeType":"PayByTraffic",
                "HostName":"iZ94t3s0j***",
                "InstanceType":"ecs.s2.large",
                "SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
                "IoOptimized":"false",
                "CreationTime":"2015-07-27T07:08Z",
                "Status":"Running",
                "VpcAttributes":{
                    "PrivateIpAddress":{
                        "IpAddress":[]
                    }
                },
                "InternetMaxBandwidthOut":"1",
                "SecurityGroupIds":{
                    "SecurityGroupId":[
                        "sg-94kd0c***"
                    ]
                },
                "RegionId":"cn-shenzhen",
                "OperationLocks":{
                    "LockReason":[]
                },
                "InstanceChargeType":"PostPaid",
                "ExpiredTime":"2011-09-08T16:00Z",
                "InstanceName":"FinanceJoshua2"
            }
        ]
    }
}

場景2(WaitFor)

FormatVersion: OOS-2019-06-01
Description: Creates a custom image.
Parameters:
  imageName:
    Description: The image name.
    Type: String
  instanceId:
    Description: The ID of the instance.
    Type: String
    AllowedPattern: i-[A-Za-z0-9]*
    MinLength: 1
    MaxLength: 30
Tasks:
- Name: checkInstanceReady
  Action: ACS::CheckFor
  Description: Checks whether the ECS instance status is running or stopped.
  Properties:
    Service: ECS
    API: DescribeInstances
    Parameters:
      InstanceIds:
      - '{{ instanceId }}'
    DesiredValues:
    - Running
    - Stopped
    PropertySelector: Instances.Instance[].Status
- Name: createImage
  Action: ACS::ExecuteAPI
  Description: Creates a custom image.
  Properties:
    Service: ECS
    API: CreateImage
    Parameters:
      ImageName: '{{ imageName }}'
      InstanceId: '{{ instanceId }}'
  Outputs:
    imageId:
      Type: String
      ValueSelector: ImageId
- Name: untilImageReady
  Action: ACS::WaitFor
  Description: Waits for the image to be available.
  Properties:
    Service: ECS
    API: DescribeImages
    Parameters:
      ImageId: '{{ createImage.imageId }}'
    DesiredValues:
    - Available
    PropertySelector: .Images.Image[].Status

我們來看下上面的模版,請直接看Tasks部分的untilImageReady任務,該任務的動作是 ACS::WaitFor ,其Properties部分定義了DesiredValues的值爲 ['Available'] ,同時也定義了PropertySelector字段,並且該字段的jq表達式爲 .Images.Image[].Status 。
該任務中,DesiredValues和PropertySelector兩個字段會被聯合起來,用來驗證指定的條件即['Available'],驗證過程爲先把API返回的JSON結果通過jq表達式篩選處理,再檢查處理得到的篩選結果是否在DesiredValues字段的List中。如果在List中,則該任務不再繼續等待,並結束該任務向下執行;否則該任務會隔段時間再次調用API,並檢查結果是否滿足條件,直至條件滿足或超出最大檢查次數。
那麼該任務調用的API是DescribeImages,API返回的JSON結果樣例如下。結合此JSON樣例,我們看下在 .Images.Image[].Status作用下,最終返回值的獲取過程。首先篩選出JSON中Key爲Images的結果,然後對結果繼續篩選,獲取Key爲Image的結果,該結果是一個數組,此時對所得結果進行迭代,迭代獲取數組中的第一個元素,並將該元素中Key爲 Status 的值作爲與指定的條件比較的值,即檢查'Available'是否在['Available']中。

API調用返回樣例(JSON)

{
    "PageNumber":1,
    "TotalCount":24,
    "PageSize":1,
    "RequestId":"49CBCED4-C9B9-4851-BEB5-8FB5E5169E30",
    "RegionId":"cn-hangzhou",
    "Images":{
        "Image":[
            {
                "ImageId":"suse11sp3_64_20G_aliaegis_20150428.vhd",
                "OSType":"linux",
                "Architecture":"x86_64",
                "OSName":"SUSE Linux  Enterprise Server 11 SP3 64位",
                "DiskDeviceMappings":{
                    "DiskDeviceMapping":[
                        {
                            "Device":"/dev/xvda",
                            "Size":"20"
                        }
                    ]
                },
                "ImageOwnerAlias":"system",
                "Progress":"100%",
                "Usage":"instance",
                "CreationTime":"2015-05-06T09:01:32Z",
                "Status":"Available",
                "ImageVersion":"1",
                "ImageName":"suse11sp3_64_20G_aliaegis_20150428.vhd",
                "IsCopied":false,
                "IsSubscribed":false,
                "Platform":"SUSE",
                "Size":20
            }
        ]
    }
}

jq語法手冊

基礎用法

通過Key篩選

jq表達式:
".foo"
input:

{"foo": 42, "bar": "less interesting data"}

output:
42

通過Index篩選

jq表達式:
".[0]"
input:

[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]

output:

{
  "name": "JSON",
  "good": true
}

通過Iterator篩選

jq表達式:
".[]"
input:

["hello","world"]

output:

"hello"  
"world"

jq表達式:
".[]"
input:

[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]

output:

{
  "name": "JSON",
  "good": true
}
{
  "name": "XML",
  "good": false
}

通過Pipe("|")篩選

jq表達式:
".[]|.name"
input:

[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]

output:  

"JSON"
"XML"

構造Array

jq表達式:
"[.user, .projects[]]"
input:

{"user":"stedolan", "projects": ["jq", "wikiflow"]}

output:

[
  "stedolan",
  "jq",
  "wikiflow"
]

構造Mapping

jq表達式:
"{user, title: .titles}"
input:

{"user":"stedolan","titles":["JQ Primer", "More JQ"]}

output:

{
  "user": "stedolan",
  "title": [
    "JQ Primer",
    "More JQ"
  ]
}

jq表達式:
"{(.user): .titles}"
input:

{"user":"stedolan","titles":["JQ Primer", "More JQ"]}

output:

{
  "stedolan": [
    "JQ Primer",
    "More JQ"
  ]
}

內建操作符和函數

Addition(+)

jq表達式:
".a + 1"
input:

{"a": 7}

output:

8

jq表達式:
".a + .b"
input:

{"a": [1,2], "b": [3,4]}

output:

[
  1,
  2,
  3,
  4
]

Subtraction(-)

jq表達式:
". - ["xml", "yaml"]"
input:

["xml", "yaml", "json"]

output:

[
  "json"
]

Length

jq表達式:
"[.[]| length]"
input:

[[1,2], "string", {"a":2}, null]

output:

[
  2,
  6,
  1,
  0
]

Keys

jq表達式:
"keys"
input:

{"abc": 1, "abcd": 2, "Foo": 3}

output:

[
  "Foo",
  "abc",
  "abcd"
]

In

jq表達式:
'.[] | in({"foo": 42})'
input:

["foo", "bar"]

output:

true
false

map

jq表達式:
"map(.+1)"
input:

[1,2,3]

output:

[
  2,
  3,
  4
]

map_values

jq表達式:
"map_values(.+1)"
input:

{"a": 1, "b": 2, "c": 3}

output:

{
  "a": 2,
  "b": 3,
  "c": 4
}

del

jq表達式:
"del(.foo)"
input:

{"foo": 42, "bar": 9001, "baz": 42}

output:

{
  "bar": 9001,
  "baz": 42
}

select

jq表達式:
'.[] | select(.id == "second")'
input:

[{"id": "first", "val": 1}, {"id": "second", "val": 2}]

output:

{
  "id": "second",
  "val": 2
}

jq表達式:
"map(select(. >= 2))"
input:

[1,5,3,0,7]

output:

[
  5,
  3,
  7
]

any

jq表達式:
"any"
input:

[true, false]

output:

true

jq表達式:
"any"
input:

[false, false]

output:

false

all

jq表達式:
"all"
input:

[true, false]

output:

false

jq表達式:
"all"
input:

[true, true]

output:

true

jq表達式:
"all"
input:

[]

output:

true

jq表達式:
"all"
input:

[]

output:

true

min、max

jq表達式:
"min"
input:

[5,4,2,7]

output:

2

sort、sort_by

jq表達式:
"sort"
input:

[8,3,null,6]

output:

[
  null,
  3,
  6,
  8
]

jq表達式:
"sort_by(.foo)"
input:

[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]

output:

[
  {
    "foo": 2,
    "bar": 1
  },
  {
    "foo": 3,
    "bar": 100
  },
  {
    "foo": 4,
    "bar": 10
  }
]

index

jq表達式:
'index(",  ")'
input:

"a,b,  cd, efg, hijk"

output:

3

split

jq表達式:
'split(", ")'
input:

"a, b,c,d, e, "

output:

[
  "a",
  "b,c,d",
  "e",
  ""
]

join

jq表達式:
'join(", ")'
input:

["a","b,c,d","e"]

output:

"a, b,c,d, e"

jq表達式:
'join("   ")'
input:

["a",1,2.3,true,null,false]

output:

"a   1   2.3   true      false"

條件判斷

if-then-else

jq表達式:

 'if . == 0 then  "zero"elif . == 1 then "one"else  "many"end'     

input:

2

output:

"many"

>, <,>=, <=,==,!=

jq表達式:

 '.<5'     
input:

2

output:

true

jq表達式:
 '.==5'     
input:

2

output:

false

高級用法

變量

jq表達式:
".bar as $x | .foo | . + $x"
input:

{"foo":10, "bar":200}

output:

210

jq表達式:
". as $i|[(.*2|. as $i| $i), $i]"
input:

5

output:

[
  10,
  5
]

自定義函數

jq表達式:
"def addvalue(f): . + [f]; map(addvalue(.[0]))"
input:

[[1,2],[10,20]]

output:

[
  [
    1,
    2,
    1
  ],
  [
    10,
    20,
    10
  ]
]

jq表達式:
"def addvalue(f): f as $x | map(. + $x); addvalue(.[0])"
input:

[[1,2],[10,20]]

output:

[
  [
    1,
    2,
    1,
    2
  ],
  [
    10,
    20,
    1,
    2
  ]
]

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章