From: Christian Pointner Date: Mon, 26 Nov 2018 22:42:25 +0000 (+0100) Subject: fix role name for openwrt/image X-Git-Url: https://git.realraum.at/?a=commitdiff_plain;h=29fb96f3637ec61bbc45fc00573c6f4d522d3667;p=noc.git fix role name for openwrt/image --- diff --git a/ansible/roles/openwrt/image/README.md b/ansible/roles/openwrt/image/README.md new file mode 100644 index 0000000..95d9d10 --- /dev/null +++ b/ansible/roles/openwrt/image/README.md @@ -0,0 +1,8 @@ +# Build OpenWRT images with Ansible + +TODO: add possibility to disable root logins using /etc/shadow + this will also take care of the annoying + "There is no root password defined ..." + message when you log in. + +## Configuration diff --git a/ansible/roles/openwrt/image/defaults/main.yml b/ansible/roles/openwrt/image/defaults/main.yml new file mode 100644 index 0000000..f00a2e8 --- /dev/null +++ b/ansible/roles/openwrt/image/defaults/main.yml @@ -0,0 +1,17 @@ +--- +openwrt_variant: lede +openwrt_release: 17.01.4 +openwrt_download_dir: "{{ global_cache_dir }}/openwrt" +openwrt_tarball_basename: "{{ openwrt_variant }}-imagebuilder-{{ openwrt_release }}-{{ openwrt_arch }}-{{ openwrt_target }}.Linux-x86_64" +openwrt_tarball_name: "{{ openwrt_tarball_basename }}.tar.xz" +openwrt_target: generic + +openwrt_output_dir: "{{ global_artifacts_dir }}/{{ inventory_hostname }}/openwrt" +openwrt_output_image_name_base: "{{ openwrt_variant }}-{{ openwrt_release }}-{{ openwrt_arch }}{% if openwrt_target != 'generic' %}-{{ openwrt_target }}{% endif %}" +openwrt_output_image_suffixes: + - squashfs-sysupgrade.bin + - squashfs-factory.bin + +openwrt_packages_remove: [] +openwrt_packages_add: [] +openwrt_packages_extra: [] diff --git a/ansible/roles/openwrt/image/openwrt-keyring.gpg b/ansible/roles/openwrt/image/openwrt-keyring.gpg new file mode 100644 index 0000000..e8a3e8b Binary files /dev/null and b/ansible/roles/openwrt/image/openwrt-keyring.gpg differ diff --git a/ansible/roles/openwrt/image/tasks/fetch.yml b/ansible/roles/openwrt/image/tasks/fetch.yml new file mode 100644 index 0000000..f68c87d --- /dev/null +++ b/ansible/roles/openwrt/image/tasks/fetch.yml @@ -0,0 +1,52 @@ +--- +- name: Create download directory + file: + dest: "{{ openwrt_download_dir }}" + state: directory + +- block: + - name: Generate OpenWrt download URLs + set_fact: + openwrt_url: + https://downloads.openwrt.org/releases/{{ openwrt_release }}/targets/{{ openwrt_arch | mandatory }}/{{ openwrt_target }} + + - name: Download sha256sums + get_url: + url: "{{ openwrt_url }}/sha256sums" + dest: "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256" + + - name: Download sha256sums.asc + get_url: + url: "{{ openwrt_url }}/sha256sums.asc" + dest: "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256.asc" + + - name: Check OpenPGP signature + command: >- + gpg2 --no-options --no-default-keyring --secret-keyring /dev/null + --verify --keyring "{{ role_path }}/openwrt-keyring.gpg" + --trust-model always + "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256.asc" + changed_when: False + + - name: Extract SHA256 hash of the imagebuilder archive + command: grep '{{ openwrt_tarball_name }}' "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256" + register: sha256 + changed_when: False + + - name: Download imagebuilder + get_url: + url: "{{ openwrt_url }}/{{ openwrt_tarball_name }}" + dest: "{{ openwrt_download_dir }}/{{ openwrt_tarball_name }}" + checksum: sha256:{{ sha256.stdout.split(' ') | first }} + + rescue: + - name: Delete downloaded artifacts + file: + path: "{{ item }}" + state: absent + with_items: + - "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256" + - "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256.asc" + - "{{ openwrt_download_dir }}/{{ openwrt_tarball_name }}" + - fail: + msg: Something borked diff --git a/ansible/roles/openwrt/image/tasks/main.yml b/ansible/roles/openwrt/image/tasks/main.yml new file mode 100644 index 0000000..1781d9e --- /dev/null +++ b/ansible/roles/openwrt/image/tasks/main.yml @@ -0,0 +1,38 @@ +--- +- include: fetch.yml + run_once: true + when: openwrt_imgbuilder_tarball is not defined + +- block: + - include: prepare.yml + + - name: Create the output directory for built images + file: + path: "{{ openwrt_output_dir }}" + state: directory + + - set_fact: + openwrt_packages: >- + {{ openwrt_packages_remove | map('regex_replace', '^', '-') | join(' ') }} + {{ openwrt_packages_add | join(' ') }} + {{ openwrt_packages_extra | join(' ') }} + + - name: Build the OpenWrt image + command: >- + make -C {{ openwrt_imgbuilder_dir }}/{{ openwrt_tarball_basename }} image + {% if openwrt_profile is defined %}PROFILE="{{ openwrt_profile }}" {% endif %} + FILES="{{ openwrt_imgbuilder_files }}" + PACKAGES="{{ openwrt_packages }}" + {% if openwrt_extra_name is defined %} EXTRA_IMAGE_NAME="{{ openwrt_extra_name }}" {% endif %} + + - name: Copy newly built OpenWrt image + with_items: "{{ openwrt_output_image_suffixes }}" + copy: + src: "{{ openwrt_imgbuilder_dir }}/{{ openwrt_tarball_basename }}/bin/targets/{{ openwrt_arch }}/{{ openwrt_target }}/{{ openwrt_output_image_name_base }}-{{ item }}" + dest: "{{ openwrt_output_dir }}" + + always: + - name: Delete the temporary build directory + file: + path: "{{ openwrt_imgbuilder_dir }}" + state: absent diff --git a/ansible/roles/openwrt/image/tasks/prepare.yml b/ansible/roles/openwrt/image/tasks/prepare.yml new file mode 100644 index 0000000..b6b67c5 --- /dev/null +++ b/ansible/roles/openwrt/image/tasks/prepare.yml @@ -0,0 +1,94 @@ +--- +- name: Create temporary build directory + command: mktemp --tmpdir -d openwrt-{{ inventory_hostname }}.XXXXXX + register: tmpdir + +- set_fact: + openwrt_imgbuilder_dir: "{{ tmpdir.stdout }}" + openwrt_imgbuilder_files: "{{ tmpdir.stdout }}/files" + +- name: Create the directories for mixins + file: + path: "{{ item }}" + state: directory + mode: '0755' + with_items: + - "{{ openwrt_download_dir }}/dl/{{ openwrt_arch }}" + - "{{ openwrt_imgbuilder_files }}/etc/config" + - "{{ openwrt_mixin | map('dirname') | map('regex_replace', '^', openwrt_imgbuilder_files) | unique | list }}" + + +- name: Copy mixins in place [1/2] + copy: + src: "{{ item.value.file }}" + dest: "{{ openwrt_imgbuilder_files }}/{{ item.key }}" + mode: "{{ item.value.mode | default('0644') }}" + with_dict: "{{ openwrt_mixin }}" + when: '"file" in item.value' + loop_control: + label: "{{ item.key }}" + +- name: Copy mixins in place [2/2] + copy: + content: "{{ item.value.content }}" + dest: "{{ openwrt_imgbuilder_files }}/{{ item.key }}" + mode: "{{ item.value.mode | default('0644') }}" + with_dict: "{{ openwrt_mixin }}" + when: '"content" in item.value' + loop_control: + label: "{{ item.key }}" + +- name: Generate /etc/fstab + mount: + fstab: "{{ openwrt_imgbuilder_files }}/etc/fstab" + state: present + src: "{{ item.src | default(omit) }}" + path: "{{ item.path | default(omit) }}" + fstype: "{{ item.fstype | default(omit) }}" + opts: "{{ item.opts | default(omit) }}" + boot: "{{ item.boot | default(omit) }}" + dump: "{{ item.dump | default(omit) }}" + passno: "{{ item.passno | default(omit) }}" + when: openwrt_mounts is defined + with_items: "{{ openwrt_mounts }}" + loop_control: + label: "{{ item.path }}" + + +- name: Create UCI configuration files + template: + src: uci.j2 + dest: "{{ openwrt_imgbuilder_files }}/etc/config/{{ item.key }}" + mode: 0644 + trim_blocks: yes +# force: no ## TODO: fail when overwriting a file + with_dict: "{{ openwrt_uci }}" + loop_control: + label: "{{ item.key }}" + +- name: Create /etc/passwd + template: + src: passwd.j2 + dest: "{{ openwrt_imgbuilder_files }}/etc/passwd" + mode: 0644 + trim_blocks: yes + when: openwrt_users is defined + +- name: Create /etc/group + template: + src: group.j2 + dest: "{{ openwrt_imgbuilder_files }}/etc/group" + mode: 0644 + trim_blocks: yes + when: openwrt_groups is defined or openwrt_users is defined + +- unarchive: + copy: False + src: "{{ openwrt_download_dir }}/{{ openwrt_tarball_name }}" + dest: "{{ openwrt_imgbuilder_dir }}" + +- name: Symlink the cache repository + file: + state: link + src: "{{ openwrt_download_dir }}/dl/{{ openwrt_arch }}" + path: "{{ openwrt_imgbuilder_dir }}/{{ openwrt_tarball_basename }}/dl" diff --git a/ansible/roles/openwrt/image/templates/group.j2 b/ansible/roles/openwrt/image/templates/group.j2 new file mode 100644 index 0000000..cb433b8 --- /dev/null +++ b/ansible/roles/openwrt/image/templates/group.j2 @@ -0,0 +1,21 @@ +{{ ansible_managed | comment }} +root:x:0: +daemon:x:1: +adm:x:4: +mail:x:8: +audio:x:29: +www-data:x:33: +ftp:x:55: +users:x:100: +network:x:101: +{% for name, opt in openwrt_users.items() %} +{% if 'group_id' not in opt %} +{{ name }}:x:{{ opt.id | default(loop.index + 110) }}: +{% endif %} +{% endfor %} +{% if openwrt_groups is defined %} +{% for name, opt in openwrt_groups.items() %} +{{ name }}:x:{{ opt.id | default(loop.index + 200) }}: +{% endfor %} +{% endif %} +nogroup:x:65534: diff --git a/ansible/roles/openwrt/image/templates/passwd.j2 b/ansible/roles/openwrt/image/templates/passwd.j2 new file mode 100644 index 0000000..9beaeb6 --- /dev/null +++ b/ansible/roles/openwrt/image/templates/passwd.j2 @@ -0,0 +1,9 @@ +{{ ansible_managed | comment }} +root:x:0:0:root:/root:/bin/ash +daemon:*:1:1:daemon:/var:/bin/false +ftp:*:55:55:ftp:/home/ftp:/bin/false +network:*:101:101:network:/var:/bin/false +{% for name, opt in openwrt_users.items() %} +{{ name }}:*:{{ opt.id | default(loop.index + 110) }}:{{ opt.gid | default(loop.index + 110) }}:{{ name }}:{{ opt.home | default('/nonexistent') }}:{{ opt.shell | default('/bin/false') }} +{% endfor %} +nobody:*:65534:65534:nobody:/var:/bin/false diff --git a/ansible/roles/openwrt/image/templates/uci.j2 b/ansible/roles/openwrt/image/templates/uci.j2 new file mode 100644 index 0000000..3cc480b --- /dev/null +++ b/ansible/roles/openwrt/image/templates/uci.j2 @@ -0,0 +1,15 @@ +{{ ansible_managed | comment }} + +{% for section in item.value %} +config {{ section.name }} +{% for option, value in section.options.items() %} +{% if value is iterable and value is not string %} +{% for v in value %} + list {{ option }} '{{ v }}' +{% endfor %} +{% else %} + option {{ option }} '{{ value }}' +{% endif %} +{% endfor %} + +{% endfor %} diff --git a/ansible/roles/openwrt/openwrt-image/README.md b/ansible/roles/openwrt/openwrt-image/README.md deleted file mode 100644 index 95d9d10..0000000 --- a/ansible/roles/openwrt/openwrt-image/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Build OpenWRT images with Ansible - -TODO: add possibility to disable root logins using /etc/shadow - this will also take care of the annoying - "There is no root password defined ..." - message when you log in. - -## Configuration diff --git a/ansible/roles/openwrt/openwrt-image/defaults/main.yml b/ansible/roles/openwrt/openwrt-image/defaults/main.yml deleted file mode 100644 index f00a2e8..0000000 --- a/ansible/roles/openwrt/openwrt-image/defaults/main.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -openwrt_variant: lede -openwrt_release: 17.01.4 -openwrt_download_dir: "{{ global_cache_dir }}/openwrt" -openwrt_tarball_basename: "{{ openwrt_variant }}-imagebuilder-{{ openwrt_release }}-{{ openwrt_arch }}-{{ openwrt_target }}.Linux-x86_64" -openwrt_tarball_name: "{{ openwrt_tarball_basename }}.tar.xz" -openwrt_target: generic - -openwrt_output_dir: "{{ global_artifacts_dir }}/{{ inventory_hostname }}/openwrt" -openwrt_output_image_name_base: "{{ openwrt_variant }}-{{ openwrt_release }}-{{ openwrt_arch }}{% if openwrt_target != 'generic' %}-{{ openwrt_target }}{% endif %}" -openwrt_output_image_suffixes: - - squashfs-sysupgrade.bin - - squashfs-factory.bin - -openwrt_packages_remove: [] -openwrt_packages_add: [] -openwrt_packages_extra: [] diff --git a/ansible/roles/openwrt/openwrt-image/openwrt-keyring.gpg b/ansible/roles/openwrt/openwrt-image/openwrt-keyring.gpg deleted file mode 100644 index e8a3e8b..0000000 Binary files a/ansible/roles/openwrt/openwrt-image/openwrt-keyring.gpg and /dev/null differ diff --git a/ansible/roles/openwrt/openwrt-image/tasks/fetch.yml b/ansible/roles/openwrt/openwrt-image/tasks/fetch.yml deleted file mode 100644 index f68c87d..0000000 --- a/ansible/roles/openwrt/openwrt-image/tasks/fetch.yml +++ /dev/null @@ -1,52 +0,0 @@ ---- -- name: Create download directory - file: - dest: "{{ openwrt_download_dir }}" - state: directory - -- block: - - name: Generate OpenWrt download URLs - set_fact: - openwrt_url: - https://downloads.openwrt.org/releases/{{ openwrt_release }}/targets/{{ openwrt_arch | mandatory }}/{{ openwrt_target }} - - - name: Download sha256sums - get_url: - url: "{{ openwrt_url }}/sha256sums" - dest: "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256" - - - name: Download sha256sums.asc - get_url: - url: "{{ openwrt_url }}/sha256sums.asc" - dest: "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256.asc" - - - name: Check OpenPGP signature - command: >- - gpg2 --no-options --no-default-keyring --secret-keyring /dev/null - --verify --keyring "{{ role_path }}/openwrt-keyring.gpg" - --trust-model always - "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256.asc" - changed_when: False - - - name: Extract SHA256 hash of the imagebuilder archive - command: grep '{{ openwrt_tarball_name }}' "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256" - register: sha256 - changed_when: False - - - name: Download imagebuilder - get_url: - url: "{{ openwrt_url }}/{{ openwrt_tarball_name }}" - dest: "{{ openwrt_download_dir }}/{{ openwrt_tarball_name }}" - checksum: sha256:{{ sha256.stdout.split(' ') | first }} - - rescue: - - name: Delete downloaded artifacts - file: - path: "{{ item }}" - state: absent - with_items: - - "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256" - - "{{ openwrt_download_dir }}/{{ openwrt_tarball_basename }}.sha256.asc" - - "{{ openwrt_download_dir }}/{{ openwrt_tarball_name }}" - - fail: - msg: Something borked diff --git a/ansible/roles/openwrt/openwrt-image/tasks/main.yml b/ansible/roles/openwrt/openwrt-image/tasks/main.yml deleted file mode 100644 index 1781d9e..0000000 --- a/ansible/roles/openwrt/openwrt-image/tasks/main.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- -- include: fetch.yml - run_once: true - when: openwrt_imgbuilder_tarball is not defined - -- block: - - include: prepare.yml - - - name: Create the output directory for built images - file: - path: "{{ openwrt_output_dir }}" - state: directory - - - set_fact: - openwrt_packages: >- - {{ openwrt_packages_remove | map('regex_replace', '^', '-') | join(' ') }} - {{ openwrt_packages_add | join(' ') }} - {{ openwrt_packages_extra | join(' ') }} - - - name: Build the OpenWrt image - command: >- - make -C {{ openwrt_imgbuilder_dir }}/{{ openwrt_tarball_basename }} image - {% if openwrt_profile is defined %}PROFILE="{{ openwrt_profile }}" {% endif %} - FILES="{{ openwrt_imgbuilder_files }}" - PACKAGES="{{ openwrt_packages }}" - {% if openwrt_extra_name is defined %} EXTRA_IMAGE_NAME="{{ openwrt_extra_name }}" {% endif %} - - - name: Copy newly built OpenWrt image - with_items: "{{ openwrt_output_image_suffixes }}" - copy: - src: "{{ openwrt_imgbuilder_dir }}/{{ openwrt_tarball_basename }}/bin/targets/{{ openwrt_arch }}/{{ openwrt_target }}/{{ openwrt_output_image_name_base }}-{{ item }}" - dest: "{{ openwrt_output_dir }}" - - always: - - name: Delete the temporary build directory - file: - path: "{{ openwrt_imgbuilder_dir }}" - state: absent diff --git a/ansible/roles/openwrt/openwrt-image/tasks/prepare.yml b/ansible/roles/openwrt/openwrt-image/tasks/prepare.yml deleted file mode 100644 index b6b67c5..0000000 --- a/ansible/roles/openwrt/openwrt-image/tasks/prepare.yml +++ /dev/null @@ -1,94 +0,0 @@ ---- -- name: Create temporary build directory - command: mktemp --tmpdir -d openwrt-{{ inventory_hostname }}.XXXXXX - register: tmpdir - -- set_fact: - openwrt_imgbuilder_dir: "{{ tmpdir.stdout }}" - openwrt_imgbuilder_files: "{{ tmpdir.stdout }}/files" - -- name: Create the directories for mixins - file: - path: "{{ item }}" - state: directory - mode: '0755' - with_items: - - "{{ openwrt_download_dir }}/dl/{{ openwrt_arch }}" - - "{{ openwrt_imgbuilder_files }}/etc/config" - - "{{ openwrt_mixin | map('dirname') | map('regex_replace', '^', openwrt_imgbuilder_files) | unique | list }}" - - -- name: Copy mixins in place [1/2] - copy: - src: "{{ item.value.file }}" - dest: "{{ openwrt_imgbuilder_files }}/{{ item.key }}" - mode: "{{ item.value.mode | default('0644') }}" - with_dict: "{{ openwrt_mixin }}" - when: '"file" in item.value' - loop_control: - label: "{{ item.key }}" - -- name: Copy mixins in place [2/2] - copy: - content: "{{ item.value.content }}" - dest: "{{ openwrt_imgbuilder_files }}/{{ item.key }}" - mode: "{{ item.value.mode | default('0644') }}" - with_dict: "{{ openwrt_mixin }}" - when: '"content" in item.value' - loop_control: - label: "{{ item.key }}" - -- name: Generate /etc/fstab - mount: - fstab: "{{ openwrt_imgbuilder_files }}/etc/fstab" - state: present - src: "{{ item.src | default(omit) }}" - path: "{{ item.path | default(omit) }}" - fstype: "{{ item.fstype | default(omit) }}" - opts: "{{ item.opts | default(omit) }}" - boot: "{{ item.boot | default(omit) }}" - dump: "{{ item.dump | default(omit) }}" - passno: "{{ item.passno | default(omit) }}" - when: openwrt_mounts is defined - with_items: "{{ openwrt_mounts }}" - loop_control: - label: "{{ item.path }}" - - -- name: Create UCI configuration files - template: - src: uci.j2 - dest: "{{ openwrt_imgbuilder_files }}/etc/config/{{ item.key }}" - mode: 0644 - trim_blocks: yes -# force: no ## TODO: fail when overwriting a file - with_dict: "{{ openwrt_uci }}" - loop_control: - label: "{{ item.key }}" - -- name: Create /etc/passwd - template: - src: passwd.j2 - dest: "{{ openwrt_imgbuilder_files }}/etc/passwd" - mode: 0644 - trim_blocks: yes - when: openwrt_users is defined - -- name: Create /etc/group - template: - src: group.j2 - dest: "{{ openwrt_imgbuilder_files }}/etc/group" - mode: 0644 - trim_blocks: yes - when: openwrt_groups is defined or openwrt_users is defined - -- unarchive: - copy: False - src: "{{ openwrt_download_dir }}/{{ openwrt_tarball_name }}" - dest: "{{ openwrt_imgbuilder_dir }}" - -- name: Symlink the cache repository - file: - state: link - src: "{{ openwrt_download_dir }}/dl/{{ openwrt_arch }}" - path: "{{ openwrt_imgbuilder_dir }}/{{ openwrt_tarball_basename }}/dl" diff --git a/ansible/roles/openwrt/openwrt-image/templates/group.j2 b/ansible/roles/openwrt/openwrt-image/templates/group.j2 deleted file mode 100644 index cb433b8..0000000 --- a/ansible/roles/openwrt/openwrt-image/templates/group.j2 +++ /dev/null @@ -1,21 +0,0 @@ -{{ ansible_managed | comment }} -root:x:0: -daemon:x:1: -adm:x:4: -mail:x:8: -audio:x:29: -www-data:x:33: -ftp:x:55: -users:x:100: -network:x:101: -{% for name, opt in openwrt_users.items() %} -{% if 'group_id' not in opt %} -{{ name }}:x:{{ opt.id | default(loop.index + 110) }}: -{% endif %} -{% endfor %} -{% if openwrt_groups is defined %} -{% for name, opt in openwrt_groups.items() %} -{{ name }}:x:{{ opt.id | default(loop.index + 200) }}: -{% endfor %} -{% endif %} -nogroup:x:65534: diff --git a/ansible/roles/openwrt/openwrt-image/templates/passwd.j2 b/ansible/roles/openwrt/openwrt-image/templates/passwd.j2 deleted file mode 100644 index 9beaeb6..0000000 --- a/ansible/roles/openwrt/openwrt-image/templates/passwd.j2 +++ /dev/null @@ -1,9 +0,0 @@ -{{ ansible_managed | comment }} -root:x:0:0:root:/root:/bin/ash -daemon:*:1:1:daemon:/var:/bin/false -ftp:*:55:55:ftp:/home/ftp:/bin/false -network:*:101:101:network:/var:/bin/false -{% for name, opt in openwrt_users.items() %} -{{ name }}:*:{{ opt.id | default(loop.index + 110) }}:{{ opt.gid | default(loop.index + 110) }}:{{ name }}:{{ opt.home | default('/nonexistent') }}:{{ opt.shell | default('/bin/false') }} -{% endfor %} -nobody:*:65534:65534:nobody:/var:/bin/false diff --git a/ansible/roles/openwrt/openwrt-image/templates/uci.j2 b/ansible/roles/openwrt/openwrt-image/templates/uci.j2 deleted file mode 100644 index 3cc480b..0000000 --- a/ansible/roles/openwrt/openwrt-image/templates/uci.j2 +++ /dev/null @@ -1,15 +0,0 @@ -{{ ansible_managed | comment }} - -{% for section in item.value %} -config {{ section.name }} -{% for option, value in section.options.items() %} -{% if value is iterable and value is not string %} -{% for v in value %} - list {{ option }} '{{ v }}' -{% endfor %} -{% else %} - option {{ option }} '{{ value }}' -{% endif %} -{% endfor %} - -{% endfor %}