{%- if instance_parameter_dict['slap-software-type'] == software_type -%}
{% import "caucase" as caucase with context %}
# KeDiFa instance profile
[buildout]
extends =
  {{ software_parameter_dict['profile_common'] }}
  {{ software_parameter_dict['profile_monitor'] }}
  {{ software_parameter_dict['profile_logrotate_base'] }}

parts =
  monitor-base
  directory
  kedifa
  logrotate-entry-kedifa
  promise-kedifa-http-reply
  slave-kedifa-information
  caucased
  caucased-promise
  caucase-updater
  promise-expose-csr-ip-port
  promise-logrotate-setup
  promise-kedifa-auth-ready

[monitor-instance-parameter]
# Note: Workaround for monitor stack, which uses monitor-httpd-port parameter
#       directly, and in our case it can come from the network, thus resulting
#       with need to strip !py!'u'
monitor-httpd-port = {{ instance_parameter_dict['configuration.monitor-httpd-port'] | int }}
password = {{ instance_parameter_dict['configuration.monitor-password'] | string }}

[caucased]
hash-existing-files = ${buildout:directory}/software_release/buildout.cfg

{%  set caucase_host = '[' ~ instance_parameter_dict['ipv6-random'] ~ ']' %}
{%  set caucase_netloc = caucase_host ~ ':' ~ instance_parameter_dict['configuration.caucase_port'] -%}
{%  set caucase_url = 'http://' ~ caucase_netloc -%}
{{  caucase.caucased(
      prefix='caucased',
      buildout_bin_directory=software_parameter_dict['bin_directory'],
      caucased_path='${directory:service}/caucased',
      backup_dir='${directory:backup-caucased}',
      data_dir='${directory:caucased}',
      netloc=caucase_netloc,
      tmp='${directory:tmp}',
      service_auto_approve_count=0,
      user_auto_approve_count=1,
      key_len=2048
)}}

# Create all needed directories
[directory]
recipe = slapos.cookbook:mkdirectory

bin = ${buildout:directory}/bin/
etc = ${buildout:directory}/etc/
srv = ${buildout:directory}/srv/
var = ${buildout:directory}/var/
tmp = ${buildout:directory}/tmp/

backup = ${:srv}/backup
log = ${:var}/log
run = ${:var}/run
service = ${:etc}/service
etc-run = ${:etc}/run

# KeDiFa directories
kedifa = ${:srv}/kedifa
etc-kedifa = ${:etc}/kedifa

# CAUCASE directories
caucased = ${:srv}/caucased
backup-caucased = ${:backup}/caucased

# reservation
reservation = ${:srv}/reservation

# auth ready
auth-ready = ${:var}/auth-ready

# CSR publication
expose-csr = ${:srv}/expose-csr
expose-csr-etc = ${:etc}/expose-csr
expose-csr-var = ${:var}/expose-csr

[kedifa-csr]
recipe = plone.recipe.command
organization = {{ slapparameter_dict['cluster-identification'] }}
organizational_unit = Kedifa Partition
command =
  if [ ! -f ${:template-csr} ] && [ ! -f ${:key} ]  ; then
    /bin/bash -c '{{ software_parameter_dict['openssl'] }} req -new -sha256 \
      -newkey rsa:2048 -nodes -keyout ${:key} \
      -subj "/O=${:organization}/OU=${:organizational_unit}" \
      -reqexts SAN \
      -config <(cat {{ software_parameter_dict['openssl_cnf'] }} \
      <(printf "\n[SAN]\nsubjectAltName=IP:${kedifa-config:ip}")) \
      -out ${:template-csr}'
  fi
