0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

deck利用時のJSON Pathの書き方

Last updated at Posted at 2025-05-15

deckの一部のファイル操作(patchadd-plugins等)では対象エンティティの選択にJSON Path形式を利用する。(deckのpatchadd-pluginsの説明には書いていないが、Lintingのページに記載がある)
JSON Pathの書き方はRFC-9535で規定されていて、基本的にはここで定義された書き方で書けるが、例外もある(後述)。
ここではdeckで使えるJSON Pathの書き方をdeck file add-pluginsコマンドを使って検証する。

検証では以下のファイルを用いた。

base.yaml
_format_version: "3.0"
services:
- enabled: true
  host: httpbin.org
  name: httpbin-service-1
  path: /
  port: 443
  protocol: https
  tags:
  - httpbin-1
  routes:
  - name: httpbin-route-1
    paths:
    - /httpbin-1
    protocols:
    - https
- enabled: true
  host: httpbin.konghq.com
  name: httpbin-service-2
  path: /
  port: 443
  protocol: https
  tags:
  - httpbin-2
  routes:
  - name: httpbin-route-2
    headers:
      foo:
      - bar
    paths:
    - /httpbin-2
    protocols:
    - https

add-pluginsで使うYAMLは以下をベースとする。

key-auth.yaml
_format_version: "1.0"
add-plugins:
- overwrite: false
  plugins:
  - name: key-auth
  selectors:
  - $

このselectorsでJSONPath形式でクエリが書けるので、これを色々変えてbase.yamlのどこにkey-auth.yamlで定義したプラグインを差し込めるかを検証する。

Global Scopeで追加

まず、元のkey-auth.yamlのselectorsであるが、$がルートを意味するため、Global Scopeで適用される。
適用した結果はこちら。

$ deck file add-plugins -s base.yaml key-auth-global.yaml
_format_version: "3.0"
plugins:
- name: key-auth
services:
- enabled: true
:(省略)

Service等、他のエンティティには適用されず最上位に挿入される。

Serviceへの追加

全Serviceを対象

全てのServiceに適用する場合は以下のような感じ。

  selectors:
  - $.service[*]

.でファイル内の子要素を参照する。[]で配列のアクセスとなり、*を指定することで全ての配列の要素を参照する感じになる。
実行した結果は以下となる。

_format_version: "3.0"
services:
- enabled: true
  host: httpbin.org
  name: httpbin-service-1
  path: /
  plugins:
  - name: key-auth
  port: 443
 :(省略)
- enabled: true
  host: httpbin.konghq.com
  name: 
  
  path: /
  plugins:
  - name: key-auth
  port: 443
 :(省略)

名前が一致するServiceに適用

Service名を指定する場合は以下。

- selectors:
  - $.services[?(@.name=='httpbin-service-2')]

?()でフィルタを指定する。
フィルタ内では@で現在の要素を指定、その中の.name'httpbin-service-2'と一致するものを絞って選択している。
結果は以下。

services:
- enabled: true
  host: httpbin.org
  name: httpbin-service-1
  :(省略)
- enabled: true
  host: httpbin.konghq.com
  name: httpbin-service-2
  path: /
  plugins:
  - name: key-auth
  port: 443

name ==で選択したhttpbin-service-2のみに適用された。

なお、selectors:は複数書けるようになっているが、複数書いた場合はOR条件になる。
なので、複数のService名を指定したい場合は以下のように書く。

- selectors:
  - $.services[?(@.name=='httpbin-service-1')]
  - $.services[?(@.name=='httpbin-service-2')]

タグが一致するServiceに適用

deck gateway dumpした後に、特定のタグのものにPluginを追加したいようなケースとかで実行する。
以下のような感じで書く。

- selectors:
  - $.services[?(@.tags[?(@ == 'httpbin-1')])]

先程のnameは単純な一致だったが、tagsは配列で複数書けるので、tags[]の配列のキーを比較する形で書く。

名前とタグが一致するServiceに適用

フィルタ内にAND条件を追加する。AND条件は&&で書けて、名前一致とタグ一致はこれまで検証した式がそのまま使えるので、&&で結合する。

- selectors:
  - $.services[?(@.name == 'httpbin-1' && @.tags[?(@ == 'httpbin-1')])]

Routeへの追加

全Routeを対象

- selectors:
  - $..routes[*]

$.services[*].routes[*] でもいいが、..だとどこにroutesがいても設定してくれる。Serviceに紐づかないようなRouteがいるようなケースでも使える。
逆にServiceに紐づくRouteのみ指定したい場合は$.services[*].routes[*] の方がいいと思う。

パスが一致するRouteに適用

いちいちRouteの名前なんて覚えていないが、パス名は分かるからそこにプラグイン差し込みたい、というような人向け。

- selectors:
  - $.services[*].routes[?(@.paths[?(@ == '/httpbin-1')])]

$..routes[?(@.paths[?(@ == '/httpbin-1')])]で行けそうなものだが、deckの不具合(正確には使っているライブラリの不具合)で適用できない。
なので、回避策として..を使わずに指定する。

ヘッダが一致するRouteに適用

ヘッダはdeckだとheaders.key[].valueのような構造になっているため、以下のような形になる。

- selectors:
  - $.services[*].routes[?(@.headers.foo[?(@ == "bar")])]

パスとヘッダが一致するRouteに適用

同じパスにアクセスさせるのだけど、ヘッダが違う時だけ振る舞いを変えるようなケース。

- selectors:
  - $.services[*].routes[?(@.paths[?(@ == '/httpbin-2')] && @.headers.foo[0] == 'bar']

これもバグがあり、$.services[*].routes[?(@.paths[?(@ == '/httpbin-2')] && @.headers.foo[?(@ == "bar")])]だと上手く行かない(JSONPath Online Evaluatorでは通る)。
どうもフィルタを複数通したあとに&&を使って更にフィルタを使うと構文エラーとされてしまう模様。
なので苦肉の策としてヘッダ側は配列決め打ちでフィルタを使わないようにする。

結論

JSONPathで柔軟にKongのエンティティを選択してプラグインの追加等が出来ることが確認できた。
検証ではService、Routeのみ対象としたが、Consumer等も名前が変わるだけで同じやり方で操作できるので、JSONPathを使ったselectorを活用することでdeck利用時に柔軟にYAMLをカスタマイズ出来るかと思う。
一方で、ライブラリのバグで上手く動かないケースもそこそこあることが確認できた。
使っているライブラリがBroadcomに買収されたVMware製であることを考えるとバグ修正も簡単には行かなさそうな気がするので、利用する場合(特に複雑な式を書く場合)はバグありきで事前検証をしっかりした方が良さそうだ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?