Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions doc/source/configuration.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _configuration:

Configuration
=============

Expand Down Expand Up @@ -40,28 +42,24 @@ docker setup.
.. literalinclude:: remoteappmanager_help.txt

When **remoteappmanager** is started from jupyterhub using the spawner,
all the command line options are filled in, with the config file path
default to `remoteappmanager_config.py` in the current directory.

It is possible to change this location by specifying::
all the command line options are filled in automatically.

c.Spawner.config_file_path = "/path/to/config.py"

in the `jupyterhub_config.py` file. Note that this config file will be used by
all remoteappmanagers for any user.
2. Config file

The **remoteappmanager** has a number of parameters configurable via a
config file. The path of the config file should be specified in the
spawner in `jupyterhub_config.py`::

2. Config file
c.Spawner.config_file_path = "/path/to/config.py"

Path to the config file is given by the `--config-file-path` command-line
option. It is a Python file in which default values of attributes in
:py:class:`remoteappmanager.file_config.FileConfig` can be override.
Please refer to :py:class:`remoteappmanager.file_config.FileConfig` for
the configurable parameters. Note that this config file will be used
by all remoteappmanagers for any user.

For example, to use CSV as the database, one could provide a config file
with the following settings::
For example, to use CSV as the database, `/path/to/config.py` would
contain the followings::

accounting_class = 'remoteappmanager.db.csv_db.CSVAccounting'
accounting_kwargs = {'url': '/path/to/csv_file'}

Please refer to :py:class:`remoteappmanager.file_config.FileConfig` for
the configurable parameters.
4 changes: 2 additions & 2 deletions doc/source/deployment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ Deployment of the complete system in a single machine/VM.

cd ../jupyterhub

and verify that `jupyterhub_config.py` and `remoteappmanager_config.py` are
correct for your deployment machine setup.
and verify that `jupyterhub_config.py` is correct for your deployment
machine setup (see :ref:`configuration`).

Setup docker containers
-----------------------
Expand Down
5 changes: 0 additions & 5 deletions jupyterhub/jupyterhub_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import os

# Configuration file for jupyterhub.
from jupyter_client.localinterfaces import public_ips

Expand All @@ -16,9 +14,6 @@
if setting_mode == 'virtual_user':
c.JupyterHub.spawner_class = 'remoteappmanager.spawner.VirtualUserSpawner'

c.Spawner.config_file_path = os.path.abspath(
'./remoteappmanager_config.py')

# Parent directory in which temporary directory is created for
# each virtual user
# Set this to a drive with well defined capacity quota
Expand Down
18 changes: 11 additions & 7 deletions remoteappmanager/__main__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import sys
import sys # pragma: no cover

from remoteappmanager.command_line_config import CommandLineConfig
from remoteappmanager.file_config import FileConfig
from tornado.options import print_help
from remoteappmanager.command_line_config import (
CommandLineConfig) # pragma: no cover
from remoteappmanager.file_config import FileConfig # pragma: no cover
from tornado.options import print_help # pragma: no cover

from remoteappmanager.application import Application
from remoteappmanager.application import Application # pragma: no cover


def main():
def main(): # pragma: no cover
command_line_config = CommandLineConfig()

try:
command_line_config.parse_config()
file_config = FileConfig()
file_config.parse_config(command_line_config.config_file)

if command_line_config.config_file:
file_config.parse_config(command_line_config.config_file)

except Exception as e:
print_help()
print("Error: {}".format(e))
Expand Down
4 changes: 0 additions & 4 deletions remoteappmanager/file_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ def parse_config(self, config_file):
"""Parses the config file, and assign their values to our local traits.
"""

if config_file.strip() == '':
raise tornado.options.Error("Config file must be specified "
"in command line arguments.")

# Keep the file line parser isolated, but use the global one
# so that we can get the help of the command line options.
file_line_parser = tornado.options.OptionParser()
Expand Down
19 changes: 9 additions & 10 deletions remoteappmanager/spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import shutil
import tempfile

from traitlets import Any, Unicode, default
from traitlets import Any, Unicode
from tornado import gen

