Home > Enterprise >  Regular expression to collect all IPs from Pod definition
Regular expression to collect all IPs from Pod definition

Time:04-29

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?

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

There should be an easier way to do it:

check the kubectl cheat sheet with many example for jsonpath or jq.

  • Related