From 18c2cc49d74788c6e883e9037dc6f4eb92f4e1d4 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Tue, 3 Sep 2024 21:01:39 +0200 Subject: [PATCH] Feature/added ipc flag (#285) * Add IPC support to RockerExtension - Introduced a new IPC class that extends RockerExtension to handle IPC namespace options. - Implemented `get_name` to return the 'ipc' identifier. - Added `get_docker_args` method to generate Docker IPC arguments based on CLI input. - Included a `get_preamble` method that returns an empty string as no preamble is needed. This commit enables the use of IPC-related Docker arguments in Rocker configurations. * :zap: basic test for ipc for high coverage --------- Co-authored-by: Tully Foote --- README.md | 2 +- setup.py | 1 + src/rocker/extensions.py | 75 ++++++++++++++++++++++++++-------------- test/test_extension.py | 34 ++++++++++++++++++ 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index bef60f6..faea049 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ You can get full details on the extensions from the main `rocker --help` command - pulse -- Mount pulse audio into the container - ssh -- Pass through ssh access to the container. -As well as access to many of the docker arguments as well such as `device`, `env`, `volume`, `name`, `network`, and `privileged`. +As well as access to many of the docker arguments as well such as `device`, `env`, `volume`, `name`, `network`, `ipc`, and `privileged`. ### Externally maintained extensions diff --git a/setup.py b/setup.py index 5ba172e..4d66983 100644 --- a/setup.py +++ b/setup.py @@ -54,6 +54,7 @@ 'group_add = rocker.extensions:GroupAdd', 'home = rocker.extensions:HomeDir', 'hostname = rocker.extensions:Hostname', + 'ipc = rocker.extensions:Ipc', 'name = rocker.extensions:Name', 'network = rocker.extensions:Network', 'nvidia = rocker.nvidia_extension:Nvidia', diff --git a/src/rocker/extensions.py b/src/rocker/extensions.py index bf5e773..6d66ec6 100644 --- a/src/rocker/extensions.py +++ b/src/rocker/extensions.py @@ -91,6 +91,32 @@ def register_arguments(parser, defaults={}): help="add development tools emacs and byobu to your environment") +class Expose(RockerExtension): + @staticmethod + def get_name(): + return 'expose' + + def __init__(self): + self.name = Expose.get_name() + + def get_preamble(self, cliargs): + return '' + + def get_docker_args(self, cliargs): + args = [''] + ports = cliargs.get('expose', []) + for port in ports: + args.append(' --expose {0}'.format(port)) + return ' '.join(args) + + @staticmethod + def register_arguments(parser, defaults={}): + parser.add_argument('--expose', + default=defaults.get('expose', None), + action='append', + help="Exposes a port from the container to host machine.") + + class Hostname(RockerExtension): @staticmethod def get_name(): @@ -114,6 +140,29 @@ def register_arguments(parser, defaults={}): parser.add_argument('--hostname', default=defaults.get('hostname', ''), help='Hostname of the container.') + +class Ipc(RockerExtension): + @staticmethod + def get_name(): + return 'ipc' + def __init__(self): + self.name = Ipc.get_name() + + def get_preamble(self, cliargs): + return '' + + def get_docker_args(self, cliargs): + args = '' + ipc = cliargs.get('ipc', None) + args += ' --ipc %s ' % ipc + return args + + @staticmethod + def register_arguments(parser, defaults={}): + parser.add_argument('--ipc', default=defaults.get('ipc', None), + help='IPC namespace to use. To share ipc with the host use host. More details can be found at https://docs.docker.com/reference/cli/docker/container/run/#ipc') + + class Name(RockerExtension): @staticmethod def get_name(): @@ -163,32 +212,6 @@ def register_arguments(parser, defaults={}): help="What network configuration to use.") -class Expose(RockerExtension): - @staticmethod - def get_name(): - return 'expose' - - def __init__(self): - self.name = Expose.get_name() - - def get_preamble(self, cliargs): - return '' - - def get_docker_args(self, cliargs): - args = [''] - ports = cliargs.get('expose', []) - for port in ports: - args.append(' --expose {0}'.format(port)) - return ' '.join(args) - - @staticmethod - def register_arguments(parser, defaults={}): - parser.add_argument('--expose', - default=defaults.get('expose', None), - action='append', - help="Exposes a port from the container to host machine.") - - class Port(RockerExtension): @staticmethod def get_name(): diff --git a/test/test_extension.py b/test/test_extension.py index 446c692..57eab1e 100644 --- a/test/test_extension.py +++ b/test/test_extension.py @@ -114,6 +114,40 @@ def test_home_extension(self): args = p.get_docker_args(mock_cliargs) self.assertTrue('-v %s:%s' % (Path.home(), Path.home()) in args) + +class IpcExtensionTest(unittest.TestCase): + + def setUp(self): + # Work around interference between empy Interpreter + # stdout proxy and test runner. empy installs a proxy on stdout + # to be able to capture the information. + # And the test runner creates a new stdout object for each test. + # This breaks empy as it assumes that the proxy has persistent + # between instances of the Interpreter class + # empy will error with the exception + # "em.Error: interpreter stdout proxy lost" + em.Interpreter._wasProxyInstalled = False + + @pytest.mark.docker + def test_ipc_extension(self): + plugins = list_plugins() + ipc_plugin = plugins['ipc'] + self.assertEqual(ipc_plugin.get_name(), 'ipc') + + p = ipc_plugin() + self.assertTrue(plugin_load_parser_correctly(ipc_plugin)) + + mock_cliargs = {'ipc': 'none'} + self.assertEqual(p.get_snippet(mock_cliargs), '') + self.assertEqual(p.get_preamble(mock_cliargs), '') + args = p.get_docker_args(mock_cliargs) + self.assertTrue('--ipc none' in args) + + mock_cliargs = {'ipc': 'host'} + args = p.get_docker_args(mock_cliargs) + self.assertTrue('--ipc host' in args) + + class NetworkExtensionTest(unittest.TestCase): def setUp(self):