OpenShift - oc command Tips - describe

OpenShift の様々な操作で使用する `oc` コマンドの `oc describe` に関する留意点をご紹介します。

### oc describe
`oc describe` コマンドは、指定したリソースの詳細を表示します。類似のコマンドとして `oc get -o yaml` や `oc get -o json` があり、これらはリソース・マニフェストの情報をそのまま表示します。
一方、`oc describe` はリソース・マニフェストの情報をそのまま表示するものと `oc describe` コマンドの実装で独自に生成した情報を表示するものが混在する事に留意が必要です。

```shell
$ oc describe --help
Show details of a specific resource or group of resources.

 Print a detailed description of the selected resources, including related resources such as events or controllers. You
may select a single object by name, all objects of that type, provide a name prefix, or label selector. For example:

 $ oc describe TYPE NAME_PREFIX

 will first check for an exact match on TYPE and NAME_PREFIX. If no such resource exists, it will output details for
every resource that has a name prefixed with NAME_PREFIX.

 Use "oc api-resources" for a complete list of supported resources.

Examples:
  # Describe a node
  oc describe nodes kubernetes-node-emt8.c.myproject.internal

  # Describe a pod
  oc describe pods/nginx

  # Describe a pod identified by type and name in "pod.json"
  oc describe -f pod.json

  # Describe all pods
  oc describe pods

  # Describe pods by label name=myLabel
  oc describe po -l name=myLabel

  # Describe all pods managed by the 'frontend' replication controller
  # (rc-created pods get the name of the rc as a prefix in the pod name)
  oc describe pods frontend

Options:
    -A, --all-namespaces=false:
        If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even
        if specified with --namespace.

    --chunk-size=500:
        Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may change in
        the future.

    -f, --filename=[]:
        Filename, directory, or URL to files containing the resource to describe

    -k, --kustomize='':
        Process the kustomization directory. This flag can't be used together with -f or -R.

    -R, --recursive=false:
        Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests
        organized within the same directory.

    -l, --selector='':
        Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching
        objects must satisfy all of the specified label constraints.

    --show-events=true:
        If true, display events related to the described object.

Usage:
  oc describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME) [options]

Use "oc options" for a list of global command-line options (applies to all commands).
```

### リソース・マニフェストの情報をそのまま表示する例
リソース・マニフェストの情報をそのまま表示しますが、対応する情報がどれか分かりづらい事があります。

```shell
$ oc describe node node1.intern  | head -n 2
Name:               node1.intern
Roles:              master,worker
```
上記に対応するリソース・マニフェストは以下の箇所になります。
```shell
oc -o yaml get node node1.intern
～
metadata:
  name: node1.intern
～
  labels:
    node-role.kubernetes.io/master: ""
    node-role.kubernetes.io/worker: ""
～
```

### 独自に生成した情報を表示する例
以下は `oc describe` が独自に生成する情報の例です。
```shell
$ oc describe node node1.intern  | awk '/^Allocated resources:/,/^Events:/'
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests          Limits
  --------           --------          ------
  cpu                9546m (60%)       30504m (192%)
  memory             36260371Ki (47%)  88772896Ki (117%)
  ephemeral-storage  5Mi (0%)          105Mi (0%)
  hugepages-1Gi      0 (0%)            0 (0%)
  hugepages-2Mi      0 (0%)            0 (0%)
  nvidia.com/gpu     1                 1
Events:              <none>
```

これは、以下の実装内で独自に計算された数値を表示しています。

https://github.com/openshift/kubernetes-kubectl/blob/master/pkg/describe/versioned/describe.go#L3302

～一部抜粋～
```shell
	reqs, limits := getPodsTotalRequestsAndLimits(nodeNonTerminatedPodsList)
	cpuReqs, cpuLimits, memoryReqs, memoryLimits, ephemeralstorageReqs, ephemeralstorageLimits :=
		reqs[corev1.ResourceCPU], limits[corev1.ResourceCPU], reqs[corev1.ResourceMemory], limits[corev1.ResourceMemory], reqs[corev1.ResourceEphemeralStorage], limits[corev1.ResourceEphemeralStorage]
	fractionCpuReqs := float64(0)
	fractionCpuLimits := float64(0)
	if allocatable.Cpu().MilliValue() != 0 {
		fractionCpuReqs = float64(cpuReqs.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
		fractionCpuLimits = float64(cpuLimits.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
	}
	fractionMemoryReqs := float64(0)
	fractionMemoryLimits := float64(0)
	if allocatable.Memory().Value() != 0 {
		fractionMemoryReqs = float64(memoryReqs.Value()) / float64(allocatable.Memory().Value()) * 100
		fractionMemoryLimits = float64(memoryLimits.Value()) / float64(allocatable.Memory().Value()) * 100
	}
	fractionEphemeralStorageReqs := float64(0)
	fractionEphemeralStorageLimits := float64(0)
	if allocatable.StorageEphemeral().Value() != 0 {
		fractionEphemeralStorageReqs = float64(ephemeralstorageReqs.Value()) / float64(allocatable.StorageEphemeral().Value()) * 100
		fractionEphemeralStorageLimits = float64(ephemeralstorageLimits.Value()) / float64(allocatable.StorageEphemeral().Value()) * 100
	}
	w.Write(LEVEL_1, "%s\t%s (%d%%)\t%s (%d%%)\n",
		corev1.ResourceCPU, cpuReqs.String(), int64(fractionCpuReqs), cpuLimits.String(), int64(fractionCpuLimits))
	w.Write(LEVEL_1, "%s\t%s (%d%%)\t%s (%d%%)\n",
		corev1.ResourceMemory, memoryReqs.String(), int64(fractionMemoryReqs), memoryLimits.String(), int64(fractionMemoryLimits))
	w.Write(LEVEL_1, "%s\t%s (%d%%)\t%s (%d%%)\n",
		corev1.ResourceEphemeralStorage, ephemeralstorageReqs.String(), int64(fractionEphemeralStorageReqs), ephemeralstorageLimits.String(), int64(fractionEphemeralStorageLimits))
	extResources := make([]string, 0, len(allocatable))
```