Ansible 2.19 template change

Hi,
I upgraded to ansible 2.19.0 and start issuing lazy templating error.

Current task

    - name: Setting conf file location
      ansible.builtin.set_fact:
        _autoConfFile: "{{ tmpDir }}/silent_installation_auto.conf"

    - name: Creating the configuration file from template for installation
      ansible.builtin.template:
        src: "silent_installation.conf.in"
        dest: "{{ _autoConfFile }}"
        mode: "u=xrw,g=r,o=r"

where contains of “silent_installation.conf.in” is just key = variable settings

startDaemon="{{ service.enable | ansible.builtin.ternary('1', '0') }}"
daemonUser="{{ service.userName }}"
port="{{ service.port }}"
serviceName="{{ service.name }}"
storageDir="{{ service.storageDir }}"
storageLogDir="{{ servicestorageLogDir }}"

With this setup Im fine on 2.18 ansible but on 2.19 its start failing on lazy template dict

184         - name: Creating the configuration file from template for installation
              ^ column 11

<<< caused by >>>

'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''
Origin: /ansible/playbooks/roles/myrole/templates/silent_installation.conf.in

fatal: [instance-01]: FAILED! => {"changed": false, "msg": "Task failed: 'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''"}

Right now Im really not sure what to do. Can you give me some hint? Im thinking about trust variables but according to documentation my setup should be ok because all the values are inside vars.yml

Thanks for any advice
Karel
@lazy_containers
@template

Can you provide the full error that you received, instead of cutting off the beginning? It might also be useful to see how service, servicestorageLogDir, and any variables they reference are defined (assuming it’s failing during templating and not during task var finalization.)

Also you might want to try ansible-core 2.19.1rc1, released earlier this week, since it fixes some similar problems.

Hi, Allready done that, same result. I will post the variables and full log soon

Task itself>

If i cutoff something importat sorry about that (but the error is just duplicated)

TASK [myrole: Creating the configuration file from template for installation] ***
[ERROR]: Task failed: 'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''

Task failed.
Origin: /ansible/playbooks/roles/myrole/tasks/install.yml:184:11

182               ips: "{{ ips | combine({'runForWeb': runForWeb}, recursive=false) }}"
183
184         - name: Creating the configuration file from template for installation
                  ^ column 11

<<< caused by >>>

'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''
Origin: /ansible/playbooks/roles/myrole/templates/silent_installation.conf.in

fatal: [instance-01]: FAILED! => {"changed": false, "msg": "Task failed: 'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''"}

vars.yml

service:
  enable: true
  name: "Manager-30353"
  userName: myUser
  port: 30353
  storageDir: /tmp/storage

storageLogDir: "/home/myUser/log/InspireContentManager-30353/"

Path for the template file “silent_installation.conf.in” is correct i double checked it.

To be absolutely honest I dont know how to answer the:
“(assuming it’s failing during templating and not during task var finalization.)” question.

I will run it in the morning with debug -vvvv and post the debug run

I cannot replicate your issue in 2.19.0. If I use the values and template you provided I get the expected 'Task failed: ''servicestorageLogDir'' is undefined' error, if I define the missing variable the template works as expected.

Are you sure you’re looking at the correct location in your code? The context provided by the error does not match the pair of tasks in your initial post.

I’m referring to the actual error, which you cut out of your initial message:

[ERROR]: Task failed: 'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''

This tells us when the error occurred (“Task failed”) and what it is. Compare to:

[ERROR]: Task failed: Finalization of task args for 'ansible.builtin.template' failed: Error while resolving value for 'dest': Syntax error in template: No filter named 'nonexistentfilter'.

when the error occurs before the task even runs.

This is why it’s best to provide the full error output. It might contain information that’s useful to the people you’re asking for help.

Hello,

yes of course I just extract the problematic path of my code (thats the line 181) I will try to extract as small subset of my setup as possible to make it reproducible. Got many lines of code for downloading the installer from 3rd party site etc etc

please stand by

and thanks
Karel

1 Like

Hello guys

the is my replication repository with steps.

If there something not clear please let me know

It’s better to provide a minimal reproducer, since the process of working through pruning the extra detail will also tell you what area(s) you need to concentrate on if you want to fix the thing.

There is one problematic line in the template (which is more or less what I expected):

service2_dbType="{{ (database.myRole2.type == '') | ansible.builtin.ternary('', myRole2InternalDbTypes[database.myRole2.type | lower]) }}"

