{#- Package ru/lopcomm/libinstance provides instance code for handling Lopcomm ORAN Radio Units. #}

{%- macro buildout_ru(ru_ref, ru)  %}

{#-  indicate whether RU is listening for netconf #}

{%- if not testing  %}
{{ promise('%s-netconf-socket' % ru_ref) }}
promise = check_socket_listening
config-host = ${vtap.{{ru.cpri_link._tap}}:gateway}
config-port = 830
{%- endif %}


{#-  push firmware to RU #}

[{{ru_ref}}-software-template]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-software
log-output = ${:_logbase}.log
software-reply-json-log-output = ${:_logbase}-reply.json.log
remote-file-path = sftp://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port}{{ru_lopcomm_firmware_path}}
is_firmware_updated = ${directory:etc}/{{ru_ref}}.is_firmware_updated
context =
  section directory directory
  section vtap vtap.{{ ru.cpri_link._tap }}
  key slapparameter_dict myslap:parameter_dict
  key log_file :log-output
  key software_reply_json_log_file :software-reply-json-log-output
  key remote_file_path :remote-file-path
  raw testing {{ testing }}
  raw python_path {{ buildout_directory}}/bin/pythonwitheggs
  raw buildout_directory_path {{ buildout_directory }}
  key is_firmware_updated :is_firmware_updated
  raw firmware_name {{ru_lopcomm_firmware_filename}}
  import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_software_template }}
output = ${directory:script}/{{ru_ref}}-software.py

{%- if not testing  %}
{{ promise('%s-firmware' % ru_ref) }}
promise = check_command_execute
config-command = [ -f ${ {{-ru_ref}}-software-template:is_firmware_updated} ]
{%- endif %}


{#-  push config to RU #}

{%   if ru.get("cu_config_link", None) %}
[{{ ru_ref }}-cu-config-dl }}]
recipe = slapos.recipe.build:download
url = {{ ru.cu_config_link }}
version = {{ ru.get("cu_config_version") }}
offline = false
{%   endif %}

[{{ru_ref}}-cu-config]
<= config-base
{% if ru.get("cu_config_link", None) %}
url = ${ {{-ru_ref}}-cu-config-dl:target}
{% else %}
url = {{ ru_lopcomm_cu_config_template }}
{% endif %}
output = ${directory:etc}/{{ru_ref}}-cu_config.xml
extra-context =
  json ru    {{ ru | tojson }}

[{{ru_ref}}-config-template]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
log-output = ${directory:var}/log/{{ru_ref}}-config.log
context =
  section directory directory
  section vtap vtap.{{ ru.cpri_link._tap }}
  key log_file :log-output
  raw testing {{ testing }}
  raw python_path {{ buildout_directory}}/bin/pythonwitheggs
  raw buildout_directory_path {{ buildout_directory }}
  raw CreateProcessingEle_template {{ ru_lopcomm_CreateProcessingEle_template }}
  key cu_config_template {{ru_ref}}-cu-config:output
  import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_config_template }}
output = ${directory:script}/{{ru_ref}}-config.py

{{ promise('%s-config-log' % ru_ref) }}
promise = check_lopcomm_config_log
config-config-log = ${ {{- ru_ref}}-config-template:log-output}


{#-  handle notifications from RU + keep on touching RU watchdog #}

[{{ru_ref}}-stats-template]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}
log-output = ${:_logbase}-stats.log
json-log-output = ${:_logbase}-stats.json.log
cfg-json-log-output = ${:_logbase}-config.json.log
supervision-json-log-output = ${:_logbase}-supervision.json.log
ncsession-json-log-output = ${:_logbase}-ncsession.json.log
software-json-log-output = ${:_logbase}-software.json.log
supervision-reply-json-log-output = ${:_logbase}-supervision-reply.json.log
is_netconf_connected = ${directory:etc}/{{ru_ref}}.is_netconf_connected
context =
  section directory directory
  section vtap vtap.{{ ru.cpri_link._tap }}
  key slapparameter_dict myslap:parameter_dict
  key log_file :log-output
  key json_log_file :json-log-output
  key cfg_json_log_file :cfg-json-log-output
  key supervision_json_log_file :supervision-json-log-output
  key supervision_reply_json_log_file :supervision-reply-json-log-output
  key is_netconf_connected :is_netconf_connected
  key ncsession_json_log_file :ncsession-json-log-output
  key software_json_log_file :software-json-log-output
  raw testing {{ testing }}
  raw python_path {{ buildout_directory}}/bin/pythonwitheggs
  raw buildout_directory_path {{ buildout_directory }}
  import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_stats_template }}
output = ${directory:bin}/{{ru_ref}}-stats.py

{{ part('%s-stats-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-stats-template:output}
wrapper-path = ${directory:service}/{{ru_ref}}-stats
mode = 0775
hash-files =
  ${:command-line}

{%- if not testing  %}
{{ promise('%s-netconf-connection' % ru_ref) }}
promise = check_command_execute
config-command = [ -f ${ {{-ru_ref}}-stats-template:is_netconf_connected} ]
{%- endif %}

{{ promise('%s-vswr' % ru_ref) }}
promise = check_lopcomm_vswr
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output}

{{ promise('%s-rssi' % ru_ref) }}
promise = check_lopcomm_rssi
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output}

{{ promise('%s-pa-current' % ru_ref) }}
promise = check_lopcomm_pa_current
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output}

