Commit f6a03ec2 authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼

Update Release Candidate

parents 5adba18a 958b275d
...@@ -7,5 +7,5 @@ parts = ...@@ -7,5 +7,5 @@ parts =
[depot_tools] [depot_tools]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = https://chromium.googlesource.com/chromium/tools/depot_tools.git repository = https://chromium.googlesource.com/chromium/tools/depot_tools.git
revision = e023d4482012d89690f6a483e877eceb47c4501e revision = eb48a6ac0fa5835353ddd137ac35f44eee011716
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
...@@ -45,9 +45,9 @@ gclient-location = ${buildout:parts-directory}/${:_buildout_section_name_} ...@@ -45,9 +45,9 @@ gclient-location = ${buildout:parts-directory}/${:_buildout_section_name_}
# called "src". # called "src".
name = src name = src
# 96.0.4664.129 version is the latest stable version in December 2021.
# Note that we need a version compiling without python2 # 114.0.5735.340 version is the latest stable version in November 2023.
version = 96.0.4664.129 version = 114.0.5735.340
[headless-chromium] [headless-chromium]
......
...@@ -5,7 +5,7 @@ exposes an interface to connect to it remotely from another browser. ...@@ -5,7 +5,7 @@ exposes an interface to connect to it remotely from another browser.
After deployment, the instance is configured like this: After deployment, the instance is configured like this:
``` ```
Caddy frontend Rapid CDN Frontend
| |
(HTTPS, IPv6) (HTTPS, IPv6)
| |
...@@ -27,7 +27,7 @@ The following instance parameters can be configured: ...@@ -27,7 +27,7 @@ The following instance parameters can be configured:
- nginx-proxy-port: Port for Ningx proxy to listen on. - nginx-proxy-port: Port for Ningx proxy to listen on.
- monitor-httpd-port: Port for monitor. - monitor-httpd-port: Port for monitor.
- incognito: Force Incognito mode - incognito: Force Incognito mode
- window-size: Initial windo size - window-size: Initial window size
- block-new-web-contents: Block new web contents - block-new-web-contents: Block new web contents
See `instance-headless-chromium-input-schema.json` for default values. See `instance-headless-chromium-input-schema.json` for default values.
[template-cfg] [template-cfg]
filename = instance.cfg.in filename = instance.cfg.in
md5sum = 6315598b2c7c19f9e2d9cdf090492e2c md5sum = c6cdcee1e16dd4bd3bc462d286dcb999
[instance-headless-chromium] [instance-headless-chromium]
_update_hash_filename_ = instance-headless-chromium.cfg.in _update_hash_filename_ = instance-headless-chromium.cfg.in
md5sum = feaef60353c94e02d38cfec66f0eb861 md5sum = 8a7e024569d92b0992f40ddac232cff5
[template-nginx-conf] [template-nginx-conf]
_update_hash_filename_ = templates/nginx.conf.in _update_hash_filename_ = templates/nginx.conf.in
md5sum = 1f35f91fa7e490cd1e2194264a8a6ed8 md5sum = 6ba793ce45bc67882ab2eea319984e3f
[template-mime-types] [template-mime-types]
_update_hash_filename_ = templates/mime_types.in _update_hash_filename_ = templates/mime_types.in
md5sum = 4ef94a7b458d885cd79ba0b930a5727e md5sum = 4ef94a7b458d885cd79ba0b930a5727e
[template-index-html]
_update_hash_filename_ = templates/index.html
md5sum = 9314b30f97535a4e516f4ea0c2029ab0
...@@ -9,6 +9,8 @@ log = ${:home}/log ...@@ -9,6 +9,8 @@ log = ${:home}/log
etc = ${:home}/etc etc = ${:home}/etc
ssl = ${:etc}/ssl ssl = ${:etc}/ssl
service = ${:etc}/service service = ${:etc}/service
srv = ${:home}/srv
nginx-root = ${:srv}/nginx-root
# Options for instance configuration. See README.md for a list of # Options for instance configuration. See README.md for a list of
# options that can be configured when requesting an instance. # options that can be configured when requesting an instance.
...@@ -17,9 +19,7 @@ ipv4 = {{ partition_ipv4 }} ...@@ -17,9 +19,7 @@ ipv4 = {{ partition_ipv4 }}
ipv6 = {{ partition_ipv6 }} ipv6 = {{ partition_ipv6 }}
remote-debugging-port = {{ parameter_dict['remote-debugging-port'] }} remote-debugging-port = {{ parameter_dict['remote-debugging-port'] }}
target-url = {{ parameter_dict['target-url'] }} target-url = {{ parameter_dict['target-url'] }}
incognito = {{ parameter_dict['incognito'] }}
window-size = {{ parameter_dict['window-size'] }} window-size = {{ parameter_dict['window-size'] }}
block-new-web-contents = {{ parameter_dict['block-new-web-contents'] }}
remote-debugging-address = ${:ipv4}:${:remote-debugging-port} remote-debugging-address = ${:ipv4}:${:remote-debugging-port}
devtools-frontend-root = {{ parameter_list['devtools-frontend'] }} devtools-frontend-root = {{ parameter_list['devtools-frontend'] }}
...@@ -34,7 +34,8 @@ nginx-htpasswd-file = ${directory:etc}/.htpasswd ...@@ -34,7 +34,8 @@ nginx-htpasswd-file = ${directory:etc}/.htpasswd
nginx-key-file = ${frontend-instance-certificate:key-file} nginx-key-file = ${frontend-instance-certificate:key-file}
nginx-cert-file = ${frontend-instance-certificate:cert-file} nginx-cert-file = ${frontend-instance-certificate:cert-file}
nginx-mime-types = ${directory:etc}/mime-types nginx-mime-types = ${directory:etc}/mime-types
nginx-root = ${directory:nginx-root}
nginx-index-html = ${:nginx-root}/index.html
# Create a wrapper script in /bin/chromium for the headless shell # Create a wrapper script in /bin/chromium for the headless shell
# executable. # executable.
...@@ -45,10 +46,11 @@ command-line = ...@@ -45,10 +46,11 @@ command-line =
{{ parameter_list['chromium-wrapper'] }} {{ parameter_list['chromium-wrapper'] }}
--remote-debugging-address=${headless-chromium:ipv4} --remote-debugging-address=${headless-chromium:ipv4}
--remote-debugging-port=${headless-chromium:remote-debugging-port} --remote-debugging-port=${headless-chromium:remote-debugging-port}
--remote-allow-origins=*
--user-data-dir=${directory:tmp} --user-data-dir=${directory:tmp}
--window-size="${headless-chromium:window-size}" --window-size="${headless-chromium:window-size}"
{% if parameter_dict['incognito'] %}--incognito{% endif -%} {% if parameter_dict['incognito'] %} --incognito{% endif -%}
{% if parameter_dict['block-new-web-contents'] %}--block-new-web-contents{% endif -%} {% if parameter_dict['block-new-web-contents'] %} --block-new-web-contents{% endif -%}
{{ '\n "${headless-chromium:target-url}"' }} {{ '\n "${headless-chromium:target-url}"' }}
environment = environment =
FONTCONFIG_FILE=${font-config:output} FONTCONFIG_FILE=${font-config:output}
...@@ -74,6 +76,11 @@ recipe = slapos.recipe.template ...@@ -74,6 +76,11 @@ recipe = slapos.recipe.template
url = {{ parameter_list['template-mime-types'] }} url = {{ parameter_list['template-mime-types'] }}
output = ${headless-chromium:nginx-mime-types} output = ${headless-chromium:nginx-mime-types}
[nginx-index-html]
recipe = slapos.recipe.template
url = {{ parameter_list['template-index-html'] }}
output = ${headless-chromium:nginx-index-html}
[nginx-launcher] [nginx-launcher]
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = command-line =
...@@ -195,6 +202,7 @@ parts = ...@@ -195,6 +202,7 @@ parts =
generate-passwd-file generate-passwd-file
nginx-config nginx-config
nginx-mime-types nginx-mime-types
nginx-index-html
nginx-launcher nginx-launcher
logrotate-entry-nginx logrotate-entry-nginx
remote-debugging-frontend remote-debugging-frontend
......
...@@ -17,6 +17,7 @@ template-nginx-config = {{ template_nginx_config_target }} ...@@ -17,6 +17,7 @@ template-nginx-config = {{ template_nginx_config_target }}
template-fonts-conf = {{ template_fonts_conf_target }} template-fonts-conf = {{ template_fonts_conf_target }}
template-monitor = {{ template_monitor }} template-monitor = {{ template_monitor }}
template-mime-types = {{ template_mime_types_target }} template-mime-types = {{ template_mime_types_target }}
template-index-html = {{ template_index_html_target }}
[instance-headless-chromium] [instance-headless-chromium]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
......
...@@ -27,6 +27,7 @@ context = ...@@ -27,6 +27,7 @@ context =
key devtools_frontend headless-chromium:devtools-frontend key devtools_frontend headless-chromium:devtools-frontend
key template_nginx_config_target template-nginx-conf:target key template_nginx_config_target template-nginx-conf:target
key template_mime_types_target template-mime-types:target key template_mime_types_target template-mime-types:target
key template_index_html_target template-index-html:target
key template_fonts_conf_target template-fonts-conf:output key template_fonts_conf_target template-fonts-conf:output
key template_instance_headless_chromium_target instance-headless-chromium:target key template_instance_headless_chromium_target instance-headless-chromium:target
key template_monitor monitor2-template:output key template_monitor monitor2-template:output
...@@ -43,3 +44,6 @@ url = ${:_profile_base_location_}/${:_update_hash_filename_} ...@@ -43,3 +44,6 @@ url = ${:_profile_base_location_}/${:_update_hash_filename_}
[template-mime-types] [template-mime-types]
<= download-base <= download-base
[template-index-html]
<= download-base
<script>
fetch("/json")
.then(r => r.json())
.then(pages => window.location.replace(new URL(pages[0].devtoolsFrontendUrl, window.location)))
</script>
\ No newline at end of file
...@@ -12,6 +12,7 @@ http { ...@@ -12,6 +12,7 @@ http {
include {{ param_headless_chromium['nginx-mime-types'] }}; include {{ param_headless_chromium['nginx-mime-types'] }};
default_type application/octet-stream; default_type application/octet-stream;
root {{ param_headless_chromium['nginx-root'] }};
server { server {
listen {{ param_headless_chromium['proxy-address'] }} ssl; listen {{ param_headless_chromium['proxy-address'] }} ssl;
...@@ -30,8 +31,13 @@ http { ...@@ -30,8 +31,13 @@ http {
uwsgi_temp_path {{ param_headless_chromium['nginx-temp-path'] }}; uwsgi_temp_path {{ param_headless_chromium['nginx-temp-path'] }};
scgi_temp_path {{ param_headless_chromium['nginx-temp-path'] }}; scgi_temp_path {{ param_headless_chromium['nginx-temp-path'] }};
# All websocket connections are served from /devtools. # A minimal page to bootstrap the DevTools frontend
location /devtools { location = / {
try_files $uri $uri/index.html =404;
}
# All websocket connections are served from /devtools/page.
location /devtools/page {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Host {{ param_headless_chromium['remote-debugging-address'] }}; proxy_set_header Host {{ param_headless_chromium['remote-debugging-address'] }};
proxy_pass http://{{ param_headless_chromium['remote-debugging-address'] }}; proxy_pass http://{{ param_headless_chromium['remote-debugging-address'] }};
...@@ -39,9 +45,9 @@ http { ...@@ -39,9 +45,9 @@ http {
proxy_set_header Connection "Upgrade"; proxy_set_header Connection "Upgrade";
} }
# The DevTools frontend is served from /serve_file/@{version_hash}. # Static content from DevTools frontend
location ~ "^\/serve_file\/@[0-9a-f]{5,40}\/(.*)" { location /devtools {
alias {{ param_headless_chromium['devtools-frontend-root'] }}/$1; alias {{ param_headless_chromium['devtools-frontend-root'] }};
} }
location / { location / {
...@@ -59,11 +65,11 @@ http { ...@@ -59,11 +65,11 @@ http {
# frontend CDN URL. The tricky thing is that the frontend URL is # frontend CDN URL. The tricky thing is that the frontend URL is
# not available yet when this file is built; what we do instead is # not available yet when this file is built; what we do instead is
# use the given Host header. # use the given Host header.
sub_filter "ws={{ param_headless_chromium['remote-debugging-address'] }}" "wss=$host"; sub_filter "ws={{ param_headless_chromium['remote-debugging-address'] }}" "wss=$http_host";
sub_filter_once on; sub_filter_once on;
sub_filter_types application/json; sub_filter_types application/json;
sub_filter "ws://{{ param_headless_chromium['remote-debugging-address'] }}" "wss://$host"; sub_filter "ws://{{ param_headless_chromium['remote-debugging-address'] }}" "wss://$http_host";
sub_filter_types application/json; sub_filter_types application/json;
# We want to use our own DevTools frontend rather than # We want to use our own DevTools frontend rather than
......
...@@ -44,6 +44,7 @@ setup( ...@@ -44,6 +44,7 @@ setup(
'slapos.core', 'slapos.core',
'slapos.libnetworkcache', 'slapos.libnetworkcache',
'requests', 'requests',
'websocket-client',
], ],
zip_safe=True, zip_safe=True,
test_suite='test', test_suite='test',
......
...@@ -25,8 +25,13 @@ ...@@ -25,8 +25,13 @@
# #
############################################################################## ##############################################################################
import base64
import os import os
import ssl
import urllib.parse
import requests import requests
import websocket
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
...@@ -35,16 +40,17 @@ setUpModule, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass( ...@@ -35,16 +40,17 @@ setUpModule, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath( os.path.abspath(
os.path.join(os.path.dirname(__file__), '../software.cfg'))) os.path.join(os.path.dirname(__file__), '../software.cfg')))
class TestHeadlessChromium(SlapOSInstanceTestCase): class TestHeadlessChromium(SlapOSInstanceTestCase):
def setUp(self): def setUp(self):
self.connection_parameters = self.requestDefaultInstance().getConnectionParameterDict() self.connection_parameters = self.computer_partition.getConnectionParameterDict()
def test_remote_debugging_port(self): def test_remote_debugging_port(self):
# The headless browser should respond at /json with a nonempty list # The headless browser should respond at /json with a nonempty list
# of available pages, each of which has a webSocketDebuggerUrl and a # of available pages, each of which has a webSocketDebuggerUrl and a
# devtoolsFrontendUrl. # devtoolsFrontendUrl.
url = self.connection_parameters['remote-debug-url'] url = self.connection_parameters['remote-debug-url']
response = requests.get('%s/json' % url) response = requests.get(urllib.parse.urljoin(url, '/json'))
# Check that request was successful and the response was a nonempty # Check that request was successful and the response was a nonempty
# list. # list.
...@@ -53,27 +59,72 @@ class TestHeadlessChromium(SlapOSInstanceTestCase): ...@@ -53,27 +59,72 @@ class TestHeadlessChromium(SlapOSInstanceTestCase):
# Check that the first page has the correct fields. # Check that the first page has the correct fields.
first_page = response.json()[0] first_page = response.json()[0]
self.assertIn('webSocketDebuggerUrl', first_page)
self.assertIn('devtoolsFrontendUrl', first_page) self.assertIn('devtoolsFrontendUrl', first_page)
websocket.create_connection(first_page['webSocketDebuggerUrl'], sslopt={"cert_reqs": ssl.CERT_NONE}).close()
def test_devtools_frontend_ok(self): def test_devtools_frontend_ok(self):
# The proxy should serve the DevTools frontend from param = self.computer_partition.getConnectionParameterDict()
# /serve_file/@{hash}/inspector.html, where {hash} is a 5-32 digit
# hash. # when accessed through RapidCDN, frontend rewrite WSS URLs with the host header but without port.
proxyURL = self.connection_parameters['proxy-url'] page, = requests.get(
username = self.connection_parameters['username'] urllib.parse.urljoin(param['proxy-url'], '/json'),
password = self.connection_parameters['password'] auth=(param['username'], param['password']),
frontend = '/serve_file/@aaaaa/inspector.html' headers={
'Host': 'hostname'
response = requests.get(proxyURL + frontend, verify=False, },
auth=(username, password)) verify=False).json()
self.assertEqual(requests.codes['ok'], response.status_code) ws_debug_url = urllib.parse.urlparse(page['webSocketDebuggerUrl'])
self.assertEqual(
(ws_debug_url.scheme, ws_debug_url.netloc), ('wss', 'hostname'))
devtools_frontend_url = dict(
urllib.parse.parse_qsl(page['devtoolsFrontendUrl'].split('?')[1]))
# devtoolsFrontendUrl is a relative URL, like this:
# 'devtoolsFrontendUrl': '/devtools/inspector.html?wss=[::1]:9442/devtools/page/22C91CF307002BFA22DF0B4E34D2D026'
# and the query string argument wss must also have been rewritten:
self.assertTrue(
devtools_frontend_url['wss'].startswith('hostname/devtools/page/'))
requests.get(
urllib.parse.urljoin(param['proxy-url'], page['devtoolsFrontendUrl']),
auth=(param['username'], param['password']),
headers={
'Host': 'hostname'
},
verify=False).raise_for_status()
# when accessed directly, the :port is kept, as a consequence the debugger interface can
# be accessed directly from the nginx ipv6
page, = requests.get(
urllib.parse.urljoin(param['proxy-url'], '/json'),
auth=(param['username'], param['password']),
verify=False).json()
ws_debug_url = urllib.parse.urlparse(page['webSocketDebuggerUrl'])
self.assertEqual(ws_debug_url.port, 9224)
devtools_frontend_url = dict(urllib.parse.parse_qsl(page['devtoolsFrontendUrl'].split('?')[1]))
# devtoolsFrontendUrl is not rewritten
self.assertEqual(f"wss://{devtools_frontend_url['wss']}", page['webSocketDebuggerUrl'])
requests.get(
urllib.parse.urljoin(param['proxy-url'], page['devtoolsFrontendUrl']),
auth=(param['username'], param['password']),
verify=False).raise_for_status()
# the websocket is usable
websocket.create_connection(
page['webSocketDebuggerUrl'],
sslopt={"cert_reqs": ssl.CERT_NONE},
header={'Authorization': 'Basic ' + base64.b64encode(
f"{param['username']}:{param['password']}".encode()).strip().decode()}).close()
class TestHeadlessChromiumParameters(SlapOSInstanceTestCase): class TestHeadlessChromiumParameters(SlapOSInstanceTestCase):
instance_parameter_dict = { instance_parameter_dict = {
# this website echoes the get request for debugging purposes # this website echoes the get request for debugging purposes
'target-url': 'https://httpbin.org/get?a=6&b=4', 'target-url': 'https://httpbin.org/get?a=6&b=4',
# TODO: this does not work, this software uses 'xml' serialisation and only support strings
'incognito': True, 'incognito': True,
"block-new-web-contents": False, "block-new-web-contents": False,
"window-size": "900,600" "window-size": "900,600"
......
...@@ -16,7 +16,11 @@ ...@@ -16,7 +16,11 @@
[template] [template]
filename = instance.cfg filename = instance.cfg
md5sum = e2e286ba8d40790da3da462d55276e29 md5sum = df4d6e24453b649cc20564d7fcc38e4b
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum = c31dffa87765d93327f18ffd89ce36ca
[amarisoft-stats.jinja2.py] [amarisoft-stats.jinja2.py]
_update_hash_filename_ = amarisoft-stats.jinja2.py _update_hash_filename_ = amarisoft-stats.jinja2.py
...@@ -28,7 +32,7 @@ md5sum = ab666fdfadbfc7d8a16ace38d295c883 ...@@ -28,7 +32,7 @@ md5sum = ab666fdfadbfc7d8a16ace38d295c883
[ru_libinstance.jinja2.cfg] [ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg _update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum = 91ef336b7e913c07d89b82b27ffad11d md5sum = a6b710ca5132276d72f90b76b873fe98
[ru_sdr_libinstance.jinja2.cfg] [ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg _update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
...@@ -36,7 +40,7 @@ md5sum = c20b620111a4dc4bc2bcae57c2007cbe ...@@ -36,7 +40,7 @@ md5sum = c20b620111a4dc4bc2bcae57c2007cbe
[ru_lopcomm_libinstance.jinja2.cfg] [ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg _update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = 02a7a12b933544b4287599afed0fc68d md5sum = a150743e78f9ecafc40b715f2aa80295
[ru_sunwave_libinstance.jinja2.cfg] [ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg _update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
...@@ -44,11 +48,11 @@ md5sum = 0450e9fa50844e4d6e51d608625c57f6 ...@@ -44,11 +48,11 @@ md5sum = 0450e9fa50844e4d6e51d608625c57f6
[ru_lopcomm_ncclient_common.py] [ru_lopcomm_ncclient_common.py]
_update_hash_filename_ = ru/lopcomm/ncclient_common.py _update_hash_filename_ = ru/lopcomm/ncclient_common.py
md5sum = 6f8d0592cc4b0b695cea5a0c25aafc4e md5sum = 8dbe6a48fc0fca4f0cbd0c746be1aeda
[ru_lopcomm_stats.jinja2.py] [ru_lopcomm_stats.jinja2.py]
_update_hash_filename_ = ru/lopcomm/stats.jinja2.py _update_hash_filename_ = ru/lopcomm/stats.jinja2.py
md5sum = 3a5a3c5588e1698ee81e983bb08e70d7 md5sum = b7ec0025a92e0947e4ac6abc4b06bf19
[ru_lopcomm_config.jinja2.py] [ru_lopcomm_config.jinja2.py]
_update_hash_filename_ = ru/lopcomm/config.jinja2.py _update_hash_filename_ = ru/lopcomm/config.jinja2.py
...@@ -66,10 +70,6 @@ md5sum = 9741fbc99aaf768e9cc3ab48925dfee5 ...@@ -66,10 +70,6 @@ md5sum = 9741fbc99aaf768e9cc3ab48925dfee5
_update_hash_filename_ = ru/lopcomm/software.jinja2.py _update_hash_filename_ = ru/lopcomm/software.jinja2.py
md5sum = 2b08bb666c5f3ab287cdddbfdb4c9249 md5sum = 2b08bb666c5f3ab287cdddbfdb4c9249
[ru_lopcomm_supervision.jinja2.py]
_update_hash_filename_ = ru/lopcomm/supervision.jinja2.py
md5sum = 437cc45f132d6c74647a716c6a1920e1
[ru_tapsplit] [ru_tapsplit]
_update_hash_filename_ = ru/tapsplit _update_hash_filename_ = ru/tapsplit
md5sum = 2b8b57c5771b2a2203c0e7767e629e55 md5sum = 2b8b57c5771b2a2203c0e7767e629e55
...@@ -80,7 +80,7 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e ...@@ -80,7 +80,7 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb] [template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg _update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 815d57a36c7e3b4361230fbd3c76a9ef md5sum = b52a8584712f9cee338c71a6dedc7dad
[template-gnb] [template-gnb]
_update_hash_filename_ = instance-gnb.jinja2.cfg _update_hash_filename_ = instance-gnb.jinja2.cfg
...@@ -108,7 +108,7 @@ md5sum = dcaac06553a3222b14c0013a13f4a149 ...@@ -108,7 +108,7 @@ md5sum = dcaac06553a3222b14c0013a13f4a149
[enb.jinja2.cfg] [enb.jinja2.cfg]
filename = config/enb.jinja2.cfg filename = config/enb.jinja2.cfg
md5sum = 8e49dfc9318da43bd817b8891cba24b7 md5sum = a961cc1469bd2534645470f914f12905
[drb_lte.jinja2.cfg] [drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg filename = config/drb_lte.jinja2.cfg
......
{%- import 'slaplte.jinja2' as slaplte with context %}
{#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with ru/libinstance.jinja2.cfg #}
{%- if _standalone is defined %}
{%- set cell_list = {} %}
{%- do slaplte.load_cell(cell_list) %}
{%- endif %}
{%- set cell_count = cell_list|length %} {%- set cell_count = cell_list|length %}
{%- if slapparameter_dict.get('tdd_ul_dl_config', '[Configuration 2] 5ms 2UL 6DL (default)') == '[Configuration 2] 5ms 2UL 6DL (default)' %} {%- if slapparameter_dict.get('tdd_ul_dl_config', '[Configuration 2] 5ms 2UL 6DL (default)') == '[Configuration 2] 5ms 2UL 6DL (default)' %}
......
...@@ -32,6 +32,7 @@ eggs-directory = {{ eggs_directory }} ...@@ -32,6 +32,7 @@ eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }} develop-eggs-directory = {{ develop_eggs_directory }}
offline = true offline = true
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- import 'ru_libinstance.jinja2.cfg' as rulib with context %} {%- import 'ru_libinstance.jinja2.cfg' as rulib with context %}
{{ rulib.buildout() }} {{ rulib.buildout() }}
...@@ -367,6 +368,9 @@ extra-context = ...@@ -367,6 +368,9 @@ extra-context =
json cell_list {{ rulib.cell_list | tojson }} json cell_list {{ rulib.cell_list | tojson }}
key sib23_file sib-config:output key sib23_file sib-config:output
key drb_file drb-config:output key drb_file drb-config:output
import-list =
rawfile slaplte.jinja2 {{ slaplte_template }}
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
......
...@@ -40,6 +40,7 @@ context = ...@@ -40,6 +40,7 @@ context =
raw ru ${rf-mode:ru} raw ru ${rf-mode:ru}
$${:extra-context} $${:extra-context}
import-list = import-list =
rawfile slaplte.jinja2 ${slaplte.jinja2:target}
rawfile ru_libinstance.jinja2.cfg ${ru_libinstance.jinja2.cfg:target} rawfile ru_libinstance.jinja2.cfg ${ru_libinstance.jinja2.cfg:target}
rawfile ru_sdr_libinstance.jinja2.cfg ${ru_sdr_libinstance.jinja2.cfg:target} rawfile ru_sdr_libinstance.jinja2.cfg ${ru_sdr_libinstance.jinja2.cfg:target}
rawfile ru_lopcomm_libinstance.jinja2.cfg ${ru_lopcomm_libinstance.jinja2.cfg:target} rawfile ru_lopcomm_libinstance.jinja2.cfg ${ru_lopcomm_libinstance.jinja2.cfg:target}
...@@ -275,6 +276,7 @@ extra-context = ...@@ -275,6 +276,7 @@ extra-context =
key enb amarisoft:enb key enb amarisoft:enb
key sdr amarisoft:sdr key sdr amarisoft:sdr
raw enb_template ${enb.jinja2.cfg:target} raw enb_template ${enb.jinja2.cfg:target}
raw slaplte_template ${slaplte.jinja2:target}
raw drb_lte_template ${drb_lte.jinja2.cfg:target} raw drb_lte_template ${drb_lte.jinja2.cfg:target}
raw sib23_template ${sib23.jinja2.asn:target} raw sib23_template ${sib23.jinja2.asn:target}
raw amarisoft_stats_template ${amarisoft-stats.jinja2.py:target} raw amarisoft_stats_template ${amarisoft-stats.jinja2.py:target}
...@@ -282,7 +284,6 @@ extra-context = ...@@ -282,7 +284,6 @@ extra-context =
raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target} raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target} raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target} raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw ru_lopcomm_supervision_template ${ru_lopcomm_supervision.jinja2.py:target}
raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target} raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target} raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target}
raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target} raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target}
......
...@@ -3,15 +3,16 @@ ...@@ -3,15 +3,16 @@
Use buildout() macro to emit instance-level code to Use buildout() macro to emit instance-level code to
handle configured RUs. handle configured RUs.
NOTE: before importing package slaplte.jinja2 needs to already loaded as
{%- import 'slaplte.jinja2' as slaplte with context %}
NOTE: driver-specific logic is implemented in rudrv.buildout_ru() . NOTE: driver-specific logic is implemented in rudrv.buildout_ru() .
#} #}
{#- cell_list keeps cell registry #} {#- cell_list keeps cell registry #}
{%- set cell_list = slapparameter_dict.get('cell_list', {'default': {}}) %} {%- set cell_list = {} %}
{%- for i, k in enumerate(cell_list) %} {%- do slaplte.load_cell(cell_list) %}
{%- set cell = cell_list[k] %}
{%- do cell.setdefault('cpri_port_number', i) %}
{%- endfor %}
{%- macro buildout() %} {%- macro buildout() %}
...@@ -39,13 +40,6 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} ...@@ -39,13 +40,6 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
lopcomm=rudrv_lopcomm, lopcomm=rudrv_lopcomm,
sunwave=rudrv_sunwave) %} sunwave=rudrv_sunwave) %}
{#- slaptap indicates tap interface, that slapos told us to use,
or 'xxx-notap-xxx' if slapos provided us either nothing or empty string. #}
{%- set slaptap = slap_configuration.get('tap-name', '') %}
{%- if slaptap == '' %}
{%- set slaptap = 'xxx-notap-xxx' %}
{%- endif %}
{#- split slapos tap interface for each RU {#- split slapos tap interface for each RU
fallback to non-split approach for ntap <= 1 to avoid hard-dependecy on setcap/tapsplit fallback to non-split approach for ntap <= 1 to avoid hard-dependecy on setcap/tapsplit
...@@ -58,7 +52,7 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} ...@@ -58,7 +52,7 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
[vtap] [vtap]
recipe = plone.recipe.command recipe = plone.recipe.command
ntap = {{ ntap }} ntap = {{ ntap }}
command = {{ netcapdo }} {{ pythonwitheggs }} {{ ru_tapsplit }} {{ slaptap }} ${:ntap} command = {{ netcapdo }} {{ pythonwitheggs }} {{ ru_tapsplit }} {{ slaplte.tap }} ${:ntap}
update-command = ${:command} update-command = ${:command}
stop-on-error = true stop-on-error = true
...@@ -68,8 +62,8 @@ ntap = 0 ...@@ -68,8 +62,8 @@ ntap = 0
stop-on-error = false stop-on-error = false
{%- if ntap == 1 %} {%- if ntap == 1 %}
{%- do vtap_list.append(slaptap) %} {%- do vtap_list.append(slaplte.tap) %}
[vtap.{{ slaptap }}] [vtap.{{ slaplte.tap }}]
network = {{ slap_configuration['tap-ipv6-network'] }} network = {{ slap_configuration['tap-ipv6-network'] }}
gateway = {{ slap_configuration['tap-ipv6-gateway'] }} gateway = {{ slap_configuration['tap-ipv6-gateway'] }}
addr = {{ slap_configuration['tap-ipv6-addr'] }} addr = {{ slap_configuration['tap-ipv6-addr'] }}
...@@ -78,7 +72,7 @@ addr = {{ slap_configuration['tap-ipv6-addr'] }} ...@@ -78,7 +72,7 @@ addr = {{ slap_configuration['tap-ipv6-addr'] }}
{%- else %} {%- else %}
{%- for i in range(1,1+ntap) %} {%- for i in range(1,1+ntap) %}
{%- set tap = '%s-%d' % (slaptap, i) %} {%- set tap = '%s-%d' % (slaplte.tap, i) %}
{%- do vtap_list.append(tap) %} {%- do vtap_list.append(tap) %}
[vtap.{{ tap }}] [vtap.{{ tap }}]
recipe = slapos.recipe.build recipe = slapos.recipe.build
...@@ -96,7 +90,7 @@ init = ...@@ -96,7 +90,7 @@ init =
# simulate what tapsplit would assign to the tap # simulate what tapsplit would assign to the tap
# ( tap subinterface will be created for real later at install time - when it # ( tap subinterface will be created for real later at install time - when it
# is too late to update section options ) # is too late to update section options )
slapnet = tapsplit.ifnet6('{{ slaptap }}') slapnet = tapsplit.ifnet6('{{ slaplte.tap }}')
tapnet = tapsplit.netsplit(slapnet, {{ 1+ntap }}) [{{ i }}] tapnet = tapsplit.netsplit(slapnet, {{ 1+ntap }}) [{{ i }}]
options['network'] = str(tapnet) options['network'] = str(tapnet)
...@@ -119,17 +113,6 @@ init = ...@@ -119,17 +113,6 @@ init =
{%- endfor %} {%- endfor %}
{#- assign TAP interfaces to RUs #}
{%- for i, (cell_ref, cell) in enumerate(cell_list|dictsort) %}
{%- if len(cell_list) > 1 %}
{%- set ru_tap = "%s-%d" % (slaptap, i+1) %}
{%- else %}
{%- set ru_tap = slaptap %}
{%- endif %}
{%- do cell.update({'_tap': ru_tap}) %}
{%- endfor %}
{#- go through all RUs and for each RU invoke {#- go through all RUs and for each RU invoke
RU-specific buildout handler #} RU-specific buildout handler #}
{%- set ru_type = {'lopcomm': 'lopcomm', 'm2ru': 'sunwave'}.get(ru, 'sdr') %} {%- set ru_type = {'lopcomm': 'lopcomm', 'm2ru': 'sunwave'}.get(ru, 'sdr') %}
......
...@@ -22,9 +22,6 @@ parts += ...@@ -22,9 +22,6 @@ parts +=
[ru_lopcomm_software.jinja2.py] [ru_lopcomm_software.jinja2.py]
<= download-base <= download-base
[ru_lopcomm_supervision.jinja2.py]
<= download-base
[ru_lopcomm_ncclient_common.py] [ru_lopcomm_ncclient_common.py]
<= download-base <= download-base
destination = ${buildout:directory}/ncclient_common.py destination = ${buildout:directory}/ncclient_common.py
......
...@@ -9,43 +9,9 @@ promise = check_socket_listening ...@@ -9,43 +9,9 @@ promise = check_socket_listening
config-host = ${vtap.{{cell._tap}}:gateway} config-host = ${vtap.{{cell._tap}}:gateway}
config-port = 830 config-port = 830
{#- monitor state of netconf connection + keep on touching RU watchdog #}
[{{ru_ref}}-supervision-template]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-supervision
log-output = ${:_logbase}.log
supervision-reply-json-log-output = ${:_logbase}-reply.json.log
is_netconf_connected = ${directory:etc}/{{ru_ref}}.is_netconf_connected
context =
section directory directory
section vtap vtap.{{ cell._tap }}
key slapparameter_dict slap-configuration:configuration
key log_file :log-output
key supervision_reply_json_log_file :supervision-reply-json-log-output
raw testing {{ slapparameter_dict.get("testing", False) }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs
raw buildout_directory_path {{ buildout_directory }}
key is_netconf_connected :is_netconf_connected
import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_supervision_template }}
output = ${directory:bin}/{{ru_ref}}-supervision.py
{{ part('%s-supervision-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-supervision-template:output}
wrapper-path = ${directory:service}/{{ru_ref}}-supervision
mode = 0775
hash-files =
${:command-line}
{{ promise('%s-netconf-connection' % ru_ref) }} {{ promise('%s-netconf-connection' % ru_ref) }}
promise = check_command_execute promise = check_command_execute
config-command = [ -f ${ {{-ru_ref}}-supervision-template:is_netconf_connected} ] config-command = [ -f ${ {{-ru_ref}}-stats-template:is_netconf_connected} ]
{#- push firmware to RU #} {#- push firmware to RU #}
...@@ -133,6 +99,8 @@ cfg-json-log-output = ${:_logbase}-config.json.log ...@@ -133,6 +99,8 @@ cfg-json-log-output = ${:_logbase}-config.json.log
supervision-json-log-output = ${:_logbase}-supervision.json.log supervision-json-log-output = ${:_logbase}-supervision.json.log
ncsession-json-log-output = ${:_logbase}-ncsession.json.log ncsession-json-log-output = ${:_logbase}-ncsession.json.log
software-json-log-output = ${:_logbase}-software.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 = context =
section directory directory section directory directory
section vtap vtap.{{ cell._tap }} section vtap vtap.{{ cell._tap }}
...@@ -141,6 +109,8 @@ context = ...@@ -141,6 +109,8 @@ context =
key json_log_file :json-log-output key json_log_file :json-log-output
key cfg_json_log_file :cfg-json-log-output key cfg_json_log_file :cfg-json-log-output
key supervision_json_log_file :supervision-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 ncsession_json_log_file :ncsession-json-log-output
key software_json_log_file :software-json-log-output key software_json_log_file :software-json-log-output
raw testing {{ slapparameter_dict.get("testing", False) }} raw testing {{ slapparameter_dict.get("testing", False) }}
......
...@@ -103,24 +103,24 @@ class LopcommNetconfClient: ...@@ -103,24 +103,24 @@ class LopcommNetconfClient:
sub = self.conn.create_subscription() sub = self.conn.create_subscription()
self.logger.info('Subscription to %s successful' % (self.address,)) self.logger.info('Subscription to %s successful' % (self.address,))
def get_notification(self): def get_notification(self):
result = None self.logger.debug('Waiting for notification from %s...' % (self.address,))
while result == None: result = self.conn.take_notification(block=True, timeout=120)
self.logger.debug('Waiting for notification from %s...' % (self.address,)) if result:
result = self.conn.take_notification(block=True) self.logger.debug('Got new notification from %s...' % (self.address,))
if result: result_in_xml = result._raw
self.logger.debug('Got new notification from %s...' % (self.address,)) data_dict = xmltodict.parse(result_in_xml)
result_in_xml = result._raw if 'alarm-notif' in data_dict['notification']:
data_dict = xmltodict.parse(result_in_xml) self.json_logger.info('', extra={'data': json.dumps(data_dict)})
if 'alarm-notif' in data_dict['notification']: elif 'supervision-notification' in data_dict['notification']:
self.json_logger.info('', extra={'data': json.dumps(data_dict)}) self.supervision_json_logger.info('', extra={'data': json.dumps(data_dict)})
elif 'supervision-notification' in data_dict['notification']: elif 'netconf-session-start' in data_dict['notification'] or 'netconf-session-end' in data_dict['notification']:
self.supervision_json_logger.info('', extra={'data': json.dumps(data_dict)}) self.ncsession_json_logger.info('', extra={'data': json.dumps(data_dict)})
elif 'netconf-session-start' in data_dict['notification'] or 'netconf-session-end' in data_dict['notification']: elif any(event in data_dict['notification'] for event in ['install-event', 'activation-event', 'download-event']):
self.ncsession_json_logger.info('', extra={'data': json.dumps(data_dict)}) self.software_json_logger.info('', extra={'data': json.dumps(data_dict)})
elif any(event in data_dict['notification'] for event in ['install-event', 'activation-event', 'download-event']): else:
self.software_json_logger.info('', extra={'data': json.dumps(data_dict)}) self.cfg_json_logger.info('', extra={'data': json.dumps(data_dict)})
else: else:
self.cfg_json_logger.info('', extra={'data': json.dumps(data_dict)}) raise TimeoutError
def edit_config(self, config_files): def edit_config(self, config_files):
for config_file in config_files: for config_file in config_files:
with open(config_file) as f: with open(config_file) as f:
...@@ -199,6 +199,23 @@ class LopcommNetconfClient: ...@@ -199,6 +199,23 @@ class LopcommNetconfClient:
"running_slot_name_build_version": running_slot_name_build_version "running_slot_name_build_version": running_slot_name_build_version
} }
def supervision_reset(self, interval=60, margin=10):
self.logger.info("NETCONF server supervision replying...")
supervision_watchdog_rpc_xml = f"""
<supervision-watchdog-reset xmlns="urn:o-ran:supervision:1.0">
<supervision-notification-interval>{interval}</supervision-notification-interval>
<guard-timer-overhead>{margin}</guard-timer-overhead>
</supervision-watchdog-reset>
"""
supervision_watchdog_reply_xml = self.custom_rpc_request(supervision_watchdog_rpc_xml)
replied = False
if supervision_watchdog_reply_xml:
replied = True
self.logger.info("NETCONF server supervision replied")
supervision_watchdog_data = xmltodict.parse(supervision_watchdog_reply_xml)
self.supervision_reply_json_logger.info('', extra={'data': json.dumps(supervision_watchdog_data)})
return replied
def close(self): def close(self):
# Close not compatible between ncclient and netconf server # Close not compatible between ncclient and netconf server
#self.conn.close() #self.conn.close()
......
#!{{ python_path }} #!{{ python_path }}
import time import time
import sys import sys
import os
import threading
sys.path.append({{ repr(buildout_directory_path) }}) sys.path.append({{ repr(buildout_directory_path) }})
from ncclient_common import LopcommNetconfClient from ncclient_common import LopcommNetconfClient
# Shared variable to indicate error occurred
error_occurred = False
lock = threading.Lock()
def get_notification_continuously(nc):
global error_occurred
try:
while not error_occurred:
nc.get_notification()
pass
except Exception as e:
with lock:
error_occurred = True
nc.logger.error(f'Error in get_notification_continuously: {e}')
# supervision watchdog keeps on
def run_supervision_reset_continuously(nc):
global error_occurred
netconf_check_file = '{{ is_netconf_connected }}'
interval = 60
margin = 10
try:
while not error_occurred:
t0 = time.time()
replied = nc.supervision_reset(interval, margin)
if replied:
with open(netconf_check_file, "w") as f:
f.write('')
elif os.path.exists(netconf_check_file):
os.remove(netconf_check_file)
t1 = time.time()
time.sleep(interval - (t1 - t0))
except Exception as e:
with lock:
error_occurred = True
nc.logger.error(f'Error in run_supervision_reset_continuously: {e}')
if __name__ == '__main__': if __name__ == '__main__':
nc = LopcommNetconfClient( nc = LopcommNetconfClient(
log_file="{{ log_file }}", log_file="{{ log_file }}",
json_log_file="{{ json_log_file }}", json_log_file="{{ json_log_file }}",
cfg_json_log_file="{{ cfg_json_log_file }}", cfg_json_log_file="{{ cfg_json_log_file }}",
supervision_json_log_file="{{ supervision_json_log_file }}", supervision_json_log_file="{{ supervision_json_log_file }}",
ncsession_json_log_file="{{ ncsession_json_log_file }}", ncsession_json_log_file="{{ ncsession_json_log_file }}",
software_json_log_file="{{ software_json_log_file }}" software_json_log_file="{{ software_json_log_file }}",
supervision_reply_json_log_file="{{ supervision_reply_json_log_file }}"
) )
while True: threads = []
try: try:
nc.connect("{{ netaddr.IPAddress(vtap.gateway) }}", 830, "oranuser", "oranpassword") nc.connect("{{ netaddr.IPAddress(vtap.gateway) }}", 830, "oranuser", "oranpassword")
nc.subscribe() nc.subscribe()
while True:
nc.get_notification() notification_thread = threading.Thread(target=get_notification_continuously, args=(nc,))
supervision_thread = threading.Thread(target=run_supervision_reset_continuously, args=(nc,))
threads.append(notification_thread)
threads.append(supervision_thread)
for thread in threads:
thread.start()
for thread in threads:
thread.join()
except Exception as e: except Exception as e:
nc.logger.debug('Got exception, waiting 10 seconds before reconnecting...') nc.logger.debug('Got exception, waiting 10 seconds before reconnecting...')
nc.logger.debug(e) nc.logger.debug(e)
......
{#- Package slaplte provides helpers for configuring Amarisoft LTE services in SlapOS.
- load_cell initializes cell registry.
-#}
{#- tap indicates tap interface, that slapos told us to use,
or 'xxx-notap-xxx' if slapos provided us either nothing or empty string. #}
{%- set tap = slap_configuration.get('tap-name', '') %}
{%- if tap == '' %}
{%- set tap = 'xxx-notap-xxx' %}
{%- endif %}
{#- ---- loading ---- #}
{#- load_cell initializes cell registry.
cell_list keeps configured cells: {} cell reference -> cell parameters
#}
{%- macro load_cell(cell_list) %}
{%- do cell_list.update( slapparameter_dict.get('cell_list', {'default': {}}) ) %}
{%- for i, k in enumerate(cell_list) %}
{%- set cell = cell_list[k] %}
{%- do cell.setdefault('cpri_port_number', i) %}
{%- endfor %}
{#- assign TAP interfaces to RUs #}
{%- for i, (cell_ref, cell) in enumerate(cell_list|dictsort) %}
{%- if len(cell_list) > 1 %}
{%- set ru_tap = "%s-%d" % (tap, i+1) %}
{%- else %}
{%- set ru_tap = tap %}
{%- endif %}
{%- do cell.update({'_tap': ru_tap}) %}
{%- endfor %}
{%- endmacro %}
...@@ -12,6 +12,8 @@ import json ...@@ -12,6 +12,8 @@ import json
# j2render renders config/<cfg>.jinja2.cfg into config/<cfg>.cfg with provided json parameters. # j2render renders config/<cfg>.jinja2.cfg into config/<cfg>.cfg with provided json parameters.
def j2render(cfg, jcfg): def j2render(cfg, jcfg):
ctx = json.loads(jcfg) ctx = json.loads(jcfg)
assert '_standalone' not in ctx
ctx['_standalone'] = True
textctx = '' textctx = ''
for k, v in ctx.items(): for k, v in ctx.items():
textctx += 'json %s %s\n' % (k, json.dumps(v)) textctx += 'json %s %s\n' % (k, json.dumps(v))
...@@ -21,6 +23,8 @@ def j2render(cfg, jcfg): ...@@ -21,6 +23,8 @@ def j2render(cfg, jcfg):
'url': 'config/{}.jinja2.cfg'.format(cfg), 'url': 'config/{}.jinja2.cfg'.format(cfg),
'output': 'config/{}.cfg'.format(cfg), 'output': 'config/{}.cfg'.format(cfg),
'context': textctx, 'context': textctx,
'import-list': '''
rawfile slaplte.jinja2 slaplte.jinja2''',
}) })
#print(r.context) #print(r.context)
...@@ -34,54 +38,57 @@ def j2render(cfg, jcfg): ...@@ -34,54 +38,57 @@ def j2render(cfg, jcfg):
f.write(r._render().decode()) f.write(r._render().decode())
config = "gnb" def do(cfg, slapparameter_dict):
json_params_empty = """{ jslapparameter_dict = json.dumps(slapparameter_dict)
"rf_mode": 'fdd', json_params_empty = """{
"slap_configuration": { "rf_mode": 'fdd',
}, "slap_configuration": {
"directory": { },
}, "directory": {
"slapparameter_dict": { },
} "slapparameter_dict": %(jslapparameter_dict)s
}""" }"""
json_params = """{ json_params = """{
"rf_mode": "tdd", "rf_mode": "tdd",
"trx": "sdr", "trx": "sdr",
"bbu": "ors", "bbu": "ors",
"ru": "ors", "ru": "ors",
"one_watt": "True", "one_watt": "True",
"earfcn": 646666, "earfcn": 646666,
"nr_arfcn": 646666, "nr_arfcn": 646666,
"nr_band": 43, "nr_band": 43,
"tx_gain": 62, "tx_gain": 62,
"rx_gain": 43, "rx_gain": 43,
"sib23_file": "sib", "sib23_file": "sib",
"slap_configuration": { "drb_file": "drb",
"tap-name": "slaptap9", "slap_configuration": {
"configuration.default_lte_bandwidth": "10 MHz", "tap-name": "slaptap9",
"configuration.default_lte_imsi": "001010123456789", "configuration.default_lte_bandwidth": "10 MHz",
"configuration.default_lte_k": "00112233445566778899aabbccddeeff", "configuration.default_lte_imsi": "001010123456789",
"configuration.default_lte_inactivity_timer": 10000, "configuration.default_lte_k": "00112233445566778899aabbccddeeff",
"configuration.default_nr_bandwidth": 40, "configuration.default_lte_inactivity_timer": 10000,
"configuration.default_nr_imsi": "001010123456789", "configuration.default_nr_bandwidth": 40,
"configuration.default_nr_k": "00112233445566778899aabbccddeeff", "configuration.default_nr_imsi": "001010123456789",
"configuration.default_nr_ssb_pos_bitmap": "10000000", "configuration.default_nr_k": "00112233445566778899aabbccddeeff",
"configuration.default_n_antenna_dl": 2, "configuration.default_nr_ssb_pos_bitmap": "10000000",
"configuration.default_n_antenna_ul": 2, "configuration.default_n_antenna_dl": 2,
"configuration.default_nr_inactivity_timer": 10000, "configuration.default_n_antenna_ul": 2,
"configuration.com_ws_port": 9001, "configuration.default_nr_inactivity_timer": 10000,
"configuration.com_addr": "127.0.1.2", "configuration.com_ws_port": 9001,
"configuration.amf_addr": "127.0.1.100", "configuration.com_addr": "127.0.1.2",
"configuration.gtp_addr": "127.0.1.1" "configuration.amf_addr": "127.0.1.100",
}, "configuration.mme_addr": "127.0.1.100",
"directory": { "configuration.gtp_addr": "127.0.1.1"
"log": "log", },
"etc": "etc", "directory": {
"var": "var" "log": "log",
}, "etc": "etc",
"slapparameter_dict": { "var": "var"
"tdd_ul_dl_config": "5ms 8UL 1DL 2/10 (maximum uplink)" },
} "slapparameter_dict": %(jslapparameter_dict)s
}""" }"""
j2render(config, json_params) j2render(cfg, json_params % locals())
do('enb', {"tdd_ul_dl_config": "[Configuration 6] 5ms 5UL 3DL (maximum uplink)"})
do('gnb', {"tdd_ul_dl_config": "5ms 8UL 1DL 2/10 (maximum uplink)"})
...@@ -147,6 +147,8 @@ filename = ue-lte.jinja2.cfg ...@@ -147,6 +147,8 @@ filename = ue-lte.jinja2.cfg
[ue-nr.jinja2.cfg] [ue-nr.jinja2.cfg]
<= copy-config-to-instance <= copy-config-to-instance
filename = ue-nr.jinja2.cfg filename = ue-nr.jinja2.cfg
[slaplte.jinja2]
<= download-base
# Download gadget files # Download gadget files
[software.cfg.html] [software.cfg.html]
......
...@@ -23,7 +23,7 @@ md5sum = 9658a11340c018de816d0de40683706a ...@@ -23,7 +23,7 @@ md5sum = 9658a11340c018de816d0de40683706a
[instance-import] [instance-import]
_update_hash_filename_ = instance-import.cfg.jinja.in _update_hash_filename_ = instance-import.cfg.jinja.in
md5sum = 6520d2aa0c1c6094cbf276080594ec1a md5sum = c8d1be7aee980deb0f0d1a3126c9b9da
[instance-export] [instance-export]
_update_hash_filename_ = instance-export.cfg.jinja.in _update_hash_filename_ = instance-export.cfg.jinja.in
......
{%- set parameter_dict = dict(default_parameter_dict, **parameter_dict) -%} {%- set parameter_dict = dict(default_parameter_dict, **parameter_dict) -%}
{%- set additional_frontend = parameter_dict['additional-frontend-guid'] -%} {%- set additional_frontend = parameter_dict['additional-frontend-guid'] -%}
{%- set namebase = parameter_dict['namebase'] -%}
{%- set theia_number = parameter_dict['number'] -%}
{%- set theia_id = '%s%s' % (namebase, theia_number) -%}
{%- set frontend_name = parameter_dict['frontend-name'] -%}
[buildout] [buildout]
extends = {{ theia_instance_cfg }} extends = {{ theia_instance_cfg }}
...@@ -16,16 +20,16 @@ parts += ...@@ -16,16 +20,16 @@ parts +=
# The import template then expects to receive it in # The import template then expects to receive it in
# slap-parameter:namebase # slap-parameter:namebase
[slap-parameter] [slap-parameter]
namebase = {{ parameter_dict['namebase'] }} namebase = {{ namebase }}
# Change frontend name to avoid conflicts # Change frontend name to avoid conflicts
[remote-frontend] [remote-frontend]
name = Import {{ parameter_dict['frontend-name'] }} name = {{ frontend_name }} for {{ theia_id }}
{% if additional_frontend -%} {% if additional_frontend -%}
[remote-additional-frontend] [remote-additional-frontend]
name = Import {{ parameter_dict['additional-frontend-name'] }} name = {{ parameter_dict['additional-frontend-name'] }} for {{ theia-id }}
{%- endif %} {%- endif %}
......
...@@ -300,7 +300,7 @@ simplegeneric = 0.8.1 ...@@ -300,7 +300,7 @@ simplegeneric = 0.8.1
singledispatch = 3.4.0.3 singledispatch = 3.4.0.3
six = 1.16.0 six = 1.16.0
slapos.cookbook = 1.0.329 slapos.cookbook = 1.0.329
slapos.core = 1.10.4 slapos.core = 1.10.5
slapos.extension.shared = 1.0 slapos.extension.shared = 1.0
slapos.libnetworkcache = 0.25 slapos.libnetworkcache = 0.25
slapos.rebootstrap = 4.5 slapos.rebootstrap = 4.5
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment