{% macro section(name) %}{% do part_list.append(name) %}{{ name }}{% endmacro -%}
{% set part_list = [] -%}
{% set init_list = [] -%}
{% set directory_dict = {} -%}

{% set private_tmpfs = slapparameter_dict.get('private-tmpfs') -%}
{% set storage_count = slapparameter_dict.get('storage-count', 1) -%}
{# When mixing different storage types via node specialisation
   ('node!' parameter), it can be convenient to configure all types in the
   common 'node' parameter and then switch between the 2 with 'storage-type'.
   So we must be quite tolerant. -#}
{% if storage_count -%}
{%   if 'mysql' in slapparameter_dict -%}
{%     if 'sqlite' in slapparameter_dict -%}
{%       set storage_type = slapparameter_dict['storage-type'] -%}
{%     else -%}
{%       set storage_type = 'MySQL' -%}
{%     endif -%}
{%   elif 'sqlite' in slapparameter_dict -%}
{%     set storage_type = 'SQLite' -%}
{%   else -%}
{%     set storage_type = slapparameter_dict.get('storage-type') or (
         'MySQL' if mariadb_location is defined else 'SQLite') -%}
{%   endif -%}
{%   do assert(slapparameter_dict.get('storage-type', storage_type) == storage_type) -%}
{% else -%}
{%   set storage_type = '' -%}
{% endif -%}

{% set mysql = storage_type == 'MySQL' -%}
{% if mysql -%}
{%   set extra_dict = slapparameter_dict.get('mysql') or {} -%}

[{{ section('mysqld') }}]
{% if private_tmpfs -%}
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:etc_run}/mariadb
private-tmpfs = {{ private_tmpfs }} ${my-cnf-parameters:tmp-directory}
command-line = ${mariadb-ns:output}
[mariadb-ns]
output = ${directory:bin}/mariadb-ns
{% else -%}
output = ${directory:etc_run}/mariadb
{% endif -%}
recipe = slapos.recipe.template:jinja2
url = {{ template_mysqld_wrapper }}
context =
  key defaults_file my-cnf:output
  key datadir my-cnf-parameters:data-directory

[my-cnf-parameters]
socket = ${directory:var_run}/mariadb.sock
{% if private_tmpfs -%}
data-directory = ${:tmp-directory}/mariadb
{% else -%}
data-directory = ${directory:srv}/mariadb
{% endif -%}
tmp-directory = ${directory:tmp}
pid-file = ${directory:var_run}/mariadb.pid
error-log = ${directory:log}/mariadb_error.log
slow-query-log = ${directory:log}/mariadb_slowquery.log
extra-dict = {{ dumps(extra_dict) }}
init-file = ${init-script:output}
engine = {{ slapparameter_dict.get('engine', '') }}

[my-cnf]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
output = ${directory:etc}/mariadb.cnf
url = {{ template_neo_my_cnf }}
context = section parameter_dict my-cnf-parameters

[binary-wrap-mysql]
recipe = slapos.cookbook:wrapper
command-line = '{{ mariadb_location }}/bin/${:command}' --defaults-file="${my-cnf:output}"
wrapper-path = ${directory:bin}/${:command}
command = mysql

{% elif storage_type == 'SQLite' -%}
{%   set extra_dict = slapparameter_dict.get('sqlite') or {} -%}

{%   if extra_dict.setdefault('cksumvfs', 1) == 0 -%}
{%     do extra_dict.pop('cksumvfs') -%}
{%   endif -%}
{%   if extra_dict.pop('relaxed-writes', False) -%}
{%     do extra_dict.setdefault('synchronous', 'OFF') -%}
{%     do extra_dict.setdefault('journal_mode', 'MEMORY') -%}
{%   endif -%}
{%   set query_string = urllib.urlencode(extra_dict) -%}

[{{ section('sqlite3-cksumvfs') }}]
recipe = slapos.recipe.build
location = ${directory:bin}/sqlite3
source = {{sqlite3_location}}/bin/${:_buildout_section_name_}
install = import os; os.symlink(options['source'], location)

{% else -%}
{% do assert(not storage_count) -%}

