Repository: docker/docker-py

Issue:
Add 'sysctl' option support
PR docker/docker#19265 merged 'sysctl' support into docker Remote API as of v1.24, but there seems to be no way to use this feature with docker-py. Has anyone started work on such a feature? If not, I will create a PR for a patch that we're using internally.

The sysctl option expects a dictionary of `{ <name>: <value> }` (for example: `{ "net.ipv4.ip_forward": "1" }`), where the types of both objects are of type string. My patch checks if <value> is not a string type, and if that's the case, it casts it using str(). I originally intended to do the casting in docker-compose (for which I have another patch), but now that I've looked closer at the API I believe it belongs in the API. I'm open to debate on that matter though.



Discussion:

Resolving patch:
diff --git a/docker/utils/utils.py b/docker/utils/utils.py
--- a/docker/utils/utils.py
+++ b/docker/utils/utils.py
@@ -619,7 +619,7 @@ def create_host_config(binds=None, port_bindings=None, lxc_conf=None,
                        blkio_weight_device=None, device_read_bps=None,
                        device_write_bps=None, device_read_iops=None,
                        device_write_iops=None, oom_kill_disable=False,
-                       shm_size=None, version=None, tmpfs=None,
+                       shm_size=None, sysctls=None, version=None, tmpfs=None,
                        oom_score_adj=None):
 
     host_config = {}
@@ -725,6 +725,13 @@ def create_host_config(binds=None, port_bindings=None, lxc_conf=None,
 
         host_config['SecurityOpt'] = security_opt
 
+    if sysctls:
+        if not isinstance(sysctls, dict):
+            raise host_config_type_error('sysctls', sysctls, 'dict')
+        host_config['Sysctls'] = {}
+        for k, v in six.iteritems(sysctls):
+            host_config['Sysctls'][k] = six.text_type(v)
+
     if volumes_from is not None:
         if isinstance(volumes_from, six.string_types):
             volumes_from = volumes_from.split(',')


Test patch:
diff --git a/tests/unit/container_test.py b/tests/unit/container_test.py
--- a/tests/unit/container_test.py
+++ b/tests/unit/container_test.py
@@ -1074,6 +1074,33 @@ def test_create_container_with_tmpfs_dict(self):
             DEFAULT_TIMEOUT_SECONDS
         )
 
+    @requires_api_version('1.24')
+    def test_create_container_with_sysctl(self):
+        self.client.create_container(
+            'busybox', 'true',
+            host_config=self.client.create_host_config(
+                sysctls={
+                    'net.core.somaxconn': 1024,
+                    'net.ipv4.tcp_syncookies': '0',
+                }
+            )
+        )
+
+        args = fake_request.call_args
+        self.assertEqual(args[0][1], url_prefix + 'containers/create')
+        expected_payload = self.base_create_payload()
+        expected_payload['HostConfig'] = self.client.create_host_config()
+        expected_payload['HostConfig']['Sysctls'] = {
+            'net.core.somaxconn': '1024', 'net.ipv4.tcp_syncookies': '0',
+        }
+        self.assertEqual(json.loads(args[1]['data']), expected_payload)
+        self.assertEqual(
+            args[1]['headers'], {'Content-Type': 'application/json'}
+        )
+        self.assertEqual(
+            args[1]['timeout'], DEFAULT_TIMEOUT_SECONDS
+        )
+
 
 class ContainerTest(DockerClientTest):
     def test_list_containers(self):