{#- 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 %}