The change in ternary() evaluation has already been reported as a bug (Ansible Core: 2.19: In ternary variable is evaluated in case not triggered · Issue #85743 · ansible/ansible · GitHub) and it’s possible the fully lazy evaluation for this case will be fixed, though that would be in 2.19.2 at the earliest.

In the meantime there are a couple of obvious ways to fix this. One is to remove the special case for the empty string and handle it the same way as other accepted values:

diff --git a/ansible/src/roles/myRole/templates/silent_installation.conf.in b/ansible/src/roles/myRole/templates/silent_installation.conf.in
index d8ecf3d..bd84c36 100644
--- a/ansible/src/roles/myRole/templates/silent_installation.conf.in
+++ b/ansible/src/roles/myRole/templates/silent_installation.conf.in
@@ -27,7 +27,7 @@ service2_additionalParams="{{ myRole2.additionalParams }}"
 service2_additionalParamsSecure="{{ myRole2.additionalParamsSecure }}"

 # service2 Database connection
-service2_dbType="{{ (database.myRole2.type == '') | ansible.builtin.ternary('', myRole2InternalDbTypes[database.myRole2.type | lower]) }}"
+service2_dbType="{{ myRole2InternalDbTypes[database.myRole2.type | lower] }}"
 service2_dbTableName="{{ database.myRole2.tableName }}"
 service2_dbConnectString="{{ database.myRole2.connectString }}"
 service2_dbConnectString_fromDSN="{{ database.myRole2.connectStringFromDSN }}"
diff --git a/ansible/src/roles/myRole/vars/main.yml b/ansible/src/roles/myRole/vars/main.yml
index 9ea9d70..0b2c7a3 100644
--- a/ansible/src/roles/myRole/vars/main.yml
+++ b/ansible/src/roles/myRole/vars/main.yml
@@ -1,5 +1,6 @@
 ---
 myRole2InternalDbTypes:
+  '': ''
   mssql: MsSQL
   mysql: MySQL
   postgresql: PostgreSQL
1 Like

Hello
thank you for investigating the issue and for providing the next steps.

Is there any chance you could give me some tips on how to investigate this type of issue on my own? I really hit a dead end when trying to troubleshoot it.

flowerysong
It’s better to provide a minimal reproducer, since the process of working through pruning the extra detail will also tell you what area(s) you need to concentrate on if you want to fix the thing.

I really want to get the full details on working with variables on my side — I actually stripped down around 80 files of code — but thanks for the extra tip for next time! (Hopefully it won’t be necessary :))

I’ll try your workaround tips in the morning.

Best Regards
Kuře

You got most of the way there and provided a working reproducer, so it wasn’t too onerous to continue to pare it down (and it’s definitely better to provide a little too much than to provide so little context that the problem can’t be reproduced.)

The first thing to focus on is the template itself, since that’s what’s failing. It’s 38 entirely independent lines, and it’s unlikely that all of them are broken. So, remove lines until the template succeeds, then restore the last thing you removed. (Since these lines are independent you can speed this up by doing a binary search: remove half the lines, check for failure, then continue with the half where the failure is.) This can be quite irritating with more complex templates, but less irritating than having no idea where the failure occurs.

At that point if it’s not obvious why it’s failing you can start eliminating variables and tasks; replace set_fact with static variables, get rid of any variables that are no longer referenced, simplify and eliminate conditions and indirection and other structure. As long as running it still fails in the same way, you know that you haven’t gone too far and gotten rid of the wrong thing.

With a little effort you can pare this down to a short playbook:

- hosts: localhost
  vars:
    database:
      myRole2:
        type: ""
    myRole2InternalDbTypes:
      mssql: MsSQL
  tasks:
    - name: Template the configuration file
      ansible.builtin.template:
        src: silent_installation.conf.in
        dest: /tmp/silent_installation_auto.conf
        mode: "u=xrw,g=r,o=r"

And a one-line template:

service2_dbType="{{ (database.myRole2.type == '') | ansible.builtin.ternary('', myRole2InternalDbTypes[database.myRole2.type | lower]) }}"

that when run produce the error we’re interested in:

TASK [Template the configuration file] *****************************************
[ERROR]: Task failed: 'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''

Task failed.
Origin: /testing/ansible2.19-templateIssue/ansible/src/test.yml:9:7

7       mssql: MsSQL
8   tasks:
9     - name: Template the configuration file
        ^ column 7

<<< caused by >>>

'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''
Origin: /testing/ansible2.19-templateIssue/ansible/src/silent_installation.conf.in

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: 'ansible._internal._templating._lazy_containers._AnsibleLazyTemplateDict object' has no attribute ''"}
1 Like

Confirming 2.19.2rc1 fixing the original issue

Thanks for your time with me!

2 Likes