Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
shell: add a way to set environment variables (#50)
Browse files Browse the repository at this point in the history
* shell: add a way to set environment variables

Add a new config dictionary in the `shell` key: `environment`. All
values in this dictionary are passed to LXD's config under the
"environment.*" config type.

We set this config when `shell` is called, which is a bit at odds with
the rest of the container config, which is usually set at creation time.
We do this so that a user who fiddles with her `lxdock.yml` file doesn't
have to restart/recreate her container to benefit from the change she's
just made. They will be effective on the next `lxdock shell` call.

* Change shell-env test's container name in test_container

It apparently prevents it from passing.

* shell-env: coerce env values into strings

Otherwise, we can set env variables to values like "42" without
explicitly quoting them in our yaml.

* Widen the scope of the "environment" config

Rather than being specific to `shell`, `environment` is now a top-level
configuration and it now affects both `provision` and `shell`.
  • Loading branch information
Virgil Dupras authored and ellmetha committed Apr 2, 2017
1 parent 8fb692b commit 0b55166
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
21 changes: 19 additions & 2 deletions docs/conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ containers, as follows:
- name: test01
- name: test02
environment
-----------

A mapping of environment variables to override in the container when executing commands. This will
affect ``lxdock shell`` and ``lxdock provision`` operations.

.. code-block:: yaml
name: myproject
image: ubuntu/xenial
environment:
LC_ALL: en_US.utf8
hostnames
---------

Expand Down Expand Up @@ -211,8 +225,11 @@ of shared items. Each shared item should define a ``source`` (a path on your hos
shell
-----

The ``shell`` option allows you to define the user to use when doing a ``lxdock shell``. This allows
you to have a shell for a specific user/home directory when doing ``lxdock shell``:
The ``shell`` option alters the behavior of the ``lxdock shell`` command. It's a map of these
sub-options:

* ``user``: Default user to open the shell under.
* ``home``: Path to open the shell under.

.. code-block:: yaml
Expand Down
3 changes: 2 additions & 1 deletion lxdock/conf/schema.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from voluptuous import All, Any, In, IsDir, Length, Required, Schema, Url
from voluptuous import All, Any, Coerce, Extra, In, IsDir, Length, Required, Schema, Url

from ..provisioners import Provisioner

from .validators import Hostname, LXDIdentifier


_top_level_and_containers_common_options = {
'environment': {Extra: Coerce(str)},
'hostnames': [Hostname(), ],
'image': str,
'mode': In(['local', 'pull', ]),
Expand Down
17 changes: 17 additions & 0 deletions lxdock/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ def halt(self):
@must_be_running
def provision(self, barebone=None):
""" Provisions the container. """
# We run this in case our lxdock.yml config was modified since our last `lxdock up`.
self._setup_env()

if barebone is None: # None == only if the container isn't provisioned.
barebone = not self.is_provisioned

Expand Down Expand Up @@ -104,6 +107,9 @@ def provision(self, barebone=None):
@must_be_running
def shell(self, username=None):
""" Opens a new interactive shell in the container. """
# We run this in case our lxdock.yml config was modified since our last `lxdock up`.
self._setup_env()

# For now, it's much easier to call `lxc`, but eventually, we might want to contribute
# to pylxd so it supports `interactive = True` in `exec()`.
shellcfg = self.options.get('shell', {})
Expand Down Expand Up @@ -145,6 +151,9 @@ def up(self):
# Setup shares if applicable.
self._setup_shares()

# Override environment variables
self._setup_env()

# Provisions the container if applicable.
if not self.is_provisioned:
self.provision(barebone=True)
Expand Down Expand Up @@ -291,6 +300,14 @@ def _perform_barebones_setup(self):
else:
logger.warning('SSH pubkey was not found. Provisioning tools may not work correctly...')

def _setup_env(self):
""" Add environment overrides from the conf to our container config. """
env_override = self.options.get('environment')
if env_override:
for key, value in env_override.items():
self._container.config['environment.{}'.format(key)] = str(value)
self._container.save(wait=True)

def _setup_hostnames(self, ip):
""" Configure the potential hostnames associated with the container. """
hostnames = self.options.get('hostnames', [])
Expand Down
13 changes: 13 additions & 0 deletions tests/integration/test_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ def test_can_open_a_shell_for_a_specific_shelluser(self, mocked_call):
assert mocked_call.call_args[0][0] == \
'lxc exec {} --env HOME=/opt -- su -m test'.format(container.lxd_name)

@unittest.mock.patch('subprocess.call')
def test_can_set_shell_environment_variables(self, mocked_call):
# Environment variables in the shell can be set through configuration.
container_options = {
'name': self.containername('shell-env'), 'image': 'ubuntu/xenial',
'environment': {'FOO': 'bar', 'BAR': 42},
}
container = Container('myproject', THIS_DIR, self.client, **container_options)
container.up()
container.shell()
assert container._container.config['environment.FOO'] == 'bar'
assert container._container.config['environment.BAR'] == '42'

def test_can_tell_if_a_container_exists_or_not(self, persistent_container):
unknown_container = Container('myproject', THIS_DIR, self.client, **{
'name': self.containername('unknown'), 'image': 'ubuntu/xenial', 'mode': 'pull', })
Expand Down

0 comments on commit 0b55166

Please sign in to comment.