cli 필터링 옵션
aws cli로 목록을 확인할 때 조건을 주어 필터링해야 하는 경우가 있다. 필터링을 할 수 있는 옵션으로는 --filter, --query 옵션 2개가 존재한다.
- --filters : AWS CLI의 서버 측 필터링. 필터를 만족하는 레코드만 반환한다.
- --query : 내장 JSON 기반 클라이언트 측 필터링. 서버에서 응답받은 결과를 필터링하여 표시한다. 쿼리는 JMESPath 구문을 사용하여 표현식을 만든다. --output 옵션을 사용하는 경우 필터링하기 전에 출력문이 페이징 처리된다.
이 글에서는 사용 중인 EC2의 비용 추적을 위해, 동작 중인 EC2 인스턴스에 특정 태그가 비어 있는 게 있는지 점검해보려고 한다. 즉, aws ec2 describe-instance 명령을 예시로 한다.
--filter 옵션
전체 EC2 목록에서 원하는 인스턴스 목록만 출력할 때 사용한다.
이 글에서는 동작 중인 EC2 목록에 대해서만 태그 확인을 하도록 필터링할 것이다.
# 사용 방법
aws ec2 describe-instances \
--filter Name=[속성],Values=[조건]
# 예시 - 동작 상태(Running)인 인스턴스
aws ec2 describe-instances \
--filter "Name=instance-state-name,Values=running"
aws cli은 기본적으로 JSON 형식으로 결과를 출력한다. 사진에서는 값이 너무 길어서 instance id만 출력하게끔 필터링했다.
실제로 콘솔에서도 2개의 인스턴스만 동작 중인 것을 확인할 수 있었다.
만약 TAG로 필터링한다면 아래와 같이 사용해야 한다.
aws ec2 describe-instances \
--filter Name=tag:[태그 이름],Values=[조건]
필터링 조건이 여럿인 경우, 조건을 공백으로 구분하여 나열한다.
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" "Name=tag:backup,Values=yes"
--query 옵션
--query 옵션은 조회 결과에서 원하는 필드 값만 출력하도록 정의하는 옵션이다. 다만 간단한 필터링도 수행할 수 있다.
필드 필터링
예로 들어, aws ec2 describe-instances의 결과는 아래와 같다.
{
"Reservations": [
{
"Groups": [],
"Instances": [
{
"AmiLaunchIndex": 0,
"ImageId": "ami-0abcdef1234567890",
"InstanceId": "i-1234567890abcdef0",
"InstanceType": "t2.micro",
"KeyName": "MyKeyPair",
"LaunchTime": "2018-05-10T08:05:20.000Z",
"Monitoring": {
"State": "disabled"
},
"Placement": {
"AvailabilityZone": "us-east-2a",
"GroupName": "",
"Tenancy": "default"
},
"PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal",
"PrivateIpAddress": "10.0.0.157",
"ProductCodes": [],
"PublicDnsName": "",
"State": {
"Code": 0,
"Name": "pending"
},
"StateTransitionReason": "",
"SubnetId": "subnet-04a636d18e83cfacb",
"VpcId": "vpc-1234567890abcdef0",
"Architecture": "x86_64",
"BlockDeviceMappings": [],
"ClientToken": "",
"EbsOptimized": false,
"Hypervisor": "xen",
"NetworkInterfaces": [
{
"Attachment": {
"AttachTime": "2018-05-10T08:05:20.000Z",
"AttachmentId": "eni-attach-0e325c07e928a0405",
"DeleteOnTermination": true,
"DeviceIndex": 0,
"Status": "attaching"
},
"Description": "",
"Groups": [
{
"GroupName": "MySecurityGroup",
"GroupId": "sg-0598c7d356eba48d7"
}
],
"Ipv6Addresses": [],
"MacAddress": "0a:ab:58:e0:67:e2",
"NetworkInterfaceId": "eni-0c0a29997760baee7",
"OwnerId": "123456789012",
"PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal",
"PrivateIpAddress": "10.0.0.157"
"PrivateIpAddresses": [
{
"Primary": true,
"PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal",
"PrivateIpAddress": "10.0.0.157"
}
],
"SourceDestCheck": true,
"Status": "in-use",
"SubnetId": "subnet-04a636d18e83cfacb",
"VpcId": "vpc-1234567890abcdef0",
"InterfaceType": "interface"
}
],
"RootDeviceName": "/dev/xvda",
"RootDeviceType": "ebs",
"SecurityGroups": [
{
"GroupName": "MySecurityGroup",
"GroupId": "sg-0598c7d356eba48d7"
}
],
"SourceDestCheck": true,
"StateReason": {
"Code": "pending",
"Message": "pending"
},
"Tags": [],
"VirtualizationType": "hvm",
"CpuOptions": {
"CoreCount": 1,
"ThreadsPerCore": 1
},
"CapacityReservationSpecification": {
"CapacityReservationPreference": "open"
},
"MetadataOptions": {
"State": "pending",
"HttpTokens": "optional",
"HttpPutResponseHopLimit": 1,
"HttpEndpoint": "enabled"
}
}
],
"OwnerId": "123456789012"
"ReservationId": "r-02a3f596d91211712",
}
}
이 결과에서 instanceId만 출력하고 싶다면 아래와 같이 구문을 작성할 수 있다. 원하는 깊이까지의 필드를 나열하면 된다.
aws ec2 describe-instances \
--query '필드'
# 예시
aws ec2 describe-instances \
--query 'Reservations[*].Instances[*].InstanceId'
같은 깊이에 있는 필드를 여러 개 출력하고 싶다면 아래와 같이 작성한다.
aws ec2 describe-instances \
--query '<listName>[].[<expression>, <expression>]'
# 예시
aws ec2 describe-instances \
--query 'Reservations[*].Instances[].[InstanceId, PrivateIpAddress]'
조건에 따른 필터링
값에 대해 조건을 줄 때는 아래와 같이 사용할 수 있다.
aws ec2 describe-instances \
--filter <expression>.[? <expression> <comparator> <expression>]
# 예시
aws ec2 describe-instances \
--filter 'Reservations[].Instances[?Tags[?Key == `Name`]].InstanceId'
조건문으로는 ==, !=, <, <=, >, >=을 사용할 수 있다.
AND 연산은 &&로 연결하고 OR 연산은 ||로 연결한다.
# AND
aws ec2 describe-instances \
--query 'Reservations[].Instances[?Tags[?Key == `Name`] && Tags[?Key == `autoStartStop`]].InstanceId'
# OR
aws ec2 describe-instances \
--query 'Reservations[].Instances[?Tags[?Key == `Name`] || Tags[?Key == `autoStartStop`]].InstanceId'
따라서 특정 Tag 값이 비어있는지 여부는 다음과 같이 확인할 수 있다.
# Name 태그가 비어있거나 Cost Type이 비어있지 않는 경우
aws ec2 describe-instances \
--query 'Reservations[].Instances[? !(not_null(Tags[?Key == `Name`].Value)) || not_null(Tags[?Key == `Cost Type`].Value)].InstanceId'
부정은 앞에 !을 붙인다.
+ jmespath가 not_null 함수는 제공하는데, 그 반대인 is_null은 제공하지를 않는 것 같다.
참고 문서
https://cloudest.oopy.io/posting/058
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-instances.html