from jupyterhub.spawner import LocalProcessSpawner
Expand Down Expand Up @@ -44,7 +44,10 @@ def get_args(self):
args[iarg] = arg.replace('--base-url=', '--base-urlpath=')

args.append("--proxy-api-url={}".format(self.proxy.api_server.url))
args.append("--config-file={}".format(self.config_file_path))

if self.config_file_path:
args.append("--config-file={}".format(self.config_file_path))

return args

def get_env(self):
Expand All @@ -53,13 +56,6 @@ def get_env(self):
env.update(_docker_envvars())
return env

@default("config_file_path")
def _config_file_path_default(self):
"""Defines the default position of the configuration file for
our utility. By default, it's the cwd of where we started up."""
return os.path.join(os.getcwd(),
os.path.basename(self.cmd[0])+'_config.py')


class VirtualUserSpawner(LocalProcessSpawner):
''' Start remoteappmanager as a local process for a virtual user.
Expand Down Expand Up @@ -128,7 +124,10 @@ def get_args(self):
args[iarg] = arg.replace('--base-url=', '--base-urlpath=')

args.append("--proxy-api-url={}".format(self.proxy.api_server.url))
args.append("--config-file={}".format(self.config_file_path))

if self.config_file_path:
args.append("--config-file={}".format(self.config_file_path))

return args

def user_env(self, env):
Expand Down
28 changes: 19 additions & 9 deletions tests/spawner/test_spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ def new_spawner(spawner_class):
return spawner_class(db=db, user=user, hub=hub)


class TestSpawner(testing.AsyncTestCase):
class TestSpawner(TempMixin, testing.AsyncTestCase):
def setUp(self):
self.spawner = new_spawner(Spawner)
super().setUp()
self.spawner = new_spawner(Spawner)

def test_args(self):
path = fixtures.get("remoteappmanager_config.py")
Expand All @@ -85,13 +85,17 @@ def test_args(self):
self.assertIn("--config-file={}".format(path), args)
self.assertIn("--base-urlpath=/", args)

def test_args_without_config_file_path(self):
args = self.spawner.get_args()
self.assertIn("--proxy-api-url=http://127.0.0.1:12345/foo/bar/", args)
self.assertFalse(any("--config-file=" in arg for arg in args))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or you could "config-file" in " ".join(args)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I think that loops over the content ofargs twice? any returns True for the first True (although if the test should pass, it loops over the whole thing, once).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you seriously talking performance on a test that checks if a string is present in a 100 bytes string?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😈

self.assertIn("--base-urlpath=/", args)

def test_cmd(self):
self.assertEqual(self.spawner.cmd, ['remoteappmanager'])

def test_default_config_file_path(self):
self.assertEqual(self.spawner.config_file_path,
os.path.join(os.getcwd(),
"remoteappmanager_config.py"))
self.assertEqual(self.spawner.config_file_path, "")

def test_env(self):
env = self.spawner.get_env()
Expand Down Expand Up @@ -125,7 +129,7 @@ def test_cmd_spawning(self):
exc.output.decode(sys.getdefaultencoding())))
raise

def test_spawner_start_and_stop(self):
def test_spawner_start_and_stop_with_config_file(self):
path = fixtures.get("remoteappmanager_config.py")
self.spawner.config_file_path = path

Expand All @@ -136,13 +140,19 @@ def test_spawner_start_and_stop(self):
status = self.io_loop.run_sync(self.spawner.poll)
self.assertEqual(status, 1)

def test_spawner_start_and_stop_without_config_file(self):
with spawner_start_and_stop(self.io_loop, self.spawner):
status = self.io_loop.run_sync(self.spawner.poll)
self.assertIsNone(status)

status = self.io_loop.run_sync(self.spawner.poll)
self.assertEqual(status, 1)

class TestVirtualUserSpawner(TempMixin, testing.AsyncTestCase):

class TestVirtualUserSpawner(TestSpawner):
def setUp(self):
super().setUp()
self.spawner = new_spawner(VirtualUserSpawner)
path = fixtures.get("remoteappmanager_config.py")
self.spawner.config_file_path = path

def test_spawner_without_workspace_dir(self):
with spawner_start_and_stop(self.io_loop, self.spawner):
Expand Down