{{ promise('%s-pa-output-power' % ru_ref) }}
promise = check_lopcomm_pa_output_power
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output}

{{ promise('%s-sync' % ru_ref) }}
promise = check_lopcomm_sync
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output}

{{ promise('%s-lof' % ru_ref) }}
promise = check_lopcomm_lof
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output}

{{ promise('%s-stats-log' % ru_ref) }}
promise = check_lopcomm_stats_log
config-stats-log = ${ {{- ru_ref}}-stats-template:log-output}


{#-  reset RU periodically #}

{%- if ru.get("reset_schedule") %}

[{{ru_ref}}-reset-info-template]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset-info
log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log
context =
  section vtap vtap.{{ ru.cpri_link._tap }}
  key log_file :log-output
  key json_log_file :json-log-output
  raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
  raw testing {{ testing }}
  raw python_path {{ buildout_directory}}/bin/pythonwitheggs
  import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_reset_info_template }}
output = ${directory:bin}/{{ru_ref}}-reset-info.py

[{{ru_ref}}-reset-template]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset
log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log
context =
  section vtap vtap.{{ ru.cpri_link._tap }}
  key log_file :log-output
  raw python_path {{ buildout_directory}}/bin/pythonwitheggs
  raw buildout_directory_path {{ buildout_directory }}
  import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_reset_template }}
output = ${directory:etc}/{{ru_ref}}-reset.py

{{ part('%s-reset-cron' % ru_ref) }}
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = {{ru_ref}}-reset
frequency = {{ ru.reset_schedule }}
command = {{ buildout_directory}}/bin/pythonwitheggs ${ {{- ru_ref}}-reset-template:output}

{{ part('%s-reset-info-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-reset-info-template:output}
wrapper-path = ${directory:service}/{{ru_ref}}-reset-info
mode = 0775
hash-files =
  ${:command-line}

{%- endif %}


{#- amend published information with Lopcomm-specific bits
    TODO make it per-RU #}
[publish-connection-information]
ssh-command = ssh ${user-info:pw-name}@${sshd-service:ipv6} -p ${sshd-service:port}
ssh-url = ssh://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port}
ru-firmware = {{ru_lopcomm_firmware_filename}}
ru-ipv6 = ${slap-configuration:tap-ipv6-gateway}

{%- endmacro  %}


{%- macro buildout()  %}

# deploy openssh-server for software upgrade
#
# FIXME user-authorized-key is global for eNB. Either we need to put SSH server
# to be also global, or unroll an SSH server via paramiko inside
# ru/lopcomm/software.py just to handle software upgrades there.
[user-info]
recipe = slapos.cookbook:userinfo

[sshd-port]
recipe = slapos.cookbook:free_port
minimum = 22222
maximum = 22231
ip = {{my_ipv6}}

[sshd-config]
recipe = slapos.recipe.template:jinja2
output = ${directory:etc}/sshd.conf
path_pid = ${directory:run}/sshd.pid
inline =
  PidFile ${:path_pid}
  Port ${sshd-port:port}
  ListenAddress ${sshd-port:ip}
  Protocol 2
  HostKey ${sshd-ssh-host-rsa-key:output}
  HostKey ${sshd-ssh-host-ecdsa-key:output}
  PasswordAuthentication no
  PubkeyAuthentication yes
  HostKeyAlgorithms ssh-rsa,ssh-dss,rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521
  AuthorizedKeysFile ${buildout:directory}/.ssh/authorized_keys
  Subsystem sftp {{ openssh_location }}/libexec/sftp-server

{{ part('sshd-service') }}
recipe = slapos.cookbook:wrapper
command-line = {{ openssh_location }}/sbin/sshd -D -e -f ${sshd-config:output}
wrapper-path = ${directory:service}/sshd
hash-files = ${sshd-config:output}
environment =
  HOME=${directory:home}
ipv6 = ${sshd-port:ip}
port = ${sshd-port:port}

{{ part('sshd-add-authorized-key') }}
recipe = slapos.cookbook:dropbear.add_authorized_key
home = ${buildout:directory}
key = {{ slapparameter_dict.get("user-authorized-key", '') }}

[sshd-ssh-keygen-base]
recipe = plone.recipe.command
output = ${directory:etc}/${:_buildout_section_name_}
command = {{ openssh_output_keygen }} -f ${:output} -N '' ${:extra-args}

[sshd-ssh-host-rsa-key]
<=sshd-ssh-keygen-base
extra-args=-t rsa
[sshd-ssh-host-ecdsa-key]
<=sshd-ssh-keygen-base
extra-args=-t ecdsa -b 521

{{ promise('sshd') }}
promise = check_socket_listening
config-host = ${sshd-service:ipv6}
config-port = ${sshd-service:port}

{%- endmacro  %}