grep with oc command

#### oc command output format

OpenShift では、各種情報の参照やリソース変更の操作等で、`oc command (CLI)` を使用します。一般的に広く使用される oc command の出力フォーマットには、以下のようなものがあります。

- -o なし : あらかじめ実装されたものを出力 (Default) 
- -o wide : Default に追加のフィールドを加えたものを出力
- -o custom-columns : 指定したフィールドのみを出力
- -o yaml : YAML フォーマットで出力
- -o json : JSON フォーマットで出力

Pod や Controller 等の各種リソースの詳細を確認したい場合に `-o yaml` や `-o json` を使用しますが、これらの出力を `grep command` 等を用いてフィルターすることは困難です。例えば、`openshift-image-registry` Project で稼働する全ての Pod を確認するとします。
```shell
$ oc project -q
openshift-image-registry
$ oc get pod
NAME                                               READY   STATUS      RESTARTS   AGE
cluster-image-registry-operator-554b7976dd-bg4dc   1/1     Running     0          14h
image-pruner-28225440-6gt4s                        0/1     Completed   0          4h4m
image-registry-c5757fcc7-rnxnv                     1/1     Running     1          14h
node-ca-2bfvm                                      1/1     Running     1          13h
node-ca-pjcjh                                      1/1     Running     1          13h
node-ca-q6blt                                      1/1     Running     1          13h
```
全ての Pod の詳細を確認したい場合には、以下を使用します。

```shell
# YAML Format
$ oc get pod -o yaml
# JSON Format
$ oc get pod -o json
```
この出力から、例えば、各 Pod の `.spec.serviceAccount` 情報のみを `grep command` 等を用いてフィルターすることは、簡単ではありません。
```shell
$ oc get pod -o yaml | grep "serviceAccount"
    serviceAccount: cluster-image-registry-operator
    serviceAccountName: cluster-image-registry-operator
        - serviceAccountToken:
        - serviceAccountToken:
    serviceAccount: pruner
    serviceAccountName: pruner
        - serviceAccountToken:
    serviceAccount: registry
    serviceAccountName: registry
        - serviceAccountToken:
        - serviceAccountToken:
    serviceAccount: node-ca
    serviceAccountName: node-ca
        - serviceAccountToken:
    serviceAccount: node-ca
    serviceAccountName: node-ca
        - serviceAccountToken:
    serviceAccount: node-ca
    serviceAccountName: node-ca
        - serviceAccountToken:
```

```shell
$ oc get pod -o json | grep "serviceAccount"
                "serviceAccount": "cluster-image-registry-operator",
                "serviceAccountName": "cluster-image-registry-operator",
                                    "serviceAccountToken": {
                                    "serviceAccountToken": {
                "serviceAccount": "pruner",
                "serviceAccountName": "pruner",
                                    "serviceAccountToken": {
                "serviceAccount": "registry",
                "serviceAccountName": "registry",
                                    "serviceAccountToken": {
                                    "serviceAccountToken": {
                "serviceAccount": "node-ca",
                "serviceAccountName": "node-ca",
                                    "serviceAccountToken": {
                "serviceAccount": "node-ca",
                "serviceAccountName": "node-ca",
                                    "serviceAccountToken": {
                "serviceAccount": "node-ca",
                "serviceAccountName": "node-ca",
                                    "serviceAccountToken": {
```
`jq command` 等を用いれば確認は可能ですが、都度 Command Syntax の指定が必要です。
```shell
$ oc get pod -o json | jq -r '.items[].spec.serviceAccount'
cluster-image-registry-operator
pruner
registry
node-ca
node-ca
node-ca
```

#### grep with oc command
前述の状況を改善する例として、以下のような出力フォーマットを使用してみます。
```shell
$ oc get pod -o json | jq -r 'paths(scalars) as $P | "." + ($P | @tsv | gsub("\t"; ".")) + "\t" + (getpath($P) | tostring)'
```
これによって、`JSON Path` と `Path Value` を1行で表示することができます。
先の `.spec.serviceAccount` を `grep command` でフィルターしてみます。
```shell
$ oc get pod -o json | jq -r 'paths(scalars) as $P | "." + ($P | @tsv | gsub("\t"; ".")) + "\t" + (getpath($P) | tostring)' | grep $'^.items.*.spec.serviceAccount\t'
.items.0.spec.serviceAccount    cluster-image-registry-operator
.items.1.spec.serviceAccount    pruner
.items.2.spec.serviceAccount    registry
.items.3.spec.serviceAccount    node-ca
.items.4.spec.serviceAccount    node-ca
.items.5.spec.serviceAccount    node-ca
```
フィルターの仕方を工夫することで、特定の Pod の情報のみを出力することもできます。ここでは最初の Pod (.items.0) をフィルターしてみます。
```shell
$ oc get pod -o json | jq -r 'paths(scalars) as $P | "." + ($P | @tsv | gsub("\t"; ".")) + "\t" + (getpath($P) | tostring)' | grep $'^.items.0.'
.items.0.apiVersion     v1
.items.0.kind   Pod
.items.0.metadata.annotations.cni.projectcalico.org/podIP       100.10.1.1/32
.items.0.metadata.annotations.cni.projectcalico.org/podIPs      100.10.1.2/32
.items.0.metadata.annotations.kubectl.kubernetes.io/restartedAt 2023-05-12T11:29:38Z
.items.0.metadata.annotations.openshift.io/scc  restricted
.items.0.metadata.creationTimestamp     2023-01-11T13:51:47Z
～省略～
```
このような方法を用いることで、oc command の出力を行単位でフィルターすることが可能になります。また、`Path Value` に `Escape Sequence` が含まれる場合の対処等、出力フォーマットを更に工夫することも可能です。