{#- defaults for global core network parameters.
    TODO automatically load enb defaults from JSON schema #}
{%- set mme_defaults = {
  'gtp_addr': '127.0.1.100',
  'ims_addr': '127.0.0.1',
  'ims_bind': '127.0.0.2',
  'qci':  9,
  'pdn_list': {
    'internet': {'name': 'internet'},
    'default': {'name': 'default'},
    'sos': {'name': 'sos'}
  }
} %}
{%- for k,v in mme_defaults|dictsort %}
{%-   do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}
{%- set dns_slave_instance_list = [] %}
{%- set sim_slave_instance_list = [] %}
{%- set fixed_ip = slapparameter_dict.get("fixed_ips", False) %}
{%- for slave in slave_instance_list %}
{%-   set slave_parameters = json_module.loads(slave['_']) %}
{%-   if slave_parameters.get('subdomain', '') != '' %}
{%-     do dns_slave_instance_list.append(slave) %}
{%-   elif slave_parameters.get('imsi', '') != '' %}
{%-     do sim_slave_instance_list.append(slave) %}
{%-   endif %}
{%- endfor %}

{% set part_list = [] -%}
{%- for slave in sim_slave_instance_list %}
{%-   set slave_parameters = json_module.loads(slave['_']) %}
{%    set slave_reference = slave.get('slave_reference', '') %}
{%    set publish_section_title = 'publish-%s' % slave_reference %}
{%    do part_list.append(publish_section_title) %}
[{{ publish_section_title }}]
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ slave_reference }}
info = Your SIM card with IMSI {{ slave_parameters.get('imsi', '') }} has been attached to service ${slap-configuration:instance-title}.
{%-     if fixed_ip %}
ipv4 = ${sim-ip-configuration:{{slave_reference}}}
{%-     endif %}
{%- endfor %}

[sim-ip-configuration]
recipe = slapos.recipe.build
sim-slave-instance-list = {{ dumps(sim_slave_instance_list) }}
ipv4-network = {{ slap_configuration.get('tun-ipv4-network', '') }}
init =
  import netaddr
  import json
  network = netaddr.IPNetwork(options['ipv4-network'])
  slave_list = options['sim-slave-instance-list']
  # if we don't have enough IPv4 addresses in the network, don't force it
  # should we make a promise fail ?
  if len(slave_list) + 2 > network.size:
    for s in slave_list:
      options[s['slave_reference']] = "Too many SIM for the IPv4 network"
  else:
    # calculate the IP addresses of each SIM
    sim_list = []
    first_addr = netaddr.IPAddress(network.first)
    for i, s in enumerate(sorted(slave_list, key=lambda x: json.loads(x['_'])['imsi'])):
      ip = str(first_addr + 2 + i)
      options[s['slave_reference']] = ip
      slave_parameters = json.loads(s['_'])
      slave_parameters['ip'] = ip
      s['_'] = json.dumps(slave_parameters)
  options['sim-with-ip-list'] = slave_list


{%- for slave in dns_slave_instance_list %}
{%-   set slave_parameters = json_module.loads(slave['_']) %}
{%    set slave_reference = slave.get('slave_reference', '') %}
{%    set publish_section_title = 'publish-%s' % slave_reference %}
{%    do part_list.append(publish_section_title) %}
[{{ publish_section_title }}]
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ slave_reference }}
domain = {{ slave_parameters['subdomain'] }}.{{ slapparameter_dict.get('local_domain', '') }}
ip = {{ slave_parameters.get('ip', '') }}
info = DNS entry with has been attached to service ${slap-configuration:instance-title}.
{%- endfor %}

[buildout]
parts =
  directory
  mme-config
  mme-service
  ims-config
  mt-call-config
  ims-service
  monitor-base
  check-interface-up.py
  publish-connection-information
{%- for i in range(slapparameter_dict.get("iperf3", 0)) %}
  iperf-service-{{ i }}
  iperf-{{ i }}-listen-promise
{%- endfor %}
{% if slapparameter_dict.get("local_domain", '') %}
  dnsmasq-service
{% endif %}
{% for part in part_list -%}
{{ '  %s' % part }}
{% endfor %}

extends = {{ monitor_template }}

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