update-command = ${:command}
template-csr = ${kedifa-config:template-csr}
key = ${kedifa-config:key}
{#- Can be stopped on error, as does not rely on self provided service #}
stop-on-error = True

{{ caucase.updater(
     prefix='caucase-updater',
     buildout_bin_directory=software_parameter_dict['bin_directory'],
     updater_path='${directory:service}/caucase-updater',
     url=caucase_url,
     data_dir='${directory:srv}/caucase-updater',
     crt_path='${kedifa-config:certificate}',
     ca_path='${kedifa-config:ca-certificate}',
     crl_path='${kedifa-config:crl}',
     key_path='${kedifa-csr:key}',
     on_renew='${kedifa-reloader:output}',
     template_csr='${kedifa-csr:template-csr}'
)}}

[expose-csr-link-csr]
recipe = plone.recipe.command
filename = csr.pem
csr_path = ${directory:expose-csr}/${:filename}
stop-on-error = False
update-command = ${:command}
command =
  ln -sf ${caucase-updater-csr:csr} ${:csr_path}

[expose-csr-certificate]
recipe = plone.recipe.command
certificate = ${directory:expose-csr-etc}/certificate.pem
key = ${directory:expose-csr-etc}/key.pem

{#- Can be stopped on error, as does not rely on self provided service #}
stop-on-error = True
update-command = ${:command}
command =
  if ! [ -f ${:key} ] && ! [ -f ${:certificate} ] ; then
    {{ software_parameter_dict['openssl'] }} req -new -newkey rsa:2048 -sha256 -subj \
      "/O=${kedifa-csr:organization}/OU=${kedifa-csr:organizational_unit}/CN={{ instance_parameter_dict['ipv6-random'] }}" \
      -days 5 -nodes -x509 -keyout ${:key} -out ${:certificate}
  fi

[expose-csr-configuration]
ip = {{ instance_parameter_dict['ipv6-random'] }}
port = 17000
key = ${expose-csr-certificate:key}
certificate = ${expose-csr-certificate:certificate}
error-log = ${directory:log}/expose-csr.log
var = ${directory:expose-csr-var}
pid = ${directory:var}/nginx-expose-csr.pid
root = ${directory:expose-csr}
nginx_mime = {{ software_parameter_dict['nginx_mime'] }}

[expose-csr-template]
recipe = slapos.recipe.template:jinja2
output = ${directory:expose-csr-etc}/nginx.conf
url = {{ software_parameter_dict['template_expose_csr_nginx_conf'] }}
context =
  section configuration expose-csr-configuration

[promise-expose-csr-ip-port]
<= monitor-promise-base
promise = check_socket_listening
name = expose-csr-ip-port-listening.py
config-host = ${expose-csr-configuration:ip}
config-port = ${expose-csr-configuration:port}

[expose-csr]
recipe = slapos.cookbook:wrapper
command-line = {{ software_parameter_dict['nginx'] }}
  -c ${expose-csr-template:output}
url = https://[${expose-csr-configuration:ip}]:${expose-csr-configuration:port}

wrapper-path = ${directory:service}/expose-csr
hash-existing-files = ${buildout:directory}/software_release/buildout.cfg

[expose-csr-certificate-get]
recipe = slapos.recipe.build
certificate-file = ${expose-csr-certificate:certificate}
init =
  import os
  options['certificate'] = ''
  if os.path.exists(options['certificate-file']):
    with open(options['certificate-file'], 'r') as fh:
      options['certificate'] = fh.read()

[jinja2-template-base]
recipe = slapos.recipe.template:jinja2
output = ${buildout:directory}/${:filename}
extra-context =
slapparameter_dict = {{ dumps(slapparameter_dict) }}
slap_software_type = {{ dumps(instance_parameter_dict['slap-software-type']) }}
context =
    import json_module json
    raw profile_common {{ software_parameter_dict['profile_common'] }}
    key slap_software_type :slap_software_type
    key slapparameter_dict :slapparameter_dict
    section directory directory
    ${:extra-context}

[kedifa-config]
ip = {{ instance_parameter_dict['ipv6-random'] }}
port = {{ instance_parameter_dict['configuration.kedifa_port'] }}
db = ${directory:kedifa}/kedifa.sqlite
certificate = ${directory:etc-kedifa}/certificate.pem
key = ${:certificate}
ca-certificate = ${directory:etc-kedifa}/ca-certificate.pem
crl = ${directory:etc-kedifa}/crl.pem
template-csr = ${directory:etc-kedifa}/template-csr.pem
pidfile = ${directory:run}/kedifa.pid
logfile = ${directory:log}/kedifa.log

[kedifa-reloader]
<= jinja2-template-base
url = {{ software_parameter_dict['template_wrapper'] }}
output = ${directory:etc-run}/kedifa-reloader
command =
  kill -HUP `cat ${kedifa-config:pidfile}`
extra-context =
  key content :command

[promise-kedifa-http-reply]
<= monitor-promise-base
promise = check_url_available
name = kedifa-http-reply.py
# Kedifa replies 400 on /, so use it to be sure that Kedifa replied
config-http-code = 400
config-url = https://[${kedifa-config:ip}]:${kedifa-config:port}
config-ca-cert-file = ${kedifa-config:ca-certificate}

[logrotate-entry-kedifa]
<= logrotate-entry-base
name = kedifa
log = ${kedifa-config:logfile}
rotate-num = {{ instance_parameter_dict['configuration.rotate-num'] | int }}
delaycompress =

[kedifa]
recipe = slapos.cookbook:wrapper
command-line = {{ software_parameter_dict['kedifa'] }}
  --ip ${kedifa-config:ip}
  --port ${kedifa-config:port}
  --db ${kedifa-config:db}
  --certificate ${kedifa-config:certificate}
  --ca-certificate ${kedifa-config:ca-certificate}
  --crl ${kedifa-config:crl}
  --pidfile ${kedifa-config:pidfile}
  --logfile ${kedifa-config:logfile}

wrapper-path = ${directory:service}/kedifa
hash-existing-files = ${buildout:directory}/software_release/buildout.cfg

# Publish KeDiFa configuration for upload and download for each slave
{%- set slave_kedifa_information = {} -%}
{%- for slave in slapparameter_dict['slave-list'] -%}
{%-   set slave_reference = slave['slave_reference'] -%}
{%-   set slave_dict = {} -%}
{%-   do slave_dict.__setitem__('key-generate-auth-url', 'https://[${kedifa-config:ip}]:${kedifa-config:port}/${%s-auth-random:passwd}/generateauth' % (slave_reference,)) -%}
{%-   do slave_dict.__setitem__('key-upload-url', 'https://[${kedifa-config:ip}]:${kedifa-config:port}/${%s-auth-random:passwd}?auth=' % (slave_reference,)) -%}
{%-   do slave_dict.__setitem__('key-download-url', 'https://[${kedifa-config:ip}]:${kedifa-config:port}/${%s-auth-random:passwd}' % (slave_reference,)) -%}
{%-   do slave_dict.__setitem__('kedifa-caucase-url', caucase_url ) -%}
{%-   do slave_kedifa_information.__setitem__(slave_reference, slave_dict) %}
[{{ slave_reference }}-auth-random-generate]
recipe = plone.recipe.command
file = ${directory:reservation}/${:_buildout_section_name_}
command =
  [ ! -f ${:file} ] && {{ software_parameter_dict['curl'] }}/bin/curl -s -g -X POST https://[${kedifa-config:ip}]:${kedifa-config:port}/reserve-id --cert ${kedifa-config:certificate} --cacert ${kedifa-config:ca-certificate} > ${:file}.tmp && mv ${:file}.tmp ${:file}
update-command = ${:command}

[{{ slave_reference }}-auth-random]
<= auth-random
file = {{ '${' + slave_reference }}-auth-random-generate:file}

{% endfor %}

[master-auth-random-generate]
recipe = plone.recipe.command
file = ${directory:reservation}/${:_buildout_section_name_}
command =
  [ ! -f ${:file} ] && {{ software_parameter_dict['curl'] }}/bin/curl -s -g -X POST https://[${kedifa-config:ip}]:${kedifa-config:port}/reserve-id --cert ${kedifa-config:certificate} --cacert ${kedifa-config:ca-certificate} > ${:file}.tmp && mv ${:file}.tmp ${:file}
update-command = ${:command}

[cleanup-auth-ready]
# Cleans auth-ready as some slaves can appear and be configured, but then
# become removed before auth-random kicks in
recipe = slapos.recipe.build
directory = ${directory:auth-ready}
init =
  import os
  if os.path.isdir(options['directory']):
    os.system("{{ software_parameter_dict['findutils'] }}/bin/find %s -type f -name *-auth-random -size 0 -delete" % (options['directory'],))

[auth-random]
recipe = slapos.recipe.build
directory = ${cleanup-auth-ready:directory}
auth-ready = ${directory:auth-ready}/${:_buildout_section_name_}
init =
  import os
  options['passwd'] = 'NotReadyYet'
  if os.path.exists(options['file']):
    with open(options['file'], 'r') as fh:
      options['passwd'] = fh.read()
    if os.path.exists(options['auth-ready']):
      os.unlink(options['auth-ready'])
  else:
    # protect against too early init run - wait for directory to be created
    if os.path.isdir(options['directory']):
      with open(options['auth-ready'], 'w') as fh:
        fh.write('')

[master-auth-random]
<= auth-random
file = ${master-auth-random-generate:file}

[slave-kedifa-information]
recipe = slapos.cookbook:publish.serialised
{# sort_keys are important in order to avoid shuffling parameters on each run #}
slave-kedifa-information = {{ json_module.dumps(slave_kedifa_information, sort_keys=True) }}
caucase-url = {{ caucase_url }}
master-key-generate-auth-url = https://[${kedifa-config:ip}]:${kedifa-config:port}/${master-auth-random:passwd}/generateauth
master-key-upload-url = https://[${kedifa-config:ip}]:${kedifa-config:port}/${master-auth-random:passwd}?auth=
master-key-download-url = https://[${kedifa-config:ip}]:${kedifa-config:port}/${master-auth-random:passwd}
kedifa-csr-url = ${expose-csr:url}/${expose-csr-link-csr:filename}
csr-certificate = ${expose-csr-certificate-get:certificate}
monitor-base-url = ${monitor-instance-parameter:monitor-base-url}

[logrotate-setup-validate]
<= jinja2-template-base
url = {{ software_parameter_dict['template_wrapper'] }}
output = ${directory:scripts}/logrotate-setup-validate
command =
  if ${logrotate:wrapper-path} -d > ${:state-file} 2>&1 ; then
    cat /dev/null > ${:state-file}
  fi
extra-context =
  key content :command
state-file = ${directory:run}/logrotate-setup.state

[promise-logrotate-setup]
<= monitor-promise-base
promise = check_file_state
name = ${:_buildout_section_name_}.py
config-filename = ${logrotate-setup-validate:state-file}
config-state = empty

[kedifa-auth-ready]
recipe = plone.recipe.command
output = ${directory:var}/${:_buildout_section_name_}.txt
update-command = ${:command}
command = {{ software_parameter_dict['findutils'] }}/bin/find ${directory:auth-ready} -type f > ${:output}

[promise-kedifa-auth-ready]
<= monitor-promise-base
promise = check_file_state
name = ${:_buildout_section_name_}.py
config-filename = ${kedifa-auth-ready:output}
config-state = empty

{%- endif -%} {# if instance_parameter_dict['slap-software-type'] == software_type #}
