Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return integer value without quote when using variable

I'm new to Ansible (about 1 week experience). I have this playbook that creates a deployment in my Kubernetes cluster using the module kubernetes.core.k8s.

...
  vars:
    worker_count: "{{ lookup('ansible.builtin.env', 'worker_count') }}"
  tasks:
    - name: Create a deployment
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: worker
            namespace: default
            labels:
              app: worker
          spec:
            replicas: "{{ worker_count }}"  <--- the problem
            selector:
              matchLabels:
                app: worker
...

In the vars section, I retrieve worker_count from env var, and use it in the replicas field.

When I tried to run it with Python package ansible_runner:

import ansible_runner
ansible_runner.run(playbook="path/to/pb", envvars={"worker_count": 5})

I got the error (I tried running the playbook with ansible-playbook CLI and got the same error).

fatal: [localhost]: FAILED! => {"changed": false, "error": 400, "msg": "Deployment worker: Failed to create object: b'{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Deployment in version \\"v1\\" cannot be handled as a Deployment: json: cannot unmarshal string into Go struct field DeploymentSpec.spec.replicas of type int32","reason":"BadRequest","code":400}\n'", "reason": "Bad Request", "status": 400}

So I tried to change the replicas line to:

replicas: "{{ worker_count | int }}"

But it still gives the same error. What I understand is by using the additional | int, it is cast to integer but then returned as string again. You can do integer operations (addition, division, etc.) to the variable, but it will still return the result in String with the quotes " (source1, source2). That's why it still gives the same error.

So I figured I need to return the variable without the quote, but I can't find a way for this after hours looking on the internet.

like image 315
Rahadian Panji Avatar asked Oct 16 '25 21:10

Rahadian Panji


1 Answers

Note: In the below examples, Ansible callback yaml is used to render stdout.

See:

  • DEFAULT_STDOUT_CALLBACK

  • community.general.yaml callback

  • Or, display the help in CLI

ansible-doc -t callback yaml

The below playbook explains what's going on

shell> cat pb2.yml
- hosts: localhost

  vars:

    w1: 5
    w2: '5'
    w3: "{{ w1 }}"
    w4: "{{ w1 + 1 - 1 }}"

  tasks:

    - debug:
        msg: |
          w1: {{ w1 }}
          w1|type_debug: {{ w1|type_debug }}
          w2: {{ w2 }}
          w2|type_debug: {{ w2|type_debug }}
          w3: {{ w3 }}
          w3|type_debug: {{ w3|type_debug }}
          w4: {{ w4 }}
          w4|type_debug: {{ w4|type_debug }}

gives (abridged)

shell> ansible-playbook pb2.yml
  ...
  msg: |-
    w1: 5
    w1|type_debug: int
    w2: 5
    w2|type_debug: AnsibleUnicode
    w3: 5
    w3|type_debug: int
    w4: 5
    w4|type_debug: str

The type of w1 is an integer and the type of w2 is a string. The type of w3 is also an integer because Jinja is not used in this simple assignment. But Jinja is used as long as there are any operations in the template. This is the reason for w4 being a string.

The result of a Jinja template is a string. You can change it by using DEFAULT_JINJA2_NATIVE:

This option preserves variable types during template operations.

This makes the type of w4 an integer.

shell> ANSIBLE_JINJA2_NATIVE=true ansible-playbook pb2.yml
  ...
    w4|type_debug: int

The below playbook will test the environment variable worker_count

- hosts: localhost

  vars:

    worker_count: "{{ lookup('env', 'worker_count') }}"
    
    definition:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: worker
        namespace: default
        labels:
          app: worker
      spec:
        replicas: "{{ worker_count }}"
        selector:
          matchLabels:
            app: worker

  tasks:

    - debug:
        msg: |
          worker_count: {{ worker_count }}
          worker_count|type_debug: {{ worker_count|type_debug }}
          definition.spec.replicas: {{ definition.spec.replicas }}
          definition.spec.replicas|type_debug: {{ definition.spec.replicas|type_debug }}

gives (abridged)

shell> worker_count=5 ansible-playbook pb.yml
  ...
  msg: |-
    worker_count: 5
    worker_count|type_debug: AnsibleUnsafeText
    definition.spec.replicas: 5
    definition.spec.replicas|type_debug: AnsibleUnsafeText

You'll get strings unless you set ANSIBLE_JINJA2_NATIVE=true

shell> ANSIBLE_JINJA2_NATIVE=true worker_count=5 ansible-playbook pb.yml
  ...
  msg: |-
    worker_count: 5
    worker_count|type_debug: int
    definition.spec.replicas: 5
    definition.spec.replicas|type_debug: int

Ansible Runner recognizes this option too. The Python script

shell> cat pb.py
import ansible_runner
r = ansible_runner.run(private_data_dir="/scratch/tmp7/test-565",
                       playbook="pb.yml",
                       envvars={"worker_count": 5})

gives (abridged)

shell> python3 pb.py

PLAY [localhost] ***************************************************************

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "worker_count: 5\nworker_count|type_debug: AnsibleUnsafeText\ndefinition.spec.replicas: 5\ndefinition.spec.replicas|type_debug: AnsibleUnsafeText\n"
}
  ...

You'll also get strings unless you set ANSIBLE_JINJA2_NATIVE=true

shell> ANSIBLE_JINJA2_NATIVE=true python3 pb.py

PLAY [localhost] ***************************************************************

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "worker_count: 5\nworker_count|type_debug: int\ndefinition.spec.replicas: 5\ndefinition.spec.replicas|type_debug: int\n"
}
  ...
like image 177
Vladimir Botka Avatar answered Oct 19 '25 11:10

Vladimir Botka



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!