0

I'm writing ansible-playbook to divide nginx.conf with includes. In my opinion it would be more comfortable to use nginx.conf with such option cause I can include or exclude some config block at playbook vars.

At current time I have trouble with part: name: 2. Copy nginx.conf config.

playbook.yml:


- name: "setup_nginx"
  hosts: "TEST_HOST"
  gather_facts: yes
  remote_user: root

  vars:

    nginx_worker_processes:          "{{ ansible_processor_cores }}"                                            
    nginx_worker_connections:        "32768"                                                                    
    nginx_worker_rlimit_nofile:      "{{ (ansible_processor_cores*{{ nginx_worker_connections }}*2)|int|abs }}" 
    nginx_directories:
        - directory: inc
          nginx_files:
            - file: "gzip.inc"                                   
            - file: "logs.inc"                                     
            - file: "mime.types"                                 
            - file: "tuning.inc"                   
            - file: "proxy.inc"                                    
            - file: "ssl.inc"                    
        - directory: sites
          nginx_files: 
            - file: "mysite1"                                     
            - file: "mysite2"                               
- tasks: 

  - name: 1. Create nginx directories
    file:
      path: "/etc/nginx/{{ item.directory }}"
      state: directory
      owner: nginx
      group: nginx
    with_items:
     - "{{ nginx_directories }}"

  - name: 2. Copy nginx.conf config.
    template:
       src: nginx.conf.j2
       dest: /etc/nginx/nginx.conf
       mode: 0640
       owner: nginx
       group: nginx
       backup: yes
    with_subelements:
     - "{{ nginx_directories }}"
     - nginx_files

nginx.conf.j2:

user nginx;

worker_processes {{ ansible_processor_cores }};                      

events {
worker_connections 32768;                                            
use epoll;                                                           
multi_accept on;                                                                           
}

worker_rlimit_nofile {{ (ansible_processor_cores*32768*2)|int|abs }};

http {

{% for val in nginx_directories %}
include /etc/nginx/{{ item.0.directory }}/{{ item.1.file }};
{% endfor %}

}

I expect result:

user nginx;

worker_processes 1;  

events {
worker_connections 32768;                                            
use epoll;                                                           
multi_accept on;                                                                          
}

worker_rlimit_nofile 65536;

http {

include /etc/nginx/inc/gzip.inc;
include /etc/nginx/inc/logs.inc;
include /etc/nginx/inc/mime.types;
include /etc/nginx/inc/tuning.inc;
include /etc/nginx/inc/proxy.inc;
include /etc/nginx/inc/ssl.inc;
include /etc/nginx/sites/mysite1;
include /etc/nginx/sites/mysite2;

}

But actual result:

user nginx;

worker_processes 1; 

events {
worker_connections 32768;                                            
use epoll;                                                           
multi_accept on;                                                                          
}

worker_rlimit_nofile 65536;

http {

include /etc/nginx/sites/mysite2.j2;
include /etc/nginx/sites/mysite2.j2;

}

I think the trouble is that I'm not correctly define subelements at template nginx.conf.j2.

Regards

Kein
  • 165
  • 2
  • 15

1 Answers1

3

Remove the loop in you template task and in your template use

{% for val in nginx_directories | subelements('nginx_files') %}
include /etc/nginx/{{ val.0.directory }}/{{ val.1.file }};
{% endfor %}

FWIW. There is an elegant solution with config_encoder_filters which encodes YAML data

my_nginx_vhost_config:
  - server:
    - listen 8080
    - server_name www.example.com
    - "location /":
      - root /usr/local/www/nginx-dist/
      - index index.html

with simple template

# {{ ansible_managed }}
{{ my_nginx_vhost_config | encode_nginx }}

to nginx configuration

# cat /usr/local/etc/nginx/conf.d/default.conf
# Ansible managed
server {
  listen 8080;
  server_name www.example.com;

  location / {
    root /usr/local/www/nginx-dist/;
    index index.html;
  }
}

Details are available in the nginx role.

Zeitounator
  • 38,476
  • 7
  • 53
  • 66
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Thanks, nice example. But with Your solution ```loop: "{{ nginx_directories }}"``` get error ```(item={u'directory': u'sites', u'nginx_files': [{u'file': u'mysite1.j2'}, {u'file': u'mysite2.j2'}]}) => {"changed": false, "item": {"directory": "sites", "nginx_files": [{"file": "mysite1.j2"}, {"file": "mysite2.j2"}]}, "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'nginx_directories'"}``` – Kein Mar 28 '19 at 02:06
  • Right. The loop in the template should be "{% for val in item.nginx_files %}". I've fixed the answer. Sorry for the noise. – Vladimir Botka Mar 28 '19 at 06:08
  • Thanks, but this doesn't works as expected: it's works only with latest element in list ```item.directory``` so I get as result only this two lines: ```include /etc/nginx/sites/mysite1.j2; include /etc/nginx/sites/mysite2.j2;``` – Kein Mar 28 '19 at 07:55
  • Thanks for the reference to the config encoder role. It is awesome ! Meanwhile, I think your answer does not exactly answer the question: @gremlintv2 is trying to create **one single** nginx conf file with all includes from the template. IMHO: 1. There is a missing task which should loop over `nginx_files` subelement to upload all include files (unless already present..) 2. Template task should not use loop, but the template internally should loop on the subelements it wants to include (`for val in nginx_directories | subelements('nginx_files')`) – Zeitounator Mar 28 '19 at 07:55
  • @olivier-clavel ```There is a missing task which should loop over nginx_files subelement to upload all include files```. There will be the third task at my playbook to upload templates to target server, but post I post ready solution after I get working second task. Regards. – Kein Mar 28 '19 at 08:00
  • For the record. Ultimately [nginxinc/ansible-role-nginx](https://github.com/nginxinc/ansible-role-nginx) should be The Role. – Vladimir Botka Mar 28 '19 at 08:06
  • 1
    @vladimir-botka, @olivier-clavel Thanks a lot for all of You! Just remove loop from task and add Your line ```(for val in nginx_directories | subelements('nginx_files'))``` in template and all works as expected. – Kein Mar 28 '19 at 08:25
  • 1
    I just edited the answer with the final solution. It should be accepted by @VladimirBotka to be visible to all. – Zeitounator Mar 28 '19 at 08:27
  • Accepted. Thank you! – Vladimir Botka Mar 28 '19 at 08:38