0

I am trying to collect IP addresses of the pods which has 3 network interfaces attached to. From the output of kubectl get pod .. -o yaml, I would like to collect the IPs of 2nd and 3rd interfaces including pod-name.

kubectl describe pod data:

apiVersion: v1
items:
- apiVersion: v1
  kind: Pod
  metadata:
    annotations:
      k8s.v1.cni.cncf.io/network-status: |-
        [{
            "name": "default-cni-network",
            "ips": [
                "10.244.160.191"
            ],
            "default": true,
            "dns": {}
        },{
            "name": "minio-tenant/minio-sriov1",
            "interface": "net1",
            "ips": [
                "10.56.217.100"
            ],
            "mac": "6a:58:82:8a:93:7b",
            "dns": {},
            "device-info": {
                "type": "pci",
                "version": "1.0.0",
                "pci": {
                    "pci-address": "0000:b1:02.7"
                }
            }
        },{
            "name": "minio-tenant/minio-sriov2",
            "interface": "net2",
            "ips": [
                "10.56.218.100"
            ],
            "mac": "66:a2:70:eb:5e:04",
            "dns": {},
            "device-info": {
                "type": "pci",
                "version": "1.0.0",
                "pci": {
                    "pci-address": "0000:b1:14.0"
                }
            }
        }]
      k8s.v1.cni.cncf.io/networks: minio-sriov1,minio-sriov2
      k8s.v1.cni.cncf.io/networks-status: |-
        [{
            "name": "default-cni-network",
            "ips": [
                "10.244.160.191"
            ],
            "default": true,
            "dns": {}
        },{
            "name": "minio-tenant/minio-sriov1",
            "interface": "net1",
            "ips": [
                "10.56.217.100"
            ],
            "mac": "6a:58:82:8a:93:7b",
            "dns": {},
            "device-info": {
                "type": "pci",
                "version": "1.0.0",
                "pci": {
                    "pci-address": "0000:b1:02.7"
                }
            }
        },{
            "name": "minio-tenant/minio-sriov2",
            "interface": "net2",
            "ips": [
                "10.56.218.100"
            ],
            "mac": "66:a2:70:eb:5e:04",
            "dns": {},
            "device-info": {
                "type": "pci",
                "version": "1.0.0",
                "pci": {
                    "pci-address": "0000:b1:14.0"
                }
            }
        }]
      kubernetes.io/psp: node-exporter
      meta.helm.sh/release-name: minio-tenant
      meta.helm.sh/release-namespace: minio-tenant
      min.io/revision: "0"
    creationTimestamp: "2022-04-27T08:09:45Z"
    generateName: minio-tenant-ss-0-
    labels:
      app: minio
      app.kubernetes.io/managed-by: Helm
      controller-revision-hash: minio-tenant-ss-0-7976bbfbc6
      statefulset.kubernetes.io/pod-name: minio-tenant-ss-0-0
  spec:
    affinity:
    containers:
    - args:
      - :9090
      env:
      - name: MINIO_UPDATE

Using this regular expression:

