From 97771b1b2bc98560855dca0921ad05f19aa390f4 Mon Sep 17 00:00:00 2001 From: Peter Yu Date: Sat, 9 Nov 2013 16:36:56 +0000 Subject: [PATCH] links implemented. use v1.6 by default now --- docker/client.py | 20 +++++++--- tests/fake_api.py | 4 +- tests/integration_test.py | 69 ++++++++++++++++++++++++++++++++++ tests/test.py | 79 ++++++++++++++++++++++----------------- 4 files changed, 131 insertions(+), 41 deletions(-) diff --git a/docker/client.py b/docker/client.py index 6a187cb5..eab34bbc 100644 --- a/docker/client.py +++ b/docker/client.py @@ -61,7 +61,7 @@ class APIError(requests.exceptions.HTTPError): class Client(requests.Session): - def __init__(self, base_url="unix://var/run/docker.sock", version="1.4"): + def __init__(self, base_url="unix://var/run/docker.sock", version="1.6"): super(Client, self).__init__() if base_url.startswith('unix:///'): base_url = base_url.replace('unix:/', 'unix:') @@ -260,7 +260,7 @@ class Client(requests.Session): 'since': since, 'before': before } - u = self._url("/containers/ps") + u = self._url("/containers/json") res = self._result(self.get(u, params=params), True) if quiet: return [{'Id': x['Id']} for x in res] @@ -492,10 +492,10 @@ class Client(requests.Session): else: return self._result(self._post_json(u, authcfg, stream=False)) - def remove_container(self, container, v=False): + def remove_container(self, container, v=False, link=False): if isinstance(container, dict): container = container.get('Id') - params = {'v': v} + params = {'v': v, 'link': link} res = self.delete(self._url("/containers/" + container), params=params) self._raise_for_status(res) @@ -515,7 +515,8 @@ class Client(requests.Session): return self._result(self.get(self._url("/images/search"), params={'term': term}), True) - def start(self, container, binds=None, port_bindings=None, lxc_conf=None): + def start(self, container, binds=None, port_bindings=None, lxc_conf=None, + links=None): if isinstance(container, dict): container = container.get('Id') @@ -537,6 +538,15 @@ class Client(requests.Session): if port_bindings: start_config['PortBindings'] = port_bindings + if links: + if isinstance(links, dict): + links = [links] + formatted_links = [] + for l in links: + for path in l: + formatted_links.append('{0}:{1}'.format(path, l[path])) + start_config['Links'] = formatted_links + url = self._url("/containers/{0}/start".format(container)) res = self._post_json(url, start_config) self._raise_for_status(res) diff --git a/tests/fake_api.py b/tests/fake_api.py index 1c611daa..6d115663 100644 --- a/tests/fake_api.py +++ b/tests/fake_api.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -CURRENT_VERSION = 'v1.4' +CURRENT_VERSION = 'v1.6' FAKE_CONTAINER_ID = '3cc2351ab11b' FAKE_IMAGE_ID = 'e9aa60c60128' @@ -170,7 +170,7 @@ fake_responses = { get_fake_search, '{1}/{0}/images/json'.format(CURRENT_VERSION, prefix): get_fake_images, - '{1}/{0}/containers/ps'.format(CURRENT_VERSION, prefix): + '{1}/{0}/containers/json'.format(CURRENT_VERSION, prefix): get_fake_containers, '{1}/{0}/containers/3cc2351ab11b/start'.format(CURRENT_VERSION, prefix): post_fake_start_container, diff --git a/tests/integration_test.py b/tests/integration_test.py index 4db21808..9cce1fa3 100644 --- a/tests/integration_test.py +++ b/tests/integration_test.py @@ -435,6 +435,75 @@ class TestRemoveContainerWithDictInsteadOfId(BaseTestCase): res = [x for x in containers if 'Id' in x and x['Id'].startswith(id)] self.assertEqual(len(res), 0) + +class TestStartContainerWithLinks(BaseTestCase): + def runTest(self): + res0 = self.client.create_container( + 'busybox', 'cat', + detach=True, stdin_open=True, + environment={'FOO': '1'}) + + container1_id = res0['Id'] + self.tmp_containers.append(container1_id) + + self.client.start(container1_id) + + # we don't want the first / + link_path = self.client.inspect_container(container1_id)['Name'][1:] + link_alias = 'mylink' + link_env_prefix = link_alias.upper() + + res1 = self.client.create_container('busybox', 'env') + container2_id = res1['Id'] + self.tmp_containers.append(container2_id) + self.client.start(container2_id, links={link_path: link_alias}) + self.assertEqual(self.client.wait(container2_id), 0) + + logs = self.client.logs(container2_id) + self.assertIn('{0}_NAME='.format(link_env_prefix), logs) + self.assertIn('{0}_ENV_FOO=1'.format(link_env_prefix), logs) + +################# +## LINKS TESTS ## +################# + + +class TestRemoveLink(BaseTestCase): + def runTest(self): + # Create containers + container1 = self.client.create_container( + 'busybox', 'cat', detach=True, stdin_open=True) + container1_id = container1['Id'] + self.tmp_containers.append(container1_id) + self.client.start(container1_id) + + # Create Link + # we don't want the first / + link_path = self.client.inspect_container(container1_id)['Name'][1:] + link_alias = 'mylink' + + container2 = self.client.create_container('busybox', 'cat') + container2_id = container2['Id'] + self.tmp_containers.append(container2_id) + self.client.start(container2_id, links={link_path: link_alias}) + + # Remove link + linked_name = self.client.inspect_container(container2_id)['Name'][1:] + link_name = '%s/%s' % (linked_name, link_alias) + self.client.remove_container(link_name, link=True) + + # Link is gone + containers = self.client.containers(all=True) + retrieved = [x for x in containers if link_name in x['Names']] + self.assertEqual(len(retrieved), 0) + + # Containers are still there + retrieved = [ + x for x in containers if x['Id'].startswith(container1_id) + or x['Id'].startswith(container2_id) + ] + self.assertEqual(len(retrieved), 2) + ################## ## IMAGES TESTS ## ################## diff --git a/tests/test.py b/tests/test.py index 4ba0a253..04afeec8 100644 --- a/tests/test.py +++ b/tests/test.py @@ -76,7 +76,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/version' + 'unix://var/run/docker.sock/v1.6/version' ) def test_info(self): @@ -85,7 +85,7 @@ class DockerClientTest(unittest.TestCase): except Exception as e: self.fail('Command should not raise exception: {0}'.format(e)) - fake_request.assert_called_with('unix://var/run/docker.sock/v1.4/info') + fake_request.assert_called_with('unix://var/run/docker.sock/v1.6/info') def test_search(self): try: @@ -94,7 +94,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/images/search', + 'unix://var/run/docker.sock/v1.6/images/search', params={'term': 'busybox'} ) @@ -108,7 +108,7 @@ class DockerClientTest(unittest.TestCase): except Exception as e: self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/images/json', + 'unix://var/run/docker.sock/v1.6/images/json', params={'filter': None, 'only_ids': 0, 'all': 1} ) @@ -119,7 +119,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/images/json', + 'unix://var/run/docker.sock/v1.6/images/json', params={'filter': None, 'only_ids': 1, 'all': 0} ) @@ -130,7 +130,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/ps', + 'unix://var/run/docker.sock/v1.6/containers/json', params={ 'all': 1, 'since': None, @@ -152,7 +152,7 @@ class DockerClientTest(unittest.TestCase): args = fake_request.call_args self.assertEqual(args[0][0], - 'unix://var/run/docker.sock/v1.4/containers/create') + 'unix://var/run/docker.sock/v1.6/containers/create') self.assertEqual(json.loads(args[0][1]), json.loads(''' {"Tty": false, "Image": "busybox", "Cmd": ["true"], @@ -174,7 +174,7 @@ class DockerClientTest(unittest.TestCase): args = fake_request.call_args self.assertEqual(args[0][0], - 'unix://var/run/docker.sock/v1.4/containers/create') + 'unix://var/run/docker.sock/v1.6/containers/create') self.assertEqual(json.loads(args[0][1]), json.loads(''' {"Tty": false, "Image": "busybox", @@ -193,7 +193,7 @@ class DockerClientTest(unittest.TestCase): args = fake_request.call_args self.assertEqual(args[0][0], - 'unix://var/run/docker.sock/v1.4/containers/create') + 'unix://var/run/docker.sock/v1.6/containers/create') self.assertEqual(json.loads(args[0][1]), json.loads(''' {"Tty": false, "Image": "busybox", "Cmd": ["true"], @@ -212,7 +212,7 @@ class DockerClientTest(unittest.TestCase): args = fake_request.call_args self.assertEqual(args[0][0], - 'unix://var/run/docker.sock/v1.4/containers/create') + 'unix://var/run/docker.sock/v1.6/containers/create') self.assertEqual(json.loads(args[0][1]), json.loads(''' {"Tty": false, "Image": "busybox", "Cmd": ["true"], @@ -230,7 +230,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/start', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/start', '{}', headers={'Content-Type': 'application/json'} ) @@ -244,7 +244,7 @@ class DockerClientTest(unittest.TestCase): except Exception as e: self.fail('Command should not raise exception: {0}'.format(e)) args = fake_request.call_args - self.assertEqual(args[0][0], 'unix://var/run/docker.sock/v1.4/' + self.assertEqual(args[0][0], 'unix://var/run/docker.sock/v1.6/' 'containers/3cc2351ab11b/start') self.assertEqual( json.loads(args[0][1]), @@ -262,7 +262,7 @@ class DockerClientTest(unittest.TestCase): except Exception as e: self.fail('Command should not raise exception: {0}'.format(e)) args = fake_request.call_args - self.assertEqual(args[0][0], 'unix://var/run/docker.sock/v1.4/' + self.assertEqual(args[0][0], 'unix://var/run/docker.sock/v1.6/' 'containers/3cc2351ab11b/start') self.assertEqual( json.loads(args[0][1]), @@ -281,7 +281,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/start', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/start', '{"Binds": ["/tmp:/mnt"]}', headers={'Content-Type': 'application/json'} ) @@ -292,7 +292,7 @@ class DockerClientTest(unittest.TestCase): except Exception as e: self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/start', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/start', '{}', headers={'Content-Type': 'application/json'} ) @@ -303,7 +303,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/wait', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/wait', None, timeout=None ) @@ -315,7 +315,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/wait', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/wait', None, timeout=None ) @@ -327,7 +327,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/attach', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/attach', None, params={'logs': 1, 'stderr': 1, 'stdout': 1} ) @@ -339,7 +339,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/attach', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/attach', None, params={'logs': 1, 'stderr': 1, 'stdout': 1} ) @@ -351,7 +351,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/changes') + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/changes') def test_diff_with_dict_instead_of_id(self): try: @@ -360,7 +360,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/changes') + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/changes') def test_stop_container(self): try: @@ -369,7 +369,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/stop', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/stop', None, params={'t': 2} ) @@ -381,7 +381,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/stop', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/stop', None, params={'t': 2} ) @@ -393,7 +393,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/kill', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/kill', None ) @@ -404,7 +404,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/kill', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/kill', None ) @@ -415,7 +415,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception : {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/restart', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/restart', None, params={'t': 2} ) @@ -427,7 +427,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b/restart', + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b/restart', None, params={'t': 2} ) @@ -439,8 +439,8 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b', - params={'v': False} + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b', + params={'v': False, 'link': False} ) def test_remove_container_with_dict_instead_of_id(self): @@ -450,8 +450,19 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/containers/3cc2351ab11b', - params={'v': False} + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b', + params={'v': False, 'link': False} + ) + + def test_remove_link(self): + try: + self.client.remove_container(fake_api.FAKE_CONTAINER_ID, link=True) + except Exception as e: + self.fail('Command should not raise exception: {0}'.format(e)) + + fake_request.assert_called_with( + 'unix://var/run/docker.sock/v1.6/containers/3cc2351ab11b', + params={'v': False, 'link': True} ) ################## @@ -465,7 +476,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/images/create', + 'unix://var/run/docker.sock/v1.6/images/create', headers={}, params={'tag': None, 'fromImage': 'joffrey/test001'}, stream=False @@ -491,7 +502,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/commit', + 'unix://var/run/docker.sock/v1.6/commit', '{}', headers={'Content-Type': 'application/json'}, params={ @@ -510,7 +521,7 @@ class DockerClientTest(unittest.TestCase): self.fail('Command should not raise exception: {0}'.format(e)) fake_request.assert_called_with( - 'unix://var/run/docker.sock/v1.4/images/e9aa60c60128' + 'unix://var/run/docker.sock/v1.6/images/e9aa60c60128' ) #################