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 @@
[instance]
filename = instance.cfg.in
md5sum = e56a6722e4f0bc958f6b61f13174e852
md5sum = ab61eeb45300a91c0c4fb42bd5c52c9f
[yarn.lock]
filename = yarn.lock
......
......@@ -279,6 +279,23 @@ location = $${directory:frontend-static}/$${:filename}
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
# -------------
......@@ -300,12 +317,13 @@ template =
export THEIA_OPEN_EDITOR_TOKEN=$(${openssl:location}/bin/openssl rand -hex 32)
export THEIA_URL=$${:base-url}
export THEIA_SHELL=$${theia-shell:rendered}
export HOME=$${buildout:directory}
export TMP=$${directory:tmp}
export TEMP=$TMP
export LC_ALL=C.UTF-8
export TERMINFO=${ncurses:location}/lib/terminfo/
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} $@
ip = $${theia-service-port:ip}
port = $${theia-service-port:port}
......@@ -392,7 +410,9 @@ rendered = $${directory:bin}/$${:_buildout_section_name_}
mode = 0700
template =
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} \
$${directory:runner} \
$${slapos-standalone-config:ipv4} \
......
......@@ -299,7 +299,8 @@ install +=
[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]
recipe = slapos.recipe.template:jinja2
......@@ -307,12 +308,7 @@ rendered = ${buildout:bin-directory}/${:_buildout_section_name_}
mode = 0777
template =
inline:
#!/bin/bash
. ${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='$ '
#!/bin/sh
cd ${theia:location}
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
import tempfile
import time
import re
import json
from six.moves.urllib.parse import urlparse, urljoin
import pexpect
......@@ -50,8 +51,17 @@ setUpModule, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass(
os.path.join(os.path.dirname(__file__), '..', 'software.cfg')))
class TestTheia(SlapOSInstanceTestCase):
__partition_reference__ = 'T' # for sockets in included slapos
class TheiaTestCase(SlapOSInstanceTestCase):
__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):
self.connection_parameters = self.computer_partition.getConnectionParameterDict()
......@@ -178,9 +188,7 @@ class TestTheia(SlapOSInstanceTestCase):
self.assertTrue(os.path.exists(script_path))
class TestTheiaEmbeddedSlapOSShutdown(SlapOSInstanceTestCase):
__partition_reference__ = 'T' # for sockets in included slapos
class TestTheiaEmbeddedSlapOSShutdown(TheiaTestCase):
def test_stopping_instance_stops_embedded_slapos(self):
embedded_slapos_supervisord_socket = _getSupervisordSocketPath(
os.path.join(
......@@ -212,57 +220,95 @@ class TestTheiaEmbeddedSlapOSShutdown(SlapOSInstanceTestCase):
self.assertFalse(embedded_slapos_process.is_running())
class SQLiteDB(object):
def __init__(self, sqlitedb_file):
self.sqlitedb_file = sqlitedb_file
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()
class TestTheiaWithSR(TheiaTestCase):
sr_url = 'bogus/software.cfg'
sr_type = 'bogus_type'
@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'
srtype = 'bogus'
class TestTheiaEnv(TheiaTestCase):
dummy_software_path = os.path.abspath('dummy/software.cfg')
@classmethod
def getInstanceParameterDict(cls):
return {
'embedded-sr': cls.srurl,
'embedded-sr-type': cls.srtype,
'embedded-sr': cls.dummy_software_path,
'autorun': 'stopped',
}
def test(self):
db = SQLiteDB(os.path.join(self.computer_partition_root_path, 'srv', 'runner', 'var', 'proxy.db'))
supplied = db.select(
fields=["*"],
table = "software14",
where={'url': self.srurl}
)
self.assertEqual(len(supplied), 1)
requested = db.select(
fields=["*"],
table = "partition14",
where={'software_release': self.srurl, 'software_type': self.srtype}
)
self.assertEqual(len(requested), 1)
def test_theia_env(self):
# The path of the env.json file expected to be generated by building the dummy software release
env_json_path = os.path.join(self.computer_partition_root_path, 'srv', 'runner', 'software', 'env.json')
# Get the pid of the theia process from the test node's instance-supervisord
with self.slap.instance_supervisor_rpc as supervisor:
all_process_info = supervisor.getAllProcessInfo()
for p in all_process_info:
if p['name'].startswith('theia-instance'):
theia_process = p
break
else:
self.fail("Could not find theia process")
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