{% endif -%}

[{{ section('binary-neolog') }}]
recipe = slapos.cookbook:symbolic.link
target-directory = ${directory:bin}
link-binary = {{ bin_directory }}/neolog

[publish]
recipe = slapos.cookbook:publish.serialised
# TODO: make port a partition parameter
ip = {{ "[%s]" % list(ipv6_set)[0] if ipv6_set else list(ipv4_set)[0] }}
{% set admin = slapparameter_dict.get('admin', 2050) -%}
{% set master = slapparameter_dict.get('master', 2051) -%}
{% if master -%}
port-master = {{ master }}
master = ${:ip}:${:port-master}
{% else -%}
master =
{% endif -%}
{% if admin -%}
port-admin = {{ admin }}
admin = ${:ip}:${:port-admin}
{%-   if 'monitor-passwd' in slapparameter_dict %}
monitor-base-url = ${monitor-publish-parameters:monitor-base-url}
{%-   endif %}
{%- else %}
admin =
{%- endif %}

{#- Hack to deploy SSL certs via instance parameters #}
{%- for name, pem in zip(('ca.crt', 'neo.crt', 'neo.key'),
                        slapparameter_dict['ssl']) %}
{%-   if pem %}

[{{ section(name) }}]
recipe = slapos.recipe.template:jinja2
output = ${directory:etc}/{{name}}
inline =
  {{'{{'}}pem}}
context = key pem :pem
pem = {{dumps(pem)}}
{%-   endif %}
{%- endfor %}
{#- endhack #}

[neo-storage]
recipe = slapos.cookbook:neoppod.storage
binary = {{ bin_directory }}/neostorage
ip = ${publish:ip}
ssl = {{ dumps(bool(slapparameter_dict['ssl'])) }}
cluster = {{ dumps(slapparameter_dict['cluster']) }}
masters = {{ dumps(slapparameter_dict['masters']) }}
database-adapter = {{ storage_type }}
wait-database = -1
{%- if mysql %}
engine = ${my-cnf-parameters:engine}
{%- else %}
environment =
  PATH={{sqlite3_location}}/bin
{%- endif %}
extra-options =
{%- if slapparameter_dict.get('data-deduplication') %}
  --dedup
{%- endif %}
{%- if slapparameter_dict.get('disable-drop-partitions') %}
  --disable-drop-partitions
{%- endif %}
{%- if slapparameter_dict.get('disable-pack') %}
  --disable-pack
{%- endif %}

{% for i in range(storage_count) -%}
{%   set storage_id = 'neo-storage-' ~ i -%}
[{{ section(storage_id) }}]
< = neo-storage
wrapper = ${directory:etc_run}/{{ 'neostorage-' ~ i }}
logfile = ${directory:log}/{{ 'neostorage-' ~ i }}.log
{%- if mysql %}
{%-   do init_list.append('CREATE DATABASE IF NOT EXISTS neo' ~  i ~ ';') %}
database-parameters = root@neo{{ i }}${my-cnf-parameters:socket}
{%- else %}
{%-   if private_tmpfs %}
private-tmpfs = {{ private_tmpfs }} ${directory:tmp}
{%-     set path = '${directory:tmp}/db.sqlite' %}
{%-   else %}
{%-     set path = '${directory:db-' ~ i ~ '}/db.sqlite' %}
{%-     do directory_dict.__setitem__('db-' ~ i, '${:srv}/' + storage_id) %}
{%-   endif %}
{%-   if query_string %}
database-parameters = file:{{ path }}?{{ query_string }}
{%-   else %}
database-parameters = {{ path }}
{%-   endif -%}
{%- endif %}

[{{ section('logrotate-storage-' ~ i) }}]
< = logrotate-entry-base
name = {{ storage_id }}
log = {{ '${' +  storage_id + ':logfile}' }}
post = {{ bin_directory }}/slapos-kill -s RTMIN+1 -- {{ bin_directory }}/neostorage -l ${:log}

{% endfor -%}

{% set reflink = slapparameter_dict.get('reflink') -%}
{% if reflink -%}
{%   set zurl = 'neo://%s@%s' % (slapparameter_dict['cluster'], slapparameter_dict['masters'].replace(' ', ',')) -%}
{%   if slapparameter_dict['ssl'] -%}
{%     set zurl = zurl + '?ca=${ca.crt:output}&cert=${neo.crt:output}&key=${neo.key:output}' -%}
{%   endif -%}
[{{ section('reflink') }}]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:etc_run}/reflink
{%   set args = [] -%}
{%   if 'commit-interval' in reflink -%}
{%     do args.extend(('-i', str(reflink['commit-interval']))) -%}
{%   endif -%}
{%   if 'period' in reflink -%}
{%     do args.extend(('-p', str(reflink['period']))) -%}
{%   endif -%}
{%   if 'no-gc' in reflink -%}
{%     do args.append('--no-gc') -%}
{%   endif -%}
command-line = {{ bin_directory }}/reflink -v {{ zurl }} run {{ ' '.join(args) }} {{ reflink['zurl'] }}
{%   if reflink['zurl'].startswith('neos://') -%}
environment =
  NEO_CA=${reflink-ca:output}
  NEO_CERT=${reflink-cert:output}
  NEO_KEY=${reflink-key:output}

{%     for x in 'ca', 'cert', 'key' -%}
[reflink-{{x}}]
recipe = slapos.recipe.template:jinja2
output = ${directory:etc}/${:_buildout_section_name_}.pem
inline =
  {{'{{'}}pem}}
context = key pem :pem
pem = {{dumps(reflink['_'+x])}}
{%     endfor -%}
{%   endif -%}
{% endif -%}

{% if mysql -%}
[init-script]
recipe = slapos.recipe.template
# XXX: is there a better location ?
output = ${directory:etc}/mariadb_initial_setup.sql
inline =
  {{ init_list | join('\n\t') }}

[{{ section('logrotate-mysql') }}]
< = logrotate-entry-base
name = mariadb
log = ${my-cnf-parameters:error-log} ${my-cnf-parameters:slow-query-log}
post = ${binary-wrap-mysql:command-line} -e "FLUSH LOGS"

{% if runTestSuite_in is defined -%}
# bin/runTestSuite to run NEO tests

[runTestSuite-parameters]
bin_directory = {{ bin_directory }}
prepend_path = {{ mariadb_location }}/bin
test_binding_list = {{ dumps(slapparameter_dict.get('test-binding-list', (
  'MySQLdb', 'PyMySQL', 'SQLite',
))) }}

[{{ section('runTestSuite') }}]
{%-  if private_tmpfs %}
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:bin}/${:_buildout_section_name_}
private-tmpfs = {{ private_tmpfs }} ${directory:tmp}
command-line = ${runTestSuite-ns:output}

[runTestSuite-ns]
{%-  endif %}
recipe = slapos.recipe.template:jinja2
output = ${directory:bin}/${:_buildout_section_name_}
url = {{ runTestSuite_in }}
context =
    section directory         directory
    section my_cnf_parameters my-cnf-parameters
    section parameters        runTestSuite-parameters
{%-  if private_tmpfs %}
    key     datadir           my-cnf-parameters:data-directory
    key     results_directory directory:results

{%-    do directory_dict.__setitem__('results', '${directory:srv}/tests') %}
{%-  endif %}
{%- endif %}

{%- endif %}

[directory]
recipe = slapos.cookbook:mkdirectory
bin = ${buildout:directory}/bin
etc = ${buildout:directory}/etc
var = ${buildout:directory}/var
etc_run =  ${:etc}/run
var_run =  ${:var}/run
log = ${buildout:directory}/var/log
tmp = ${buildout:directory}/tmp
srv = ${buildout:directory}/srv
{%- for k, v in directory_dict.iteritems() %}
{{ k }} = {{ v }}
{%- endfor %}

[buildout]
extends =
  {{ logrotate_cfg }}
{%- if admin %}
  {{ admin_cfg }}
{%- endif %}
{%- if master %}
  {{ master_cfg }}
{%- endif %}
parts +=
  {{ '\n  '.join(part_list) }}
