2019/01/30 新規作成
2019/02/04 TIPS追加
Oracle Cloud Infrastructure(OCI)のcliに限らず、広く使われているjsonですが、
やや取り扱いに戸惑うことがあるのでまとめてみました。
1.json基礎
jsonとは?
JSON (JavaScript Object Notation)は、軽量のデータ交換フォーマットです。
人間にとって読み書きが容易で、マシンにとっても簡単にパースや生成を行なえる形式です。
JavaScriptプログラミング言語 (ECMA-262標準第3版 1999年12月)の一部をベースに作られています。
JSONは完全に言語から独立したテキスト形式ですが、C、C++、C#、Java、JavaScript、Perl、Python、その他多くのCファミリーの言語を使用するプログラマにとっては、馴染み深い規約が使われています。
これらの性質が、 JSONを理想的なデータ交換言語にしています。
https://www.json.org/json-ja.html
とのことです。
基本ルール
RFC 8259にいろいろ書いてありました。
https://tools.ietf.org/html/rfc8259
値の種類
値 | 説明 | 書き方 |
---|---|---|
object | nameとvalueのペア | { "name" : value } |
arry | 配列(タイプの異なる値もOK) | [ value, value ] |
number | 数字(10進数) | value |
string | 文字列 | "value" |
その他 | true, false, null (小文字必須) | trueなど |
※複数の値を並べて書くときは、「,」で区切る
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": 100
},
"Animated" : false,
"IDs": [116, 943, 234, 38793]
}
}
※自分で書くと「,」を忘れたり、消し忘れたりしがち。
jsonフォーマッターとかで構文間違いがないか要確認。
2.OCI cliでjsonを使う
2-1.input情報にjsonを使う
oci cliを使う際のinput情報としてjson形式が求められることがあります。
また、オプション以下をまとめてjsonで記載してコマンドへ渡すこともできます。
※inputの場合でもWindowsでoci cliを使う場合の注意!が該当します
直書きするパターン
簡単なものであれば、直書きすることも(?)。
ただ、慣れてないとけっこう間違えてストレスです。
$ oci network route-table create --route-rules '[{"cidrBlock":"0.0.0.0/0","networkEntityId":"ocid1.internetgateway.oc1.phx.xxxxxx"}]'
jsonファイルを渡すパターン
--from-json
オプションでファイルに書いたものを渡す。
ファイルの場所はfile://
に続けて絶対あるいは相対パスで指定。
同じサービス/リソースを何度も作る場合などは便利。
ただ、変数化して値を変えながら作るとかするなら、terraformとか使った方が楽。
$ cat input.json
{
"accessType": "ObjectRead",
"bucketName": "test",
"name": "test",
"namespace": "test",
"objectName": "test"
}
$ oci os preauth-request create --from-json file://input.json
inputに必要なjsonの型(skeleton)を確認する1
--generate-full-command-json-input
このオプションを付けると、そのコマンドのinputに必要な情報の全てを含んだ型をjson形式で出力してくれます。
出力結果をリダイレクトでファイルに吐き出してあげれば、あとはこれを埋めるだけでinput用のjsonファイルが完成します。jsonは形式が崩れて、構文エラーになることが多いので、こちらから作ると失敗が少ないかと。
$ oci network route-table create --generate-full-command-json-input
{
"compartmentId": "string",
"definedTags": {
"string1": {
"string1": {
"string1": "string",
"string2": "string"
},
"string2": {
"string1": "string",
"string2": "string"
}
},
"string2": {
"string1": {
"string1": "string",
"string2": "string"
},
"string2": {
"string1": "string",
"string2": "string"
}
}
},
"displayName": "string",
"dn": "string",
"freeformTags": {
"string1": "string",
"string2": "string"
},
"maxWaitSeconds": 0,
"routeRules": [
{
"cidrBlock": "string",
"destination": "string",
"destinationType": "string",
"networkEntityId": "string"
},
{
"cidrBlock": "string",
"destination": "string",
"destinationType": "string",
"networkEntityId": "string"
}
],
"vcnId": "string",
"waitForState": "PROVISIONING|AVAILABLE|TERMINATING|TERMINATED",
"waitIntervalSeconds": 0
}
inputに必要なjsonの型(skeleton)を確認する2
--generate-param-json-input
先ほどのオプションは、全input情報をjsonで書くための型を出力しますが、こちらは一部分のみ指定して、jsonの型を出力させられます。
$ oci network route-table create --generate-param-json-input route-rules
[
{
"cidrBlock": "string",
"destination": "string",
"destinationType": "string",
"networkEntityId": "string"
},
{
"cidrBlock": "string",
"destination": "string",
"destinationType": "string",
"networkEntityId": "string"
}
]
2-2.outputのjsonを扱う
"--query"オプションを理解する
※先に「実際にjson outputを制御してみる」を見た方がイメージがわきやすいかもしれません。
getやlistの出力結果の型を理解する
"--query"オプションは、JMESPath のクエリを使うことで、出力結果をフィルタリングするオプションです。
最初はややとっつきにくいのですが、型を理解すると簡単です。
※今回はoci cliで使うという観点で。
getで出力されるjsonの型
例えば、oci cliのget(特手のリソースを指定して、詳細な情報を取得するコマンド)の結果は以下のような形で返ってきます。一見複雑ですが、ただのオブジェクト{ }の組み合わせです。
{ #O1
"data": { #O2
"XXXXX": "XXXXX",
"XXXXX": "XXXXX",
"XXXXX": { #O3
"XXXXX": { #O4a
"XXXXX": "XXXXX"
}, #O4aここまで
"XXXXX": { #O4b
"XXXXX": "XXXXX"
} #O4bここまで
}, #O3ここまで
"XXXXX": "XXXXX",
"XXXXX": "XXXXX",
"XXXXX": XXXXX
}, #O2ここまで
"XXXXX": "XXXXX"
} #01ここまで
※O = Object として階層番号を振ってみました
{ "data" : {} }
という name : value のペアがベースになっていて、valueの方も{ "XXXXX" : "XXXXX" }とペアになっていて、さらにこのオブジェクトのvalueも{ }とペアになっていて…と入れ子になっています。
イメージ:{ #O1 "data" : { #O2 "XXX" : {#O3 "XXX" : { #O4a "XXX" : "XXX" }, "XXX" : { #O4b "XXX" : "XXX" } } } }
※正確にはO1の中も、{ "data" : {}, "XXXXX" : "XXXXX" }
と二つのペアが並んでいる。
listで出力されるjsonの型
listの結果もほぼ同じですが、listの場合は、複数のリソースについての情報を一覧にするコマンドなので、配列が使われています。
{ #O1
"data": [ #A1
{ #O2a
"XXXXX": "XXXXX",
"XXXXX": "XXXXX",
"XXXXX": XXXXX
}, #O2aここまで
{ #O2b
"XXXXX": "XXXXX",
"XXXXX": "XXXXX",
"XXXXX": XXXXX
}, #O2bここまで
{ #O2c
"XXXXX": "XXXXX",
"XXXXX": "XXXXX",
"XXXXX": XXXXX
} #02cここまで
] #A1ここまで
} #O1ここまで
※A = Arrayとして階層番号を振ってみました
こちらの場合は`{ "data" : [ ] }というオブジェクトがベースにありつつ、配列の中に[ { #O2a }, { #O2b }, { #O2c } ]といった形で、オブジェクトが並んでいます。
queryオプションでの指定の仕方を理解する
上の構造がわかれば、今度は指定の仕方です。
getの出力から一部の情報を指定する方法
例えば、以下のような出力の中から、"aaaaa"を取り出したい場合。
"O1"の「data」の中の、"AAAAA"(name)に対応する値(value)が欲しいので、"data.AAAAA"
という形で指定します("aaaaa"が結果として返ってきます)。
{ #O1
"data": { #O2
"AAAAA": "aaaaa",
"XXXXX": "XXXXX"
} #O2ここまで
} #01ここまで
listの出力から一部の情報を指定する方法
一方、listの出力結果で以下のような形となっている場合、複数のリソースが一覧になっているので、各々のリソースが同じ項目を持っています。
例えば、以下の出力から、各リソースの"AAAAA"に対応する値のみを一覧で表示したい場合。
"O1"の「data」の中の、配列(A1)の中の全てのリソース[*]から、"AAAAA"に対応する値が欲しいので、data[*].AAAAA
という形で指定します("aaaaa"と"yyyyy"が結果として返ってきます)。
※例えば"AAAAA"が、リソース名であったり、IPアドレスであったりすると想像してください。
{ #O1
"data": [ #A1
{ #O2a
"AAAAA": "aaaaa",
"BBBBB": 10
}, #O2aここまで
{ #O2b
"AAAAA": "yyyyy",
"BBBBB": 100
} #O2bここまで
] #A1ここまで
} #O1ここまで
応用
ここまで理解できれば、応用していくだけです。
-
特定のリソースの、特定の情報
例えば、「全てのリソース」ではなく、特定の条件に当てはまるリソースの、"AAAAA"に対応する値が欲しい場合。より具体的には、"BBBBB"が10より大きいリソースに関してのみ、"AAAAA"に対応する値を一覧で表示したい場合。
data[?"BBBBB" >
10].AAAAA
となります。先ほどはdata[*]と配列の中は何も指定していなかった箇所で、条件を指定している点に注意してください。 -
複数の情報
"AAAAA"だけでなく、"BBBBB"に対応する値も欲しい場合。この場合は、"data"に対する出力が複数になるので、配列を使って、data[*].["AAAAA","BBBBB"]
という形になります。 -
nameとvalueのセットを表示
ここまで"AAAAA"に対応する値のみを出力するようなフィルタをしてきましたが、"AAAAA":"aaaaa"といった形で、nameの方も出力させたい場合は、"data.AAAAA:AAAAA"
とします。
階層がさらに深い場合は「.」を追加していけばOkです。
Windowsでoci cliを使う場合の注意!
Windowsの場合は、フィルタを行う際に注意が必要です。
ここはクラウドベンダのcliによって方言があるようです。
※参考:AWS Command Line Interface のパラメータ値の指定
ociの場合はマニュアルに以下の記載があります。
On Windows, to pass complex input to the CLI as a JSON string, you must enclose the entire block in double quotes.
Inside the block, each double quote for the key and value strings must be escaped with a backslash (\) character.
The following command shows how to pass two values for the --metadata object on Windows.
oci os bucket create -ns mynamespace --name mybucket --metadata "{\"key1\":\"value1\",\"key2\":\"value2\"}" --compartment-id ocid1.compartment.oc1..aaaaaaaarhifmvrvuqtye5q66rck6copzqck3ukc5fldrwpp2jojdcypxfga
つまりWindowsの場合、以下のルールに従う必要があります。
- ""(ダブルクォーテーション)で全てのブロックを囲う
- ブロック内の"(ダブルクォーテーション)は、\(バックスラッシュ)でエスケープする
したがって、例えばdata[*].AAAAA
と記載していたものは"data[*].AAAAA"
と記載する必要があり、data[*]."AAAAA"
と記載していたものは、"data[*].\"AAAAA\""
と記載する必要があります。
※アンダースコア(_)以外の記号を使っている場合は、その値は""で囲う必要があります。
- bashなどの場合
- 全体をシングルクォーテーションで囲うことで""をエスケープ('data[*]."display-name"')
- Windows PowerShellの場合
- ""(バックスラッシュ)に"`"(バッククォート)を加えた"\`"で""をダブルエスケープ("data[*].\`"display-name\`"")
# "Parameter '<PARAMETER NAME>' must be in JSON format."
エラーが出続けて途方に暮れてたのですが、これが原因でした。
※マニュアルに書いてあるのと、失敗した時のエラーメッセージで教えてくれます。
- Managing CLI Input and Output
- エラーメッセージ(抜粋)
If a key name has any characters besides [a-z, A-Z, 0-9, _], it needs to be escaped.
In bash or similar "NIX" based shells used in "NIX" environment, escaping can be done byusing double quotes inside single quotes.
e.g. --query 'data[*]."display-name"'
If using PowerShell in Windows environment, escaping can be done by using double quoteswith double escape character \`.
e.g. --query data[*].\`"display-name\`"
実際にjson outputを制御してみる
やっとです。
※Windows PowerShellから実行
特定のcompute instanceの情報をgetする
何もフィルタしないとこんな感じ
> oci compute instance get --instance-id ocid1.instance.oc1.phx.xxxxxxxxxxxxxxxxxxx
{
"data": {
"availability-domain": "xxxx:PHX-AD-1",
"compartment-id": "ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxx",
"defined-tags": {
"test_tag": {
"tag1": "test"
},
"test_tag2": {
"tag2": "test"
}
},
"display-name": "test-instance",
"extended-metadata": {},
"fault-domain": "FAULT-DOMAIN-1",
"freeform-tags": {},
"id": "ocid1.instance.oc1.phx.xxxxxxxxxxxxxxxxxxx",
"image-id": "ocid1.image.oc1.phx.xxxxxxxxxxxxxxxxxxx",
"ipxe-script": null,
"launch-mode": "EMULATED",
"launch-options": {
"boot-volume-type": "IDE",
"firmware": "BIOS",
"is-consistent-volume-naming-enabled": null,
"is-pv-encryption-in-transit-enabled": null,
"network-type": "E1000",
"remote-data-volume-type": "SCSI"
},
"lifecycle-state": "STOPPED",
"metadata": {},
"region": "phx",
"shape": "VM.Standard1.1",
"source-details": {
"boot-volume-size-in-gbs": null,
"image-id": "ocid1.image.oc1.phx.xxxxxxxxxxxxxxxxxxx",
"kms-key-id": null,
"source-type": "image"
},
"time-created": "2019-01-16T11:22:54.286000+00:00",
"time-maintenance-reboot-due": null
},
"etag": "xxxxxxxxxxxxxxxxxxx"
}
ここから、インスタンスの名前(display-name)とshape、リージョンとフォルトドメインのみを取得したい場合は以下。
> oci compute instance get --instance-id ocid1.instance.oc1.phx.xxxxxxxxxxxxxxxxxxx --query "data.[\`"display-name\`", shape, region, \`"fault-domain\`"]"
[
"test-instance",
"VM.Standard1.1",
"phx",
"FAULT-DOMAIN-1"
]
複数のcompute instanceの情報をlistする
何もフィルタしないとこんな感じ。
※コンパートメントの指定はしています
> oci compute instance list
{
"data": [
{
"availability-domain": "gype:PHX-AD-1",
"compartment-id": "ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxx",
"defined-tags": {
"test_tag": {
"tag1": "test"
},
"test_tag": {
"tag2": "test"
}
},
"display-name": "test-instance",
"extended-metadata": {},
"fault-domain": "FAULT-DOMAIN-1",
"freeform-tags": {},
"id": "ocid1.instance.oc1.phx.xxxxxxxxxxxxxxxxxxx",
"image-id": "ocid1.image.oc1.phx.xxxxxxxxxxxxxxxxxxx",
"ipxe-script": null,
"launch-mode": "EMULATED",
"launch-options": {
"boot-volume-type": "IDE",
"firmware": "BIOS",
"is-consistent-volume-naming-enabled": null,
"is-pv-encryption-in-transit-enabled": null,
"network-type": "E1000",
"remote-data-volume-type": "SCSI"
},
"lifecycle-state": "STOPPED",
"metadata": {},
"region": "phx",
"shape": "VM.Standard1.1",
"source-details": {
"boot-volume-size-in-gbs": null,
"image-id": "ocid1.image.oc1.phx.xxxxxxxxxxxxxxxxxxx",
"kms-key-id": null,
"source-type": "image"
},
"time-created": "2019-01-16T11:22:54.286000+00:00",
"time-maintenance-reboot-due": null
},
{
"availability-domain": "gype:PHX-AD-1",
"compartment-id": "ocid1.compartment.oc1..YYYYYYYYYYYYYYYYY",
"defined-tags": {
"test_tag": {
"tag1": "test"
}
},
"display-name": "test-instance2",
"extended-metadata": {},
"fault-domain": "FAULT-DOMAIN-1",
"freeform-tags": {},
"id": "ocid1.instance.oc1.phx.YYYYYYYYYYYYYYYYY",
"image-id": "ocid1.image.oc1.phx.YYYYYYYYYYYYYYYYY",
"ipxe-script": null,
"launch-mode": "NATIVE",
"launch-options": {
"boot-volume-type": "PARAVIRTUALIZED",
"firmware": "UEFI_64",
"is-consistent-volume-naming-enabled": true,
"is-pv-encryption-in-transit-enabled": true,
"network-type": "VFIO",
"remote-data-volume-type": "PARAVIRTUALIZED"
},
"lifecycle-state": "STOPPED",
"metadata": {
"ssh_authorized_keys": "ssh-rsa YYYYYYYYYYYYYYYYY",
"user_data": "XXX"
},
"region": "phx",
"shape": "VM.Standard2.1",
"source-details": {
"boot-volume-size-in-gbs": null,
"image-id": "ocid1.image.oc1.phx.YYYYYYYYYYYYYYYYY",
"kms-key-id": null,
"source-type": "image"
},
"time-created": "2018-12-31T02:27:32.144000+00:00",
"time-maintenance-reboot-due": null
},
{
"availability-domain": "gype:PHX-AD-1",
"compartment-id": "ocid1.compartment.oc1..ZZZZZZZZZZZZZZZ",
"defined-tags": {},
"display-name": "instance-20190128-0100",
"extended-metadata": {},
"fault-domain": "FAULT-DOMAIN-3",
"freeform-tags": {},
"id": "ocid1.instance.oc1.phx.ZZZZZZZZZZZZZZZ",
"image-id": "ocid1.image.oc1.phx.ZZZZZZZZZZZZZZZ",
"ipxe-script": null,
"launch-mode": "NATIVE",
"launch-options": {
"boot-volume-type": "PARAVIRTUALIZED",
"firmware": "UEFI_64",
"is-consistent-volume-naming-enabled": true,
"is-pv-encryption-in-transit-enabled": true,
"network-type": "VFIO",
"remote-data-volume-type": "PARAVIRTUALIZED"
},
"lifecycle-state": "RUNNING",
"metadata": {
"ssh_authorized_keys": "ssh-rsa ZZZZZZZZZZZZZZZ",
"user_data": "ZZZZZZZZZZZZZZZ"
},
"region": "phx",
"shape": "VM.Standard2.1",
"source-details": {
"boot-volume-size-in-gbs": null,
"image-id": "ocid1.image.oc1.phx.ZZZZZZZZZZZZZZZ",
"kms-key-id": null,
"source-type": "image"
},
"time-created": "2019-01-27T16:01:26.157000+00:00",
"time-maintenance-reboot-due": null
}
]
}
これらのリソースの名前のみの一覧を取得する。
> oci compute instance list --query "data[*].\`"display-name\`""
[
"test-instance",
"test-instance2",
"instance-20190128-0100",
]
出力を見やすくする
jsonに対するフィルタを行いつつ、--output
オプションで"table"を指定することで最終出力結果をもう少し見やすくすることができます。
> oci compute instance list --query "data[*].[\`"display-name\`", shape]" --output table
+--------------------------------+----------------+
| Column1 | Column2 |
+--------------------------------+----------------+
| test-instance | VM.Standard1.1 |
| test-instance2 | VM.Standard2.1 |
| instance-20190128-0100 | VM.Standard2.1 |
+--------------------------------+----------------+
列名(Column)がついていないのは、フィルタする際に省略していたからです。
省略せずに、nameとvalueのペアとして、フィルタを記載するとname部分が列名として出力されます。
> oci compute instance list --query "data[*].{\`"display-name\`":\`"display-name\`", shape:shape}" -
-output table
+--------------------------------+----------------+
| display-name | shape |
+--------------------------------+----------------+
| test-instance | VM.Standard1.1 |
| test-instance2 | VM.Standard2.1 |
| instance-20190128-0100 | VM.Standard2.1 |
+--------------------------------+----------------+
3.TIPS
使っている中で気づいたことなどをメモ
- sortやsort_byで値の並び変えはできるが、項目の並び替えは指定できない
- 項目は0-9,A-Z昇順のようなので、表示名に「1.」や「2.」をつけることで制御可能
PS C:\> oci bv volume list --availability-domain "xxxx:US-ASHBURN-AD-1" --output table --query "data[*].{\`"1.availability-domain\`":\`"availability-domain\`", \`"2.display-name\`":\`"display-name\`", \`"3.size-in-mbs\`":\`"size-in-mbs\`",\`"4.volume-group-id\`":\`"volume-group-id\`"}"
+-----------------------+--------------------+---------------+-------------------+
| 1.availability-domain | 2.display-name | 3.size-in-mbs | 4.volume-group-id |
+-----------------------+--------------------+---------------+-------------------+
| xxxx:US-ASHBURN-AD-1 | test-volume1 | 524288 | None |
| xxxx:US-ASHBURN-AD-1 | test-volume2 | 524288 | None |
| xxxx:US-ASHBURN-AD-1 | test-volume3 | 524288 | None |
+-----------------------+--------------------+---------------+-------------------+
- フェルタで指定する項目の名前を間違えると、エラーにはならず、値が"none"になる
- 本当に値がnoneなのか、フィルタの項目名が間違っているのか要確認
PS C:\> oci bv volume list --availability-domain "xxxx:US-ASHBURN-AD-1" --output table --query "data[*].{\`"1.availability-domain\`":\`"availability-domain\`", \`"2.display-name\`":\`"display-name\`", \`"3.size-in-mbs\`":\`"size-in-mbs\`",\`"4.volume-group-id\`":\`"volume-group-id\`",\`"5.unexist item\`":\`"unexist item\`"}"
+-----------------------+--------------------+---------------+-------------------+----------------+
| 1.availability-domain | 2.display-name | 3.size-in-mbs | 4.volume-group-id | 5.unexist item |
+-----------------------+--------------------+---------------+-------------------+----------------+
| xxxx:US-ASHBURN-AD-1 | test-volume1 | 524288 | None | None |
| xxxx:US-ASHBURN-AD-1 | test-volume2 | 524288 | None | None |
| xxxx:US-ASHBURN-AD-1 | test-volume3 | 524288 | None | None |
+-----------------------+--------------------+---------------+-------------------+----------------+
- cliでAD名を指定する際はprefixまで付ける
- AD名は、テナンシーごとにprefixがつくので、それを確認して指定する必要がある
-
ListAvailabilityDomains
のrest apiか、oci cliのoci iam availability-domain list
、もしくはcomputeインスタンス作成画面のADを選択する箇所で確認可能
4.参考
-
マニュアル
-
Qiita記事
-
Oracle Cloud(OCI)のoci cli設定ファイルの使い方をまとめてみた
- 都度queryを書かなくて良いように、この記事で紹介しているoci_cli_rcを利用すると便利
-
OCI-CLI(with jq) cook book
- "--query"オプションではなく、パイプしてjqコマンドで整形する方法がまとめられています
-
Oracle Cloud(OCI)のoci cli設定ファイルの使い方をまとめてみた
以上