skip to Main Content

Apologies for this simple question, but I tried various approach without success.

This is my vars file

---
preprod:
  name: nginx
prod:
  name: apache

I am trying to pass the value of name based on the environment name user provides (preprod, prod etc).
This is my template

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: {{ env.name }} 
  name: {{ env.name }}
  namespace: default
spec:
  selector:
    matchLabels:
      app: {{ env.name }}
  template:
    metadata:
      labels:
        app: {{ env.name }}
    spec:
      containers:
      - image: {{ env.name }}
        imagePullPolicy: Always
        name: {{ env.name }}
        resources: {}

However, when I try with this using following command:

ansible-playbook playbook.yaml -e env=preprod

I am getting the following error.

fatal: [localhost]: FAILED! => {"changed": false, "msg": "AnsibleUndefinedVariable: 'str object' has no attribute 'name'"}

My expectation is the {{ env.name }} should have been replaced with the value of preprod.name as in nginx in this case.

I want users to provide the value for env via -e on the command line, it seems if I do like preprod.name directly on the template, it seems to work, but I don’t want that.

I hope this clarifies what I am trying to do, but it didn’t work.
May I know what I am missing?

2

Answers


  1. This error message indicates that the extra var passed on command line as -e is a string, and not the key (we expect) of the dict we are loading from the vars file.

    I’m making up an example playbook as you have not shown how you load your vars file. I’m using include_vars as we can name the variable to load dict into.

        # include vars with a name, so that we can access testvars[env]
        - include_vars:
            file: testvars.yml
            name: testvars
        - template:
            src: test/deployment.yaml.j2
            dest: /tmp/deployment.yaml
          vars:
            _name: "{{ testvars[env]['name'] }}"
    

    With this approach, the prod and preprod keys will be available under testvars, and can be referenced with a variable such as env.

    Then the template should use _name variable, like:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: {{ _name }} 
    
    Login or Signup to reply.
  2. Given the variables in a place where the play can find it, e.g. group_vars/all. Optionally add default_env

    shell> cat group_vars/all
    preprod:
      name: nginx
    prod:
      name: apache
    default_env:
      name: lighttpd
    

    Use vars lookup plugin to "Retrieve the value of an Ansible variable". See

    shell> ansible-doc -t lookup vars
    

    For example, the playbook

    shell> cat playbook.yml
    - hosts: test_11
      vars:
        env: "{{ lookup('vars', my_env|default('default_env')) }}"
        app: "{{ env.name }}"
      tasks:
        - debug:
            var: app
    

    by default displays

    shell> ansible-playbook playbook.yml
    ...
      app: lighttpd
    

    Now you can select the environment by declaring the variable my_env, .e.g

    shell> ansible-playbook playbook.yml -e my_env=prod
    ...
      app: apache
    

    and

    shell> ansible-playbook playbook.yml -e my_env=preprod
    ...
      app: nginx
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search