Commit d53e62d8 authored by Xavier Thompson's avatar Xavier Thompson

software/theia: Fix slapos env discrepancy

See merge request nexedi/slapos!938
parents c8f8159e b2f3dc78
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
[instance] [instance]
filename = instance.cfg.in filename = instance.cfg.in
md5sum = e56a6722e4f0bc958f6b61f13174e852 md5sum = ab61eeb45300a91c0c4fb42bd5c52c9f
[yarn.lock] [yarn.lock]
filename = yarn.lock filename = yarn.lock
......
...@@ -279,6 +279,23 @@ location = $${directory:frontend-static}/$${:filename} ...@@ -279,6 +279,23 @@ location = $${directory:frontend-static}/$${:filename}
filename = $${:_buildout_section_name_} filename = $${:_buildout_section_name_}
# Common Environment
# ------------------
[common-environment]
recipe = slapos.recipe.template:jinja2
rendered = ${buildout:bin-directory}/${:_buildout_section_name_}
mode = 0777
template =
inline:
#!/bin/sh
. ${gowork:env.sh}
# reset PS1 from gowork
export PS1='$ '
export HOME=$${buildout:directory}
export PATH=${python-language-server:location}/bin:${java-jdk:location}/bin:${cli-utilities:PATH}:$HOME/.cargo/bin:$PATH
# Theia Backend # Theia Backend
# ------------- # -------------
...@@ -300,12 +317,13 @@ template = ...@@ -300,12 +317,13 @@ template =
export THEIA_OPEN_EDITOR_TOKEN=$(${openssl:location}/bin/openssl rand -hex 32) export THEIA_OPEN_EDITOR_TOKEN=$(${openssl:location}/bin/openssl rand -hex 32)
export THEIA_URL=$${:base-url} export THEIA_URL=$${:base-url}
export THEIA_SHELL=$${theia-shell:rendered} export THEIA_SHELL=$${theia-shell:rendered}
export HOME=$${buildout:directory}
export TMP=$${directory:tmp} export TMP=$${directory:tmp}
export TEMP=$TMP export TEMP=$TMP
export LC_ALL=C.UTF-8 export LC_ALL=C.UTF-8
export TERMINFO=${ncurses:location}/lib/terminfo/ export TERMINFO=${ncurses:location}/lib/terminfo/
export EDITOR="${python-language-server:location}/bin/python -m theia_open --wait" export EDITOR="${python-language-server:location}/bin/python -m theia_open --wait"
export THEIA_DEFAULT_PLUGINS="local-dir:${theia-plugins:location}"
. $${common-environment:rendered}
exec ${theia-wrapper:rendered} $@ exec ${theia-wrapper:rendered} $@
ip = $${theia-service-port:ip} ip = $${theia-service-port:ip}
port = $${theia-service-port:port} port = $${theia-service-port:port}
...@@ -392,7 +410,9 @@ rendered = $${directory:bin}/$${:_buildout_section_name_} ...@@ -392,7 +410,9 @@ rendered = $${directory:bin}/$${:_buildout_section_name_}
mode = 0700 mode = 0700
template = template =
inline:#!/bin/sh inline:#!/bin/sh
export PATH=${buildout:bin-directory}:$PATH . $${common-environment:rendered}
export PATH=${nodejs:location}/bin/:$PATH
. $${slapos-standalone-activate:rendered}
exec ${slapos-standalone:script-path} \ exec ${slapos-standalone:script-path} \
$${directory:runner} \ $${directory:runner} \
$${slapos-standalone-config:ipv4} \ $${slapos-standalone-config:ipv4} \
......
...@@ -299,7 +299,8 @@ install += ...@@ -299,7 +299,8 @@ install +=
[cli-utilities] [cli-utilities]
PATH = ${nodejs:location}/bin/:${bash:location}/bin/:${fish-shell:location}/bin/:${tig:location}/bin/:${vim:location}/bin/:${tmux:location}/bin/:${git:location}/bin/:${curl:location}/bin:${python2.7:location}/bin/:${buildout:bin-directory} PATH = ${nodejs:location}/bin:${bash:location}/bin:${fish-shell:location}/bin:${tig:location}/bin:${vim:location}/bin:${tmux:location}/bin:${git:location}/bin:${curl:location}/bin:${python2.7:location}/bin:${buildout:bin-directory}
[theia-wrapper] [theia-wrapper]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
...@@ -307,12 +308,7 @@ rendered = ${buildout:bin-directory}/${:_buildout_section_name_} ...@@ -307,12 +308,7 @@ rendered = ${buildout:bin-directory}/${:_buildout_section_name_}
mode = 0777 mode = 0777
template = template =
inline: inline:
#!/bin/bash #!/bin/sh
. ${gowork:env.sh}
export PATH=${python-language-server:location}/bin/:${java-jdk:location}/bin/:${cli-utilities:PATH}:$HOME/.cargo/bin:$PATH
export THEIA_DEFAULT_PLUGINS="local-dir:${theia-plugins:location}"
# reset PS1 from gowork
export PS1='$ '
cd ${theia:location} cd ${theia:location}
exec ${yarn:location}/bin/yarn theia start $@ exec ${yarn:location}/bin/yarn theia start $@
......
# Dummy Software
A very simple SR that dumps the environment in JSON format during installation.
[buildout]
newest = false
versions = versions
parts =
log-env
[log-env]
recipe = slapos.recipe.build
init =
import json
import os
with open("${buildout:directory}/../env.json", 'w') as f:
json.dump(dict(os.environ), f)
[versions]
slapos.recipe.build = 0.46
...@@ -33,6 +33,7 @@ import subprocess ...@@ -33,6 +33,7 @@ import subprocess
import tempfile import tempfile
import time import time
import re import re
import json
from six.moves.urllib.parse import urlparse, urljoin from six.moves.urllib.parse import urlparse, urljoin
import pexpect import pexpect
...@@ -50,8 +51,17 @@ setUpModule, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass( ...@@ -50,8 +51,17 @@ setUpModule, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass(
os.path.join(os.path.dirname(__file__), '..', 'software.cfg'))) os.path.join(os.path.dirname(__file__), '..', 'software.cfg')))
class TestTheia(SlapOSInstanceTestCase): class TheiaTestCase(SlapOSInstanceTestCase):
__partition_reference__ = 'T' # for sockets in included slapos __partition_reference__ = 'T' # for supervisord sockets in included slapos
@classmethod
def _getSlapos(cls):
partition_root = cls.computer_partition_root_path
slapos = os.path.join(partition_root, 'srv', 'runner', 'bin', 'slapos')
return slapos
class TestTheia(TheiaTestCase):
def setUp(self): def setUp(self):
self.connection_parameters = self.computer_partition.getConnectionParameterDict() self.connection_parameters = self.computer_partition.getConnectionParameterDict()
...@@ -178,9 +188,7 @@ class TestTheia(SlapOSInstanceTestCase): ...@@ -178,9 +188,7 @@ class TestTheia(SlapOSInstanceTestCase):
self.assertTrue(os.path.exists(script_path)) self.assertTrue(os.path.exists(script_path))
class TestTheiaEmbeddedSlapOSShutdown(SlapOSInstanceTestCase): class TestTheiaEmbeddedSlapOSShutdown(TheiaTestCase):
__partition_reference__ = 'T' # for sockets in included slapos
def test_stopping_instance_stops_embedded_slapos(self): def test_stopping_instance_stops_embedded_slapos(self):
embedded_slapos_supervisord_socket = _getSupervisordSocketPath( embedded_slapos_supervisord_socket = _getSupervisordSocketPath(
os.path.join( os.path.join(
...@@ -212,57 +220,95 @@ class TestTheiaEmbeddedSlapOSShutdown(SlapOSInstanceTestCase): ...@@ -212,57 +220,95 @@ class TestTheiaEmbeddedSlapOSShutdown(SlapOSInstanceTestCase):
self.assertFalse(embedded_slapos_process.is_running()) self.assertFalse(embedded_slapos_process.is_running())
class SQLiteDB(object): class TestTheiaWithSR(TheiaTestCase):
def __init__(self, sqlitedb_file): sr_url = 'bogus/software.cfg'
self.sqlitedb_file = sqlitedb_file sr_type = 'bogus_type'
def select(self, fields, table, where={}):
connection = sqlite3.connect(self.sqlitedb_file)
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
connection.row_factory = dict_factory
cursor = connection.cursor()
condition = " AND ".join("%s='%s'" % (k, v) for k, v in where.items())
cursor.execute(
"SELECT %s FROM %s%s"
% (
", ".join(fields),
table,
" WHERE %s" % condition if where else "",
)
)
return cursor.fetchall()
@classmethod
def getInstanceParameterDict(cls):
return {
'embedded-sr': cls.sr_url,
'embedded-sr-type': cls.sr_type,
}
def test(self):
slapos = self._getSlapos()
info = subprocess.check_output((slapos, 'proxy', 'show'))
instance_name = "Embedded Instance"
self.assertIsNotNone(re.search(r"%s\s+slaprunner\s+available" % (self.sr_url,), info), info)
self.assertIsNotNone(re.search(r"%s\s+%s\s+%s" % (self.sr_url, self.sr_type, instance_name), info), info)
class TestTheiaWithSR(SlapOSInstanceTestCase):
__partition_reference__ = 'T' # for sockets in included slapos
srurl = 'bogus/software.cfg' class TestTheiaEnv(TheiaTestCase):
srtype = 'bogus' dummy_software_path = os.path.abspath('dummy/software.cfg')
@classmethod @classmethod
def getInstanceParameterDict(cls): def getInstanceParameterDict(cls):
return { return {
'embedded-sr': cls.srurl, 'embedded-sr': cls.dummy_software_path,
'embedded-sr-type': cls.srtype, 'autorun': 'stopped',
} }
def test(self): def test_theia_env(self):
db = SQLiteDB(os.path.join(self.computer_partition_root_path, 'srv', 'runner', 'var', 'proxy.db')) # The path of the env.json file expected to be generated by building the dummy software release
supplied = db.select( env_json_path = os.path.join(self.computer_partition_root_path, 'srv', 'runner', 'software', 'env.json')
fields=["*"],
table = "software14", # Get the pid of the theia process from the test node's instance-supervisord
where={'url': self.srurl} with self.slap.instance_supervisor_rpc as supervisor:
) all_process_info = supervisor.getAllProcessInfo()
self.assertEqual(len(supplied), 1) for p in all_process_info:
requested = db.select( if p['name'].startswith('theia-instance'):
fields=["*"], theia_process = p
table = "partition14", break
where={'software_release': self.srurl, 'software_type': self.srtype} else:
) self.fail("Could not find theia process")
self.assertEqual(len(requested), 1) theia_pid = theia_process['pid']
# Get the environment of the theia process
theia_env = psutil.Process(theia_pid).environ()
# Start a theia shell that inherits the environment of the theia process
# This simulates the environment of a shell launched from the browser application
theia_shell_process = pexpect.spawnu('{}/bin/theia-shell'.format(self.computer_partition_root_path), env=theia_env)
theia_shell_process.expect_exact('Standalone SlapOS for computer `slaprunner` activated')
# Launch slapos node software from theia shell
theia_shell_process.sendline('slapos node software')
theia_shell_process.expect('Installing software release %s' % self.dummy_software_path)
theia_shell_process.expect('Finished software releases.')
# Get the theia shell environment
with open(env_json_path) as f:
theia_shell_env = json.load(f)
# Remove the env.json file to later be sure that a new one has been generated
os.remove(env_json_path)
# Launch slapos-node-software from the embedded supervisord
embedded_run_path = os.path.join(self.computer_partition_root_path, 'srv', 'runner', 'var', 'run')
embedded_supervisord_socket_path = _getSupervisordSocketPath(embedded_run_path, self.logger)
with getSupervisorRPC(embedded_supervisord_socket_path) as embedded_supervisor:
previous_stop_time = embedded_supervisor.getProcessInfo('slapos-node-software')['stop']
embedded_supervisor.startProcess('slapos-node-software')
for _retries in range(20):
time.sleep(1)
if embedded_supervisor.getProcessInfo('slapos-node-software')['stop'] != previous_stop_time:
break
else:
self.fail("the supervisord service 'slapos-node-software' takes too long to finish")
# Get the supervisord environment
with open(env_json_path) as f:
supervisord_env = json.load(f)
# Compare relevant variables from both environments
self.maxDiff = None
self.assertEqual(theia_shell_env['PATH'].split(':'), supervisord_env['PATH'].split(':'))
self.assertEqual(theia_shell_env['SLAPOS_CONFIGURATION'], supervisord_env['SLAPOS_CONFIGURATION'])
self.assertEqual(theia_shell_env['SLAPOS_CLIENT_CONFIGURATION'], supervisord_env['SLAPOS_CLIENT_CONFIGURATION'])
self.assertEqual(theia_shell_env['HOME'], supervisord_env['HOME'])
# Cleanup the theia shell process
theia_shell_process.terminate()
theia_shell_process.wait()
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