Aditi Sharma
Aditi Sharma

Reputation: 503

ansible regex to search and append ip as a registry host for container images

We are trying to update the image: field in Kubernetes YAML manifests by dynamically appending an IP address (10.20.30.40/) to the image URL, except in certain cases. Specifically, we have three scenarios to consider:

Scenario 1: Image starting with an IP address

Condition: If the image: field starts with an IP address (e.g., 10.20.30.40/), we do not modify it.

Example:

    image: 10.20.30.40/ml-pipeline/argoexec:v3.4.16-license-compliance

Scenario 2: Image not starting with an IP address

Condition: If the image: field does not start with an IP address, we append the Oxy IP (10.20.30.40/) to the image URL. Example:

    image: ml-pipeline/workflow-controller:v3.4.16-license-compliance

After modification:

    image: 10.20.30.40/ml-pipeline/workflow-controller:v3.4.16-license-compliance

Scenario 3: Image with Ansible variable

Condition: If the image: field contains an Ansible variable (e.g., {{ ... }}), it should stay as it is because the image URL is dynamically calculated based on the variable.

Example:

    image: "{{ .ProxyImage }}"

This should not be modified by appending IP.

All three samples in this YAML

    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        internal.kpt.dev/upstream-identifier: apps|Deployment|default|workflow-controller
      labels:
        application-crd-id: kubeflow-pipelines
      name: workflow-controller
      namespace: kubeflow
    spec:
      selector:
        matchLabels:
          app: workflow-controller
          application-crd-id: kubeflow-pipelines
      template:
        metadata:
          labels:
            app: workflow-controller
            application-crd-id: kubeflow-pipelines
        spec:
          containers:
          - args:
            - --configmap
            - workflow-controller-configmap
            - --executor-image
            - 10.20.30.40/ml-pipeline/argoexec:v3.4.16-license-compliance  # Scenario 1 (No change)
            command:
            - workflow-controller
            image: ml-pipeline/workflow-controller:v3.4.16-license-compliance  # Scenario 2 (Should be modified)
            name: workflow-controller
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      labels:
        app: metacontroller
        application-crd-id: kubeflow-pipelines
        kustomize.component: metacontroller
      name: metacontroller
      namespace: kubeflow
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: metacontroller
          application-crd-id: kubeflow-pipelines
          kustomize.component: metacontroller
      serviceName: ""
      template:
        metadata:
          annotations:
            sidecar.istio.io/inject: "false"
          labels:
            app: metacontroller
            application-crd-id: kubeflow-pipelines
            kustomize.component: metacontroller
        spec:
          containers:
          - command:
            - /usr/bin/metacontroller
            image: "{{ .ProxyImage }}"  # Scenario 3 (No change)
            name: metacontroller

The Ansible code I am trying and its not able to fix for 3rd scenario

    ---
    - name: Prepend Oxy IP to images without special characters or Jinja2 templates
      hosts: localhost
      become: true
    
      vars:
        kubeflow_dir_path: "/home/manifest"  # Define the manifest directory
        oxy_ip: "10.20.30.40"                # Define the Oxy server IP
    
      tasks:
        - name: Find YAML files in the manifest directory
          ansible.builtin.find:
            paths: "{{ kubeflow_dir_path }}"
            patterns: "*.yaml"
            recurse: yes
          register: yaml_files
    
        - name: Prepend Oxy IP to images that don't start with a string in quotes (excluding Jinja2 logic)
          ansible.builtin.shell: |
            find "{{ kubeflow_dir_path }}" -type f \( -name "*.yaml" -o -name "*.yml" \) -exec \
            sed -i '/^\s*image:/ { /^[{].*image:/! s/\(image:\s\)\([a-zA-Z0-9._-]*\/\)\?\([^\/]*\)/\1{{ oxy_ip }}\/\3/ } }' {} +
          register: replace_output
    
        - name: Display the list of files that were modified
          ansible.builtin.debug:
            var: replace_output.stdout

Upvotes: 0

Views: 60

Answers (1)

U880D
U880D

Reputation: 12124

The following minimal example would just work on the provided cases

m1.yaml

---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    internal.kpt.dev/upstream-identifier: apps|Deployment|default|workflow-controller
  labels:
    application-crd-id: kubeflow-pipelines
  name: workflow-controller
  namespace: kubeflow
spec:
  selector:
    matchLabels:
      app: workflow-controller
      application-crd-id: kubeflow-pipelines
  template:
    metadata:
      labels:
        app: workflow-controller
        application-crd-id: kubeflow-pipelines
    spec:
      containers:
      - args:
        - --configmap
        - workflow-controller-configmap
        - --executor-image
        - 192.0.2.254/ml-pipeline/argoexec:v3.4.16-license-compliancie
        command:
        - workflow-controller
        image: ml-pipeline/workflow-controller:v3.4.16-license-compliance
        name: workflow-controller

m2.yaml

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: metacontroller
    application-crd-id: kubeflow-pipelines
    kustomize.component: metacontroller
  name: metacontroller
  namespace: kubeflow
spec:
  replicas: 1
  selector:
    matchLabels:
      app: metacontroller
      application-crd-id: kubeflow-pipelines
      kustomize.component: metacontroller
  serviceName: ""
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "false"
      labels:
        app: metacontroller
        application-crd-id: kubeflow-pipelines
        kustomize.component: metacontroller
    spec:
      containers:
      - command:
        - /usr/bin/metacontroller
        image: "{{ .ProxyImage }}"
        name: metacontroller

oxy.yml

---
- name: Prepend Oxy IP to images without special characters or Jinja2 templates
  hosts: localhost
  become: false
  gather_facts: false

  vars:

    oxy_ip: "192.0.2.1"
    strYML: "{{ lookup('file', 'm1.yaml') }}"

  tasks:

  - name: Show from AnsibleUnsafeText
    debug:
      msg: "{{ strYML | from_yaml }}"

  - debug:
      msg: "{{ oxy_ip}}/{{ image }}"
    when:
      - not image is search('ProxyImage')
      - not image is search(oxy_ip)
    vars:
      image: "{{ ((strYML | from_yaml).spec.template.spec.containers | first).image }}"

will result into an output of

TASK [debug] **************************************************************
ok: [localhost] =>
  msg: 192.0.2.1/ml-pipeline/workflow-controller:v3.4.16-license-compliance

But one need to adopt the approach. Depending on what should be achieved there would be a lot of corner cases to cover, as well error handling necessary.

Upvotes: 0

Related Questions