さくらのクラウドのAPIで名前で完全一致させる方法
2021-01-20 追記:今日 usacloud の v1.1.0 がリリースされ、 usacloud だけで出来ることが増えたので大幅に書き換えました。
usacloud では名前はデフォルトでは部分一致になります
さくらのクラウド の API を利用するには usacloud という CLI (コマンドラインインターフェース)が便利です。作者の yamamoto-febc さん、ありがとうございます!
usacloud は README の「基本的な使い方」に
usacloud <リソース> <サブコマンド> [オプション] [対象リソースのID or 名前(部分一致) or タグ]
とある通り、名前を指定する場合は部分一致という仕様になっています。
これは通常は便利かもしれませんが、例えば DNSオプションサービス ではドメイン名を指定するとサブドメインもマッチしてしまうので完全一致にしたいというケースもあります。
usacloud v1.1.0 からはオプション定で名前でも完全一致にできます
作者の yamamoto-febc さんに相談したところ usacloud の v1.1.0 では --argument-match-mode
というオプションが追加されました。
デフォルト値は partial
で部分一致ですが exact
を指定すれば完全一致になります。
例えば example.com というドメイン名で完全一致でDNS情報をJSON形式で出力するには以下のようにします。
usacloud dns read --output-type json --argument-match-mode exact example.com
usacloud v1.1.0 ではオプション指定で jq 形式のクエリで出力のJSONをフィルタリングできます
v1.0.3 までは --query
オプションで JMESPath のクエリを指定して出力のJSONを絞り込むことが出来ました。
v1.1.0 からは itchyny さんの gojq: Pure Go implementation of jq を使って jq のクエリを指定できるようになりました(itchyny さん素晴らしいCLIとライブラリ実装ありがとうございます!)。
v1.1.0 から追加された --query-driver
オプション(デフォルト値は jmethpath
)に jq
と指定しつつ --query
オプションに jq のクエリを書くことで利用できます。
例を示します。
usacloud dns read --output-type json --argument-match-mode exact --query-driver -jq --query '.[0].Records' example.com
横に長くてスクロールしないと見れないので引用でも書いておきます。
usacloud dns read --output-type json --argument-match-mode exact --query-driver -jq --query '.[0].Records' example.com
さらにこだわる人向け:API のフィルタリングでサーバ側で名前で完全一致も可能
通常の用途では上記の使い方で十分で、以下の対応は不要です。
usacloud では引数にリソースIDか名前かタグを指定できるという仕様の関係でサーバ側ではなくクライアント側でフィルタリングしています。
フィルタリング前の状態で大量な件数にヒットする場合は、理想はサーバ側で完全一致でフィルタリングしたいところです。
API ドキュメント の「リクエストパラメータの共通仕様」の「フィルタリング」の項を読んでみると、「文字列型カラムは中間一致」ですが「配列を与えると完全一致のOR結合」になるということがわかりました。
例えば Name
のフィールドが example.com
に完全一致するようなフィルタリングは {"Filter":{"Name":["example.com"]}}
と指定すれば良いわけです。
API ドキュメントのリクエスト例では
GET /cloud/1.1/server
{
Filter: {
"Name": "test example", // Name に test と example を両方含みます
"Zone.Name": [ "is1a", "is1b" ], // Zone.Name が is1a または is1b に完全一致
"CreatedAt <": "2011-09-01T00:00:00+0900"// 作成日時がこの時刻より前(演算子は時刻・数値カラムのみ使用可)
// (これらをすべて満たすレコードが抽出されます)
}
のようにリクエスト行の後に JSON が書かれていますが、実際には URL エンコードしてクエリストリングとして指定する必要があります。
usacloud の rest コマンドでさくらのクラウドAPIを直接呼べる
usacloud の restコマンド を使うとさくらのクラウドAPIを直接呼び出すことができます。
また rest
コマンドの -d
オプションを使うと JSON をURLエンコードしてクエリストリングとして指定もしてくれます。
フィルタリングの条件に "ServiceClass":"cloud/dns"
も追加して {"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"}}
としこれをエンコーディングして下記のようにすれば指定したドメイン名で完全一致するDNSの設定情報が取得できます。
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"}}' '/commonserviceitem'
(上記と同じ内容を引用で再掲)
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"}}' '/commonserviceitem'
usacloud
の rest
コマンドでも上で紹介したのと同様に --query-driver jq
と --query jq形式のクエリ
を指定することでフィルタリングも出来ます。例を示します。
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"}}' --query-driver jq --query '.CommonServiceItems[0].Settings.DNS.ResourceRecordSets' /commonserviceitem
(上記と同じ内容を引用で再掲)
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"}}' --query-driver jq --query '.CommonServiceItems[0].Settings.DNS.ResourceRecordSets' /commonserviceitem
さくらのクラウドのAPIの「取得キーの選択」
DNS レコードだけとか ID だけ取得したい場合は、 API ドキュメントの「取得キーの選択」で "Include":["Settings"]
や "Include":["ID"]
を追加して絞り込みが出来ます。ただし、必ずついてくる項目もあるので --query
でさらに絞り込む必要があります。
ドメイン名完全一致で ID を取得する例
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["ID"]}' --query-driver jq --query '.CommonServiceItems[0].ID' /commonserviceitem
(上記と同じ内容を引用で再掲)
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["ID"]}' --query-driver jq --query '.CommonServiceItems[0].ID' /commonserviceitem
出力例
999999999999
ドメイン名完全一致で DNS レコードを取得する例
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["Settings"]}' --query-driver jq --query '.CommonServiceItems[0].Settings.DNS.ResourceRecordSets' /commonserviceitem
(上記と同じ内容を引用で再掲)
usacloud rest request -d '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["Settings"]}' --query-driver jq --query '.CommonServiceItems[0].Settings.DNS.ResourceRecordSets' /commonserviceitem
出力例
[
{
"Name": "api",
"RData": "192.0.2.1",
"TTL": 3600,
"Type": "A"
},
…(略)…
]
参考:curl と jq だけで同じことをする方法
jq での URL エンコード
bash - How to urlencode data for curl command? - Stack Overflow の 回答 で知ったのですが stedolan/jq: Command-line JSON processor で以下の例のようにして URL エンコードすることが出来ます。
$ printf %s 'encode this'|jq -sRr @uri
encode%20this
$ jq -rn --arg x 'encode this' '$x|@uri'
encode%20this
これを使うと curl と jq だけでも同じことを実現できます。
もちろん jq の代わりに gojq でも大丈夫です。
ACCESS_TOKEN
, ACCESS_TOKEN_SECRET
, API_URL
は さくらのクラウド API v1.1 ドキュメント の「はじめに」を参照しつつ以下のように環境変数を設定しておくこととします。
export ACCESS_TOKEN=コントロールパネルのAPIキーのアクセストークン
export ACCESS_TOKEN_SECRET=コントロールパネルのAPIキーのアクセストークンシークレット
export API_URL=https://secure.sakura.ad.jp/cloud/zone/tk1a/api/cloud/1.1/ # DNSはゾーン無関係ですが東京第1ゾーンを指定
ドメイン名完全一致で ID を取得する例
curl -sS -u "$ACCESS_TOKEN:$ACCESS_TOKEN_SECRET" "$API_URL/commonserviceitem?"$(jq -rn --arg x '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["ID"]}' '$x|@uri') | jq -r '.CommonServiceItems[0].ID'
(上記と同じ内容を引用で再掲)
curl -sS -u "$ACCESS_TOKEN:$ACCESS_TOKEN_SECRET" "$API_URL/commonserviceitem?"$(jq -rn --arg x '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["ID"]}' '$x|@uri') | jq -r '.CommonServiceItems[0].ID'
(本題と関係ないのですが、 jq の前の $
をバックスラッシュでエスケープしないと KaTeX parse error: Double superscript at position 82
という感じで zenn cli でのプレビュー結果内にエラーが出ました。シングルクォート内の $
はそのままで良いけどクォートの外かダブルクォート内の $
はエスケープが必要なようです)
ドメイン名完全一致で DNS レコードを取得する例
curl -sS -u "$ACCESS_TOKEN:$ACCESS_TOKEN_SECRET" "$API_URL/commonserviceitem?"$(jq -rn --arg x '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["Settings"]}' '$x|@uri') | jq '.CommonServiceItems[0].Settings.DNS.ResourceRecordSets'
(上記と同じ内容を引用で再掲)
curl -sS -u "$ACCESS_TOKEN:$ACCESS_TOKEN_SECRET" "$API_URL/commonserviceitem?"$(jq -rn --arg x '{"Filter":{"Name":["example.com"],"ServiceClass":"cloud/dns"},"Include":["Settings"]}' '$x|@uri') | jq '.CommonServiceItems[0].Settings.DNS.ResourceRecordSets'
Discussion