[myslap]
# NOTE we don't query slapos.cookbook:slapconfiguration the second time because
# slapparameter_dict is potentially modified with defaults.
parameter_dict = {{ dumps(slapparameter_dict) }}
configuration = {{ dumps(slap_configuration) }}

[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = {{ slap_connection['computer-id'] }}
partition = {{ slap_connection['partition-id'] }}
url = {{ slap_connection['server-url'] }}
key = {{ slap_connection['key-file'] }}
cert = {{ slap_connection['cert-file'] }}
ue_db_path = ${ue-db-config:output}
{%- if fixed_ip %}
sim_list = ${sim-ip-configuration:sim-with-ip-list}
{%- else %}
sim_list = {{ dumps(sim_slave_instance_list) }}
{%- endif %}

[monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
port = ${monitor-instance-parameter:monitor-httpd-port}
url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}

[monitor-instance-parameter]
monitor-httpd-port = ${monitor-address:port}

[monitor-address]
recipe = slapos.cookbook:free_port
minimum = 8035
maximum = 8055
ip = ${monitor-instance-parameter:monitor-httpd-ipv6}

[directory]
recipe = slapos.cookbook:mkdirectory
software = {{ buildout_directory }}
home = ${buildout:directory}
etc = ${:home}/etc
var = ${:home}/var
bin = ${:home}/bin
tmp = ${:home}/tmp
run = ${:var}/run
script = ${:etc}/run
service = ${:etc}/service
promise = ${:etc}/promise
log = ${:var}/log

[ims-sh-wrapper]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
ims-log = ${directory:log}/ims-output.log
inline =
  #!/bin/sh
  (echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting IMS software..." && echo) >> ${:ims-log};
  tail -c 1M ${:ims-log} > ${:ims-log}.tmp;
  mv ${:ims-log}.tmp ${:ims-log};
  {{ amarisoft['ims_dir'] }}/lteims ${directory:etc}/ims.cfg >> ${:ims-log} 2>> ${:ims-log};

### IMS
[ims-service]
recipe = slapos.cookbook:wrapper
command-line = ${ims-sh-wrapper:output}
wrapper-path = ${directory:service}/ims
mode = 0775
pidfile = ${directory:run}/ims.pid
hash-files =
  ${ims-config:output}
  ${mt-call-config:output}
  ${ue-db-config:output}
  ${ims-sh-wrapper:output}
environment =
  LD_LIBRARY_PATH={{ openssl_location }}/lib:{{ nghttp2_location }}/lib
  AMARISOFT_PATH={{ amarisoft['license_dir'] }}

[mme-sh-wrapper]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
mme-log = ${directory:log}/mme-output.log
inline =
  #!/bin/sh
  sudo -n {{ amarisoft['dir'] }}/init-mme;
  rm -f ${directory:var}/lte_ue.db;
  (echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting MME software..." && echo) >> ${:mme-log};
  tail -c 1M ${:mme-log} > ${:mme-log}.tmp;
  mv ${:mme-log}.tmp ${:mme-log};
  {{ amarisoft['mme_dir'] }}/ltemme ${directory:etc}/mme.cfg >> ${:mme-log} 2>> ${:mme-log};

### MME
[mme-service]
recipe = slapos.cookbook:wrapper
# When the machine shutdowns abruptly, lte_ue is not cleaned up which causes
# amarisoft ltemme to fail. TODO: find a cleaner way to handle this
command-line = ${mme-sh-wrapper:output}
wrapper-path = ${directory:service}/mme
mode = 0775
pidfile = ${directory:run}/mme.pid
hash-files =
  ${mme-config:output}
  ${ue-db-config:output}
  ${mme-sh-wrapper:output}
environment =
  LD_LIBRARY_PATH={{ openssl_location }}/lib:{{ nghttp2_location }}/lib
  AMARISOFT_PATH={{ amarisoft['license_dir'] }}

### EMPTY mme-ifup script
[mme-ifup-empty]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:bin}/mme-ifup-empty
command-line = echo Using interface
mode = 775

{%- for i in range(slapparameter_dict.get("iperf3", 0)) %}
[iperf-service-{{ i }}]
recipe = slapos.cookbook:wrapper
port = {{ 5001 + i }}
ip = ${slap-configuration:tun-ipv4-addr}
command-line = {{ iperf3_location }}/bin/iperf3 --server --interval 1 --port ${:port} --bind ${:ip}
wrapper-path = ${directory:service}/iperf3-{{ i }}
mode = 0775
pidfile = ${directory:run}/iperf3-{{ i }}.pid

[iperf-{{ i }}-listen-promise]
<= monitor-promise-base
promise = check_socket_listening
name = iperf-{{ i }}-port-listening.py
config-host = ${iperf-service-{{ i }}:ip}
config-port = ${iperf-service-{{ i }}:port}
{% endfor %}

[config-base]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
extra-context =
context =
  section directory directory
  section slap_configuration slap-configuration
  key slapparameter_dict myslap:parameter_dict
  raw gtp_addr_v6 {{ my_ipv6 }}
  raw gtp_addr_v4 {{ lan_ipv4 }}
  import  netaddr netaddr
  key ifup_empty mme-ifup-empty:wrapper-path
  ${:extra-context}

[ims-config]
<= config-base
url = {{ ims_template }}
output = ${directory:etc}/ims.cfg

[mt-call-config]
<= config-base
url = {{ mt_call_template }}
output = ${directory:etc}/mt_call_qos.sdp

[ue-db-config]
<= config-base
url = {{ ue_db_template }}
output = ${directory:etc}/ue_db.cfg
context =
  section slap_configuration slap-configuration
  import json_module json

[mme-config]
<= config-base
url = {{ mme_template }}
output = ${directory:etc}/mme.cfg

{% if slapparameter_dict.get("local_domain", '') %}
[dnsmasq-config]
recipe = slapos.recipe.template:jinja2
url = {{dnsmasq_template}}
filename = dnsmasq.cfg
extensions = jinja2.ext.do
output = ${directory:etc}/${:filename}
context =
  import json_module json
  import netaddr netaddr
  section directory directory
  section slap_configuration slap-configuration
  key slapparameter_dict slap-configuration:configuration

[dnsmasq-service]
recipe = slapos.cookbook:wrapper
port = 5353
ip = ${slap-configuration:tun-ipv4-addr}
command-line = {{ dnsmasq_location }}/sbin/dnsmasq --conf-file=${dnsmasq-config:output} -x ${directory:run}/dnsmasq.pid --local-service --keep-in-foreground
wrapper-path = ${directory:service}/dnsmasq
mode = 0775
hash-files =
  ${dnsmasq-config:output}

#[dnsmasq-listen-promise]
#<= monitor-promise-base
#promise = check_socket_listening
#name = dnsmasq-port-listening.py
#config-host = ${dnsmasq-service:ip}
#config-port = ${dnsmasq-service:port}
{% endif %}

[monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %}
monitor-title = {{ slapparameter_dict['name'] | string }}
{% endif %}
{% if slapparameter_dict.get("monitor-password", None) %}
password = {{ slapparameter_dict['monitor-password'] | string }}
{% endif %}

{% set imsi_list = [] -%}
{%- for slave in sim_slave_instance_list %}
{%-   set slave_parameters = json_module.loads(slave['_']) %}
{%-   do imsi_list.append(slave_parameters.imsi) %}
{%- endfor %}

[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
core-network-ipv6 = {{ my_ipv6 }}
core-network-ipv4 = {{ lan_ipv4 }}
core-network-mac = {{ mac }}
{%- if slapparameter_dict.get("iperf3", 0) %}
iperf3-server-ipv4 = ${iperf-service-0:ip}
{%- endif %}
{%- for i in range(1, slapparameter_dict.get("iperf3", 0) + 1) %}
iperf3-server-{{ i - 1 }}-port = ${iperf-service-{{ i - 1 }}:port}
{%- endfor %}
amarisoft-version = {{ amarisoft['version']}}
amarisoft-host-id = {{ amarisoft['lteenb_host_id'] }}
amarisoft-available-versions = {{ amarisoft['version_installed'] }}
license-expiration = {{ amarisoft['ltemme_expiration'] }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
sim-list = {{ imsi_list | join(', ') }}

[macro.promise]
<= monitor-promise-base
name = ${:_buildout_section_name_}

[check-interface-up.py]
<= macro.promise
promise = check_interface_up
config-testing = {{ slapparameter_dict.get("testing", False) }}
{% if not slapparameter_dict.get("testing", False) %}
config-ifname = ${slap-configuration:tun-name}
{% else %}
config-ifname =
{% endif %}