networks-status:[\s\S]*?
(?:")(name)(?:":\s*")([\S]*)(?:",[\s]*)
(?:")(interface)(?:":\s*")([\S]*)(?:",[\s\S]*?)
(?:")(ips)(?:":\s*\[\s*")([\S]*)(?:")
[\s\S]*?(pod-name)(?::\s)([\S]*)

I would like to get the following output:

name
minio-tenant/minio-sriov1
interface
net1
ips
10.56.217.100
name
minio-tenant/minio-sriov2
interface
net2
ips
10.56.218.100
pod-name
minio-tenant-ss-0-0

It gets me:

name
minio-tenant/minio-sriov1
interface
net1
ips
10.56.217.100
pod-name
minio-tenant-ss-0-0

There is missing portion of IP:

name
minio-tenant/minio-sriov2
interface
net2
ips
10.56.218.100

If I use * or + to repeat on the data section, I am getting unexpected result.

networks-status:[\s\S]*?
(
(?:")(name)(?:":\s*")([\S]*)(?:",[\s]*)
(?:")(interface)(?:":\s*")([\S]*)(?:",[\s\S]*?)
(?:")(ips)(?:":\s*\[\s*")([\S]*)(?:")
)*
[\s\S]*?(pod-name)(?::\s)([\S]*)

Can you give some hints how I can get the expected results?

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
spark
  • 531
  • 6
  • 17
  • 2
    Why not use jq, might be easier. – Chris Apr 28 '22 at 11:49
  • I tried to use 'jq' tool but the json format gives a lot of escape characters in annotations: which I can't use with jq properly. for example, set -o pipefail && kubectl get pods -l app=minio -n minio-tenant -o json |jq -r '[.items[] | {ips: .metadata.annotations["k8s.v1.cni.cncf.io/networks-status"]}]' – spark Apr 28 '22 at 14:08
  • output is cut off: [ { "ips": "[{\n \"name\": \"default-cni-network\",\n \"ips\": [\n \"10.244.160.191\"\n ],\n \"default\": true,\n \"dns\": {}\n},{\n \"name\": \"minio-tenant/minio-sriov1\",\n \"interface\": \"net1\",\n \"ips\": [\n \"10.56.217.100\"\n ],\n ,\n \"version\": \"1.0.0\",\n \"pci\": {\n \"pci-address\": \"0000:b1:02.7\"\n }\n }\n},{\n \"name\": \"minio-tenant/minio-sriov2\",\n \"interface\": \"net2\",\n \"ips\": [\n \"10.56.218.100\"\n ],\n \"mac\": \ }\n}]" } ] – spark Apr 28 '22 at 14:09
  • 2
    1) I personally don't understand clearly your expectation. 2) using regex to extract values available as strings in a Json structure is pure non sense. Ansible parses Json and has plethora of filters to work with data structures. – Zeitounator Apr 28 '22 at 17:54
  • using regex is a bad idea, consider `jq` – P.... Apr 28 '22 at 18:39
  • That is because k8s returns you string representation of JSON(s), not JSON(s), use a `| from_json` on that string and you can come back to using _'normal'_ querying of object like @Zeitounator pointed. – β.εηοιτ.βε Apr 29 '22 at 07:50

2 Answers2

1

As I said in the comments, jq is the tool of your choise here.

$ kubectl get pod <name> -o json | jq -r '.items[].metadata.annotations."k8s.v1.cni.cncf.io/network-status" | fromjson | del(.[0]) | .[] | .name + "\t" + .interface + "\t" + .ips[]'

First we get the value of the annotation by .items[].metadata.annotations."k8s.v1.cni.cncf.io/network-status" which returns a string with json in it. So we use fromjson to convert it from json and get an array. We delete the first entry del(.[0]), because you wrote you only want the 2nd and 3rd and in the end print the name, the interface and the ip separated with a tab for each element .[] | .name + "\t" + .interface + "\t" + .ips[].

This will output

minio-tenant/minio-sriov1   net1    10.56.217.100
minio-tenant/minio-sriov2   net2    10.56.218.100
Chris
  • 5,109
  • 3
  • 19
  • 40
1

Don't use regular expression for this, it is a little bit like trying to use them to parse HTML, it is a non sense, especially because Ansible is very JSON capable. Your issue here lies in the fact that those JSON snippets are in string in your YAML dictionary, but you can use the from_json filter in order to query them.

Here, I am using a json_query and JMESPath to retrieve the objects as you where expecting them:

- debug:
    var: >-
      {
        'networks': _metadata.annotations['k8s.v1.cni.cncf.io/network-status']
          | from_json
          | json_query('[?default != `true`].{
            name: name,
            interface: interface,
            ips: ips
          }'),
        'pod-name': _metadata.labels['statefulset.kubernetes.io/pod-name']
      }
  vars:
    _metadata: "{{ k8s.stdout['items'].0.metadata }}"

This would yield:

networks:
- interface: net1
  ips:
  - 10.56.217.100
  name: minio-tenant/minio-sriov1
- interface: net2
  ips:
  - 10.56.218.100
  name: minio-tenant/minio-sriov2
pod-name: minio-tenant-ss-0-0
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83