{% set enable_http = slapparameter_dict.get('enable-http-server', 'False').lower() -%}
{% set use_tap = slapparameter_dict.get('use-tap', 'False').lower() -%}
{% set use_nat = slapparameter_dict.get('use-nat', 'True').lower() -%}
{% set name = slapparameter_dict.get('name', 'localhost') -%}
{% set monitor = slapparameter_dict.get('enable-monitor', 'True').lower()  -%}
{% set disable_ansible_promise = slapparameter_dict.get('disable-ansible-promise', 'False').lower() -%}
{% set frontend_software_type = 'default' -%}
{% set extends_list = [] -%}
{% set part_list = [] -%}

{% if monitor -%}
{% do extends_list.append(template_monitor) -%}
{% endif -%}
{% do extends_list.append(logrotate_cfg) -%}

[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
bin = ${buildout:directory}/bin
srv = ${buildout:directory}/srv
var = ${buildout:directory}/var
log = ${:var}/log
scripts = ${:etc}/run
services = ${:etc}/service
promises = ${:etc}/promise
novnc-conf = ${:etc}/novnc
run = ${:var}/run
ca-dir = ${:srv}/ssl
public = ${:srv}/public/
cron-entries = ${:etc}/cron.d
crontabs = ${:etc}/crontabs
cronstamps = ${:etc}/cronstamps

[create-mac]
recipe = slapos.cookbook:generate.mac
storage-path = ${directory:srv}/mac

[create-tap-mac]
recipe = slapos.cookbook:generate.mac
storage-path = ${directory:srv}/tap_mac

[gen-passwd]
recipe = slapos.cookbook:generate.password
storage-path = ${directory:srv}/passwd
bytes = 8

[kvm-controller-parameter-dict]
python-path = {{ python_executable }}
vnc-passwd = ${gen-passwd:passwd}
socket-path = ${directory:var}/qmp_socket

[kvm-parameter-dict]
python-path = {{ python_executable }}
ipv4 = ${slap-network-information:local-ipv4}
ipv6 = ${slap-network-information:global-ipv6}
vnc-ip = ${:ipv4}
vnc-port = 5901

default-cdrom-iso = {{ debian_amd64_netinst_location }}
nbd-host = ${slap-parameter:nbd-host}
nbd-port = ${slap-parameter:nbd-port}
nbd2-host = ${slap-parameter:nbd2-host}
nbd2-port = ${slap-parameter:nbd2-port}

tap-interface = ${slap-network-information:network-interface}

disk-path = ${directory:srv}/virtual.qcow2
disk-size = ${slap-parameter:disk-size}
disk-type = ${slap-parameter:disk-type}


pid-file-path = ${directory:run}/pid_file
socket-path = ${kvm-controller-parameter-dict:socket-path}

smp-count = ${slap-parameter:cpu-count}
smp-options = ${slap-parameter:cpu-options}
ram-size = ${slap-parameter:ram-size}
numa = ${slap-parameter:numa}
mac-address = ${create-mac:mac-address}
tap-mac-address = ${create-tap-mac:mac-address}

use-tap = ${slap-parameter:use-tap}
use-nat = ${slap-parameter:use-nat}
nat-rules = ${slap-parameter:nat-rules}
enable-vhost = ${slap-parameter:enable-vhost}

virtual-hard-drive-url = ${slap-parameter:virtual-hard-drive-url}
virtual-hard-drive-md5sum = ${slap-parameter:virtual-hard-drive-md5sum}
virtual-hard-drive-gzipped = ${slap-parameter:virtual-hard-drive-gzipped}
hard-drive-url-check-certificate = ${slap-parameter:hard-drive-url-check-certificate}

shell-path = {{ dash_executable_location }}
qemu-path =  {{ qemu_executable_location }}
qemu-img-path = {{ qemu_img_executable_location }}

etc-directory = ${directory:etc}
disk-storage-list = 
{% for key, path in storage_dict.items() -%}
{{ '  ' ~ key ~ ' ' ~ path }}
{% endfor -%}
external-disk-number = ${slap-parameter:external-disk-number}
external-disk-size = ${slap-parameter:external-disk-size}
external-disk-format = ${slap-parameter:external-disk-format}

{% if enable_http == 'true' or ( use_tap == 'true' and tap_network_dict.has_key('ipv4') ) -%}
httpd-port = ${slap-parameter:httpd-port}
{% else -%}
httpd-port = 0
{% endif -%}

# Main instance document server info
{% if slapparameter_dict.get('document-host', '') and slapparameter_dict.get('document-port', '') -%}
cluster-doc-host = ${tunnel-cluster-url:ipv4}
cluster-doc-port = ${tunnel-cluster-url:ipv4-port}
{% else -%}
cluster-doc-host = 
cluster-doc-port = 0
{% endif -%}
netcat-binary = {{ netcat_bin }}
language = ${slap-parameter:keyboard-layout-language}

[kvm-run]
recipe = slapos.recipe.template:jinja2
template = {{ template_kvm_run }}
rendered = ${directory:bin}/kvm_raw
mode = 700
context = 
  section parameter_dict kvm-parameter-dict

[kvm-contoller]
recipe = slapos.recipe.template:jinja2
template = {{ template_kvm_controller_run }}
rendered = ${directory:scripts}/kvm_controller
mode = 700
context = 
  section parameter_dict kvm-controller-parameter-dict

[tunnel-6to4-base]
recipe = slapos.cookbook:wrapper
ipv4 = ${slap-network-information:local-ipv4}
ipv6 = ${slap-network-information:global-ipv6}
wrapper-path = ${directory:services}/6tunnel-${:ipv6-port}
command-line = {{ sixtunnel_executable_location }} -6 -4 -d -l ${:ipv6} ${:ipv6-port} ${:ipv4} ${:ipv4-port}

{% if use_nat == 'true' -%}
{%   set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') %}
{%   for port in nat_rule_list.split(' ') -%}
{%     set external_port = 10000 + port|int() -%}
{%     set section_name = '6tunnel-' ~ external_port -%}
[{{ section_name }}]
<= tunnel-6to4-base
ipv4-port = {{ external_port }}
ipv6-port = {{ external_port }}
{%     do part_list.append(section_name) -%}
{%   endfor -%}
{% endif -%}

[kvm-instance]
recipe = slapos.cookbook:wrapper
socket-path = ${kvm-controller-parameter-dict:socket-path}
wrapper-path = ${directory:services}/kvm
command-line = ${kvm-run:rendered}
kvm-controller = ${kvm-contoller:rendered}


[kvm-vnc-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/vnc_promise
hostname = ${kvm-parameter-dict:vnc-ip}
port = ${kvm-parameter-dict:vnc-port}

[kvm-disk-image-corruption-promise]
# Check that disk image is not corrupted
recipe = collective.recipe.template
input = inline:#!/bin/sh
  # Return code 0 is "OK"
  # Return code 3 is "found leaks, but image is OK"
  # http://git.qemu.org/?p=qemu.git;a=blob;f=qemu-img.c;h=4e9a7f5741c9cb863d978225829e68fefcae3947;hb=HEAD#l702
  ${kvm-parameter-dict:qemu-img-path} check ${kvm-parameter-dict:disk-path}
  RETURN_CODE=$?
  if [ $RETURN_CODE -eq 0 ] || [ $RETURN_CODE -eq 3 ]; then
    exit 0
  else
    exit 1
  fi
output = ${directory:promises}/kvm-disk-image-corruption
mode = 700


[novnc-instance]
recipe = slapos.cookbook:novnc
path = ${ca-novnc:executable}
ip = ${slap-network-information:global-ipv6}
port = 6080
vnc-ip = ${kvm-parameter-dict:vnc-ip}
vnc-port = ${kvm-parameter-dict:vnc-port}
novnc-location = {{ novnc_location }}
websockify-path = {{ websockify_executable_location }}
ssl-key-path = ${ca-novnc:key-file}
ssl-cert-path = ${ca-novnc:cert-file}

[websockify-sighandler]
recipe = slapos.cookbook:signalwrapper
wrapper-path = ${directory:services}/websockify
wrapped-path = ${novnc-instance:path}

[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = {{ openssl_executable_location }}
ca-dir = ${directory:ca-dir}
requests-directory = ${cadirectory:requests}
wrapper = ${directory:services}/certificate_authority
ca-private = ${cadirectory:private}
ca-certs = ${cadirectory:certs}
ca-newcerts = ${cadirectory:newcerts}
ca-crl = ${cadirectory:crl}

[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = ${directory:ca-dir}/requests/
private = ${directory:ca-dir}/private/
certs = ${directory:ca-dir}/certs/
newcerts = ${directory:ca-dir}/newcerts/
crl = ${directory:ca-dir}/crl/

[ca-novnc]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = ${directory:novnc-conf}/novnc.key
cert-file = ${directory:novnc-conf}/novnc.crt
executable = ${directory:bin}/novnc
wrapper = ${directory:bin}/websockify

[novnc-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/novnc_promise
hostname = ${novnc-instance:ip}
port = ${novnc-instance:port}


#----------------
#--
#-- Deploy cron.

[cron]
recipe = slapos.cookbook:cron
dcrond-binary = {{ dcron_executable_location }}
cron-entries = ${directory:cron-entries}
crontabs = ${directory:crontabs}
cronstamps = ${directory:cronstamps}
catcher = ${cron-simplelogger:wrapper}
binary = ${directory:services}/crond

[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = ${directory:bin}/cron_simplelogger
log = ${directory:log}/crond.log

#----------------
#--
#-- Deploy frontend.

[request-slave-frontend]
recipe = slapos.cookbook:requestoptional
software-url = ${slap-parameter:frontend-software-url}
server-url = ${slap-connection:server-url}
key-file = ${slap-connection:key-file}
cert-file = ${slap-connection:cert-file}
computer-id = ${slap-connection:computer-id}
partition-id = ${slap-connection:partition-id}
name = ${slap-parameter:frontend-instance-name}
software-type = ${slap-parameter:frontend-software-type}
slave = true
config-host = ${novnc-instance:ip}
config-port = ${novnc-instance:port}
return = url resource port domainname
sla-instance_guid = ${slap-parameter:frontend-instance-guid}

[frontend-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/frontend_promise
url = ${publish-connection-information:url}
dash_path = {{ dash_executable_location }}
curl_path = {{ curl_executable_location }}


{% if enable_http == 'true' %}
[httpd]
recipe = slapos.cookbook:simplehttpserver
host = ${slap-network-information:local-ipv4}
port = ${slap-parameter:httpd-port}
base-path = ${directory:public}
wrapper = ${directory:services}/http-server
log-file = ${directory:log}/httpd.log
use-hash-url = false

[httpd-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/httpd
hostname = ${httpd:host}
port = ${httpd:port}
{% endif %}

{% if monitor == 'true' -%}
[monitor-access-log]
< = monitor-directory-access
source = ${directory:log}

[monitor-access-public]
< = monitor-directory-access
source = ${directory:public}

[monitor-parameters]
port = 8026

{% if slapparameter_dict.get('document-host', '') and slapparameter_dict.get('document-port', '') -%}
# XXX - Set frontend software type to 'custom-personal' by default for cluster instance
{% set frontend_software_type = 'custom-personal' -%}
{% endif -%}

[request-monitor-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Monitor {{ slapparameter_dict.get('name', '') }} Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config-url = ${monitor-parameters:url}
software-type = {{ slapparameter_dict.get('monitor-frontend-software-type', frontend_software_type) }}
return = site_url domain

[monitor-frontend-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/monitor_frontend
url = ${publish-connection-information:monitor_url}
dash_path = {{ dash_executable_location }}
curl_path = {{ curl_executable_location }}
check-secure = 1
{% endif -%}

[publish-connection-information]
recipe = slapos.cookbook:publish
ipv6 = ${slap-network-information:global-ipv6}
backend-url = https://[${novnc-instance:ip}]:${novnc-instance:port}/vnc_auto.html?host=[${novnc-instance:ip}]&port=${novnc-instance:port}&encrypt=1&password=${kvm-controller-parameter-dict:vnc-passwd}
url = ${request-slave-frontend:connection-url}/vnc_auto.html?host=${request-slave-frontend:connection-domainname}&port=${request-slave-frontend:connection-port}&encrypt=1&path=${request-slave-frontend:connection-resource}&password=${kvm-controller-parameter-dict:vnc-passwd}
{% set disk_number = len(storage_dict) -%}
maximum-extra-disk-amount = {{ disk_number }}
{% set iface = 'eth0' -%}
{% if use_nat == 'true' -%}
{%   set iface = 'eth1' -%}
# Publish NAT port mapping status
# XXX: hardcoded value from [slap-parameter]
{%   set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') %}
{%   for port in nat_rule_list.split(' ') -%}
{%     set external_port = 10000 + port|int() -%}
nat-rule-port-{{port}} = ${slap-network-information:global-ipv6} : ${6tunnel-{{external_port}}:ipv6-port}
{%     if slapparameter_dict.get('publish-nat-url', False) -%}
nat-rule-url-{{port}} = [${slap-network-information:global-ipv6}]:${6tunnel-{{external_port}}:ipv6-port}
{%     endif -%}
{%   endfor -%}
{% endif -%}
{% if use_tap == 'true' -%}
tap-ipv4 = ${slap-network-information:tap-ipv4}
{% endif -%}

{% set kvm_http = 'http://${slap-network-information:local-ipv4}:' ~ slapparameter_dict.get('httpd-port', 8081) -%}
{% if enable_http == 'true' %}
{%   if use_nat == 'true' -%}
{%     set kvm_http = 'http://10.0.2.100' -%}
{%   endif %}
{%   if slapparameter_dict.get('authorized-key', '') -%}
7_info = Get the publick key file in your VM with the command: wget {{ kvm_http }}/authorized_keys
{%   endif %}
{% endif %}
{% if monitor -%}
monitor_url = ${request-monitor-frontend:connection-site_url}
monitor_v6_url = ${monitor-parameters:url}
{% endif -%}

{% if use_tap == 'true' and tap_network_dict.has_key('ipv4') -%}
1_info = Use these configurations below to configure interface {{ iface }} in your VM.
2_info = ${network-config:ifconfig}
3_info = ${network-config:route-iface}
4_info = ${network-config:route-network}
5_info = ${network-config:route-default}
{% if enable_http == 'true' %}
6_info = Or run in your VM the command: wget -O- {{ kvm_http }}/netconfig.sh | /bin/sh -
{% endif %}

[network-config]
recipe = plone.recipe.command
path = ${directory:public}/netconfig.sh
ifconfig = ifconfig {{ iface }} ${slap-network-information:tap-ipv4} netmask ${slap-network-information:tap-netmask}
route-iface = route add ${slap-network-information:tap-gateway} dev {{ iface }}
route-network = route add -net ${slap-network-information:tap-network} netmask ${slap-network-information:tap-netmask} gw ${slap-network-information:tap-gateway}
{%   if iface == 'eth0' -%}
route-default = route add default gw ${slap-network-information:tap-gateway}
{%   elif global_ipv4_prefix -%}
route-default = ip route add {{ global_ipv4_prefix }} via ${slap-network-information:tap-gateway} dev {{ iface }} src ${slap-network-information:tap-ipv4}
{% else -%}
route-default =
{%   endif -%}
command = 
  echo "#!/bin/sh" > ${:path}
  echo "" >> ${:path}
  echo "${:ifconfig}" >> ${:path}
  echo "${:route-iface}" >> ${:path}
  echo "${:route-network}" >> ${:path}
  echo "${:route-default}" >> ${:path}
update-command = ${:command}
{% endif -%}

{% macro writefile(section_name, file_path, content, mode='') -%}
{% set data_list =  content.split('\n') -%}
[{{ section_name }}]
recipe = collective.recipe.template
input = inline:
  {{ data_list | join('\n  ') }}
output = {{ file_path }}
mode = {{ mode }}
{% endmacro -%}

# write vm-data into file public/data
{{ writefile('vm-data-content', '${directory:public}/data', slapparameter_dict.get('data-to-vm', ''), '700') }}

# write public key for vms to public/authorized_keys
{{ writefile('get-authorized-key', '${directory:public}/authorized_keys', slapparameter_dict.get('authorized-key', ''), '700') }}

[publish-host-config]
recipe = plone.recipe.command
name = {{ slapparameter_dict.get('name', 'localhost') }}
{% if use_tap == 'true' and tap_network_dict.has_key('ipv4') -%}
local-ipv4 = ${slap-network-information:tap-ipv4}
gateway = ${slap-network-information:tap-gateway}
netmask = ${slap-network-information:tap-network}
network = ${slap-network-information:tap-netmask}
{% else -%}
local-ipv4 = 127.0.0.1
gateway =
netmask =
network =
{% endif -%}
path-host = ${directory:public}/hostname
path-ip = ${directory:public}/ipv4
path-gateway = ${directory:public}/gateway
path-network = ${directory:public}/network
path-netmask = ${directory:public}/netmask
command = 
  rm -f ${:path-host}
  rm -f ${:path-ip}
  rm -f ${:path-gateway}
  rm -f ${:path-network}
  rm -f ${:path-netmask}
  echo "${:name}" > ${:path-host}
  echo "${:local-ipv4}" > ${:path-ip}
  echo "${:gateway}" > ${:path-gateway}
  echo "${:network}" > ${:path-network}
  echo "${:netmask}" > ${:path-netmask}
update-command = ${:command}

# To access documents of main instance (in case of kvm-cluster) through http
[cluster-url-path]
recipe = slapos.recipe.template:jinja2
template = {{ template_content }}
filename = cluster.hash
rendered = ${directory:public}/${:filename}
hash-url = https://10.0.2.101:443/{{ slapparameter_dict.get('document-path', '') }}
context =
    key content_list :hash-url
    raw sep #

# This 6to4 tunnel help to access document url in ipv4
[tunnel-cluster-url]
recipe = slapos.cookbook:ipv4toipv6
ipv6 = {{ slapparameter_dict.get('document-host', '') }}
ipv4 = ${slap-network-information:local-ipv4}
ipv6-port = {{ slapparameter_dict.get('document-port', '') }}
ipv4-port = 16936
shell-path = {{ dash_executable_location }}
6tunnel-path = {{ sixtunnel_executable_location }}
runner-path = ${directory:services}/6tunnel-cluster

[ansible-vm-promise]
recipe = slapos.recipe.template:jinja2
template = {{ ansible_promise_tpl }}
rendered = ${directory:promises}/ansible_{{ name }}
extensions = jinja2.ext.do
context =
  key host slap-network-information:tap-ipv4
  raw logs ${directory:public}/ansible
  raw name {{ name }}


[logrotate-vm-bootstrap]
< = logrotate-entry-base
name = vm-bootstrap
log = ${directory:public}/ansible/vm-bootstrap.log

[logrotate-entry-base]
recipe = slapos.cookbook:logrotate.d
logrotate-entries = ${logrotate:logrotate-entries}
backup = ${logrotate:backup}

[slap-parameter]
# Default values if not specified
frontend-software-type = frontend
frontend-software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/refs/tags/slapos-0.92:/software/kvm/software.cfg
frontend-instance-guid =
frontend-instance-name = VNC Frontend
nbd-port = 1024
nbd-host =
nbd2-port = 1024
nbd2-host =

ram-size = 1024
disk-size = 10
disk-type = virtio

cpu-count = 1
# cpu-option is a string: [cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]
cpu-options = 
# list of numa options separate by space: node,nodeid=1,cpus=9-15 node,nodeid=2,cpus=1,3,7
numa = 

nat-rules = 22 80 443
use-nat = True
use-tap = False
enable-vhost = False

virtual-hard-drive-url =
virtual-hard-drive-md5sum =
virtual-hard-drive-gzipped = False
# if virtual-hard-drive-url use https, then specify if https certificate should be checked or not
hard-drive-url-check-certificate = True

external-disk-number = 0
external-disk-size = 20
external-disk-format = qcow2

# Help to get some configuration files into the vm from http
enable-http-server = False
httpd-port = 8081
# for auto config, the public key file will be available in the VM via url http://10.0.2.100/authorized_key if use-nat = True
authorized-key = 

# send some content which will be accessible to the vm through static url: http://10.0.2.100/data
data-to-vm =

# Change keyboard layout language
keyboard-layout-language = 

#############################
#
# Instanciate kvm (Buildout Section)
#
#############################

# Set Additionals parts

{% if slapparameter_dict.get('document-host', '') %}

{%   do part_list.append('cluster-url-path') -%}
{% endif -%}
{% if enable_http == 'true' %}
{%   do part_list.extend(['httpd', 'httpd-promise', 'publish-host-config']) -%}
{% if slapparameter_dict.get('data-to-vm', '') %}
{%   do part_list.append('vm-data-content') -%}
{% endif -%}
{% if use_tap == 'true' and tap_network_dict.has_key('ipv4') and disable_ansible_promise == 'false' %}
{%   do part_list.extend(['ansible-vm-promise', 'logrotate-vm-bootstrap']) -%}
{% endif -%}
{% if slapparameter_dict.get('authorized-key', '') %}
{%   do part_list.append('get-authorized-key') -%}
{%   endif -%}

{% endif -%}


[buildout]
parts =
  certificate-authority
  publish-connection-information
  kvm-instance
  kvm-contoller
  kvm-vnc-promise
  kvm-disk-image-corruption-promise
  websockify-sighandler
  novnc-promise
#  kvm-monitor
  cron
#  cron-entry-monitor
  frontend-promise
{% if monitor -%}
# monitor parts
  cron-entry-monitor
  cron-entry-rss
  deploy-index
  deploy-status-history-cgi
  deploy-status-cgi
#  deploy-logfile-cgi
#  deploy-resource-consumption-monitoring-cgi
  setup-static-files
  public-symlink
  cgi-httpd-wrapper
  cgi-httpd-graceful-wrapper
  monitor-promise
  monitor-instance-log-access
  monitor-access-log
  monitor-access-public
#  monitor-frontend-promise
{% endif -%}
# Complete parts with sections
  {{ part_list | join('\n  ') }}

extends = 
#  Add extends list
 {{ extends_list | join('\n  ') }}
#  {{ template_httpd_cfg }}

eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true