You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by an...@apache.org on 2016/12/27 08:36:40 UTC

libcloud git commit: Allow Passing in Full API URL to Rancher Driver

Repository: libcloud
Updated Branches:
  refs/heads/trunk 5e153d03c -> 88a59541e


Allow Passing in Full API URL to Rancher Driver

The scheme (secure) and port no longer need to be explicitly specified.
Closes #958


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/88a59541
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/88a59541
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/88a59541

Branch: refs/heads/trunk
Commit: 88a59541e28e11a01941fdac2acf1fedb0f45594
Parents: 5e153d0
Author: Matthew Ellison <ma...@arroyonetworks.com>
Authored: Mon Dec 12 19:27:21 2016 -0500
Committer: Anthony Shaw <an...@apache.org>
Committed: Tue Dec 27 19:36:22 2016 +1100

----------------------------------------------------------------------
 libcloud/container/drivers/rancher.py   |  71 +++++----
 libcloud/test/container/test_rancher.py | 218 +++++++++++++++++----------
 2 files changed, 181 insertions(+), 108 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/88a59541/libcloud/container/drivers/rancher.py
----------------------------------------------------------------------
diff --git a/libcloud/container/drivers/rancher.py b/libcloud/container/drivers/rancher.py
index eda0058..9bd87e6 100644
--- a/libcloud/container/drivers/rancher.py
+++ b/libcloud/container/drivers/rancher.py
@@ -20,7 +20,7 @@ try:
 except:
     import json
 
-from libcloud.utils.py3 import httplib
+from libcloud.utils.py3 import httplib, urlparse
 from libcloud.utils.py3 import b
 
 from libcloud.common.base import JsonResponse, ConnectionUserAndKey
@@ -85,22 +85,13 @@ class RancherConnection(ConnectionUserAndKey):
 
 
 class RancherContainerDriver(ContainerDriver):
+    """
+    Driver for Rancher by Rancher Labs.
 
-    type = Provider.RANCHER
-    name = 'Rancher'
-    website = 'http://rancher.com'
-    connectionCls = RancherConnection
-    # Holding off on cluster support for now.
-    # Only Environment API interaction enabled.
-    supports_clusters = False
-    # As in the /v1/
-    version = '1'
-
-    def __init__(self, key, secret, secure=True, host='localhost', port=443):
-        """
-        Rancher Container driver class.
+    This driver is capable of interacting with the Version 1 API of Rancher.
+    It currently does NOT support the Version 2 API.
 
-        Example:
+    Example:
 
         >>> from libcloud.container.providers import get_driver
         >>> from libcloud.container.types import Provider
@@ -114,6 +105,24 @@ class RancherContainerDriver(ContainerDriver):
         >>> newcontainer = connection.deploy_container("myawesomepastebin",
         image, environment={"STORAGE_TYPE": "file"})
 
+    :ivar   baseuri: The URL base path to the API.
+    :type   baseuri: ``str``
+    """
+
+    type = Provider.RANCHER
+    name = 'Rancher'
+    website = 'http://rancher.com'
+    connectionCls = RancherConnection
+    # Holding off on cluster support for now.
+    # Only Environment API interaction enabled.
+    supports_clusters = False
+    # As in the /v1/
+    version = '1'
+
+    def __init__(self, key, secret, secure=True, host='localhost', port=443):
+        """
+        Creates a new Rancher Container driver.
+
         :param    key: API key or username to used (required)
         :type     key: ``str``
 
@@ -123,32 +132,30 @@ class RancherContainerDriver(ContainerDriver):
         :param    secure: Whether to use HTTPS or HTTP.
         :type     secure: ``bool``
 
-        :param    host: Override hostname used for connections.
+        :param    host: Override hostname used for connections. This can also
+         be a full URL string, including scheme, port, and base path.
         :type     host: ``str``
 
         :param    port: Override port used for connections.
         :type     port: ``int``
 
-
-        :return: ``None``
+        :return: A newly initialized driver instance.
         """
 
-        if host.startswith('http://'):
-            secure = False
-
-        super(RancherContainerDriver, self).__init__(key=key, secret=secret,
-                                                     secure=secure, host=host,
-                                                     port=port)
+        # Parse the Given Host
+        if '://' not in host and not host.startswith("//"):
+            host = '//' + host
+        parsed = urlparse.urlparse(host)
 
-        # strip the prefix
-        prefixes = ['http://', 'https://']
-        for prefix in prefixes:
-            if host.startswith(prefix):
-                host = host.strip(prefix)
+        super(RancherContainerDriver, self).__init__(
+            key=key,
+            secret=secret,
+            secure=False if parsed.scheme == 'http' else secure,
+            host=parsed.hostname,
+            port=parsed.port if parsed.port else port
+        )
 
-        # We only support environment api keys, meaning none of this:
-        # self.baseuri = "/v%s/projects/%s" % (self.version, project_id)
-        self.baseuri = "/v%s" % self.version
+        self.baseuri = parsed.path if parsed.path else "/v%s" % self.version
 
     def ex_list_stacks(self):
         """

http://git-wip-us.apache.org/repos/asf/libcloud/blob/88a59541/libcloud/test/container/test_rancher.py
----------------------------------------------------------------------
diff --git a/libcloud/test/container/test_rancher.py b/libcloud/test/container/test_rancher.py
index eb23ddf..a2997e4 100644
--- a/libcloud/test/container/test_rancher.py
+++ b/libcloud/test/container/test_rancher.py
@@ -26,13 +26,151 @@ from libcloud.test.file_fixtures import ContainerFileFixtures
 from libcloud.test import MockHttp
 
 
+# --------------------------------------------------------------------------- #
+# Mock Classes
+
+class RancherMockHttp(MockHttp):
+    fixtures = ContainerFileFixtures('rancher')
+
+    def _v1_environments(self, method, url, body, headers):
+        if method == 'GET':
+            return (httplib.OK, self.fixtures.load('ex_list_stacks.json'), {},
+                    httplib.responses[httplib.OK])
+        else:
+            return (httplib.OK, self.fixtures.load('ex_deploy_stack.json'), {},
+                    httplib.responses[httplib.OK])
+
+    def _v1_environments_1e9(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ex_deploy_stack.json'), {},
+                httplib.responses[httplib.OK])
+
+    def _v1_environments_1e10(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ex_destroy_stack.json'), {},
+                httplib.responses[httplib.OK])
+
+    def _v1_environments_1e1(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ex_activate_stack.json'), {},
+                httplib.responses[httplib.OK])
+
+    def _v1_services(self, method, url, body, headers):
+        if '?healthState=healthy' in url:
+            return (httplib.OK, self.fixtures.load('ex_search_services.json'),
+                    {}, httplib.responses[httplib.OK])
+        elif method == 'GET':
+            return (httplib.OK, self.fixtures.load('ex_list_services.json'),
+                    {}, httplib.responses[httplib.OK])
+        else:
+            return (httplib.OK, self.fixtures.load('ex_deploy_service.json'),
+                    {}, httplib.responses[httplib.OK])
+
+    def _v1_services_1s13(self, method, url, body, headers):
+        if method == 'GET':
+            return (httplib.OK, self.fixtures.load('ex_deploy_service.json'),
+                    {}, httplib.responses[httplib.OK])
+        elif method == 'DELETE':
+            return (httplib.OK, self.fixtures.load('ex_destroy_service.json'),
+                    {}, httplib.responses[httplib.OK])
+
+    def _v1_services_1s6(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ex_activate_service.json'), {},
+                httplib.responses[httplib.OK])
+
+    def _v1_containers(self, method, url, body, headers):
+        if '?state=running' in url:
+            return (httplib.OK,
+                    self.fixtures.load('ex_search_containers.json'), {},
+                    httplib.responses[httplib.OK])
+        elif method == 'POST':
+            return (httplib.OK, self.fixtures.load('deploy_container.json'),
+                    {}, httplib.responses[httplib.OK])
+        return (httplib.OK, self.fixtures.load('list_containers.json'), {},
+                httplib.responses[httplib.OK])
+
+    def _v1_containers_1i31(self, method, url, body, headers):
+        if method == 'GET':
+            return (httplib.OK, self.fixtures.load('deploy_container.json'),
+                    {}, httplib.responses[httplib.OK])
+        elif method == 'DELETE' or '?action=stop' in url:
+            return (httplib.OK, self.fixtures.load('stop_container.json'), {},
+                    httplib.responses[httplib.OK])
+        elif '?action=start' in url:
+            return (httplib.OK, self.fixtures.load('start_container.json'), {},
+                    httplib.responses[httplib.OK])
+        else:
+            return (httplib.OK, self.fixtures.load('deploy_container.json'),
+                    {}, httplib.responses[httplib.OK])
+
+
+RancherContainerDriver.connectionCls.conn_classes = (
+    RancherMockHttp, RancherMockHttp
+)
+RancherMockHttp.type = None
+RancherMockHttp.use_param = 'a'
+
+
+# --------------------------------------------------------------------------- #
+# Test Cases
+
+
+class RancherContainerDriverInitTestCase(unittest.TestCase):
+    """
+    Tests for testing the different permutations of the driver initialization
+    string.
+    """
+
+    def test_full_url_string(self):
+        """
+        Test a 'full' URL string, which contains a scheme, port, and base path.
+        """
+        path = "http://myhostname:1234/base"
+        driver = RancherContainerDriver(*CONTAINER_PARAMS_RANCHER, host=path)
+
+        self.assertEqual(driver.secure, False)
+        self.assertEqual(driver.connection.host, "myhostname")
+        self.assertEqual(driver.connection.port, 1234)
+        self.assertEqual(driver.baseuri, "/base")
+
+    def test_url_string_no_port(self):
+        """
+        Test a partial URL string, which contains a scheme, and base path.
+        """
+        path = "http://myhostname/base"
+        driver = RancherContainerDriver(*CONTAINER_PARAMS_RANCHER, host=path,
+                                        port=1234)
+
+        self.assertEqual(driver.secure, False)
+        self.assertEqual(driver.connection.host, "myhostname")
+        self.assertEqual(driver.connection.port, 1234)
+        self.assertEqual(driver.baseuri, "/base")
+
+    def test_url_string_no_scheme(self):
+        """
+        Test a partial URL string, which contains a port, and base path.
+        """
+        path = "myhostname:1234/base"
+        driver = RancherContainerDriver(*CONTAINER_PARAMS_RANCHER, host=path)
+
+        self.assertEqual(driver.secure, True)
+        self.assertEqual(driver.connection.host, "myhostname")
+        self.assertEqual(driver.connection.port, 1234)
+        self.assertEqual(driver.baseuri, "/base")
+
+    def test_url_string_no_base_path(self):
+        """
+        Test a partial URL string, which contains a scheme, and a port.
+        """
+        path = "http://myhostname:1234"
+        driver = RancherContainerDriver(*CONTAINER_PARAMS_RANCHER, host=path)
+
+        self.assertEqual(driver.secure, False)
+        self.assertEqual(driver.connection.host, "myhostname")
+        self.assertEqual(driver.connection.port, 1234)
+        self.assertEqual(driver.baseuri, "/v%s" % driver.version)
+
+
 class RancherContainerDriverTestCase(unittest.TestCase):
 
     def setUp(self):
-        RancherContainerDriver.connectionCls.conn_classes = (
-            RancherMockHttp, RancherMockHttp)
-        RancherMockHttp.type = None
-        RancherMockHttp.use_param = 'a'
         self.driver = RancherContainerDriver(*CONTAINER_PARAMS_RANCHER)
 
     # Stacks
@@ -186,77 +324,5 @@ class RancherContainerDriverTestCase(unittest.TestCase):
         self.assertEqual(destroyed.extra['state'], "stopping")
 
 
-class RancherMockHttp(MockHttp):
-    fixtures = ContainerFileFixtures('rancher')
-
-    def _v1_environments(self, method, url, body, headers):
-        if method == 'GET':
-            return (httplib.OK, self.fixtures.load('ex_list_stacks.json'), {},
-                    httplib.responses[httplib.OK])
-        else:
-            return (httplib.OK, self.fixtures.load('ex_deploy_stack.json'), {},
-                    httplib.responses[httplib.OK])
-
-    def _v1_environments_1e9(self, method, url, body, headers):
-        return (httplib.OK, self.fixtures.load('ex_deploy_stack.json'), {},
-                httplib.responses[httplib.OK])
-
-    def _v1_environments_1e10(self, method, url, body, headers):
-        return (httplib.OK, self.fixtures.load('ex_destroy_stack.json'), {},
-                httplib.responses[httplib.OK])
-
-    def _v1_environments_1e1(self, method, url, body, headers):
-        return (httplib.OK, self.fixtures.load('ex_activate_stack.json'), {},
-                httplib.responses[httplib.OK])
-
-    def _v1_services(self, method, url, body, headers):
-        if '?healthState=healthy' in url:
-            return (httplib.OK, self.fixtures.load('ex_search_services.json'),
-                    {}, httplib.responses[httplib.OK])
-        elif method == 'GET':
-            return (httplib.OK, self.fixtures.load('ex_list_services.json'),
-                    {}, httplib.responses[httplib.OK])
-        else:
-            return (httplib.OK, self.fixtures.load('ex_deploy_service.json'),
-                    {}, httplib.responses[httplib.OK])
-
-    def _v1_services_1s13(self, method, url, body, headers):
-        if method == 'GET':
-            return (httplib.OK, self.fixtures.load('ex_deploy_service.json'),
-                    {}, httplib.responses[httplib.OK])
-        elif method == 'DELETE':
-            return (httplib.OK, self.fixtures.load('ex_destroy_service.json'),
-                    {}, httplib.responses[httplib.OK])
-
-    def _v1_services_1s6(self, method, url, body, headers):
-        return (httplib.OK, self.fixtures.load('ex_activate_service.json'), {},
-                httplib.responses[httplib.OK])
-
-    def _v1_containers(self, method, url, body, headers):
-        if '?state=running' in url:
-            return (httplib.OK,
-                    self.fixtures.load('ex_search_containers.json'), {},
-                    httplib.responses[httplib.OK])
-        elif method == 'POST':
-            return (httplib.OK, self.fixtures.load('deploy_container.json'),
-                    {}, httplib.responses[httplib.OK])
-        return (httplib.OK, self.fixtures.load('list_containers.json'), {},
-                httplib.responses[httplib.OK])
-
-    def _v1_containers_1i31(self, method, url, body, headers):
-        if method == 'GET':
-            return (httplib.OK, self.fixtures.load('deploy_container.json'),
-                    {}, httplib.responses[httplib.OK])
-        elif method == 'DELETE' or '?action=stop' in url:
-            return (httplib.OK, self.fixtures.load('stop_container.json'), {},
-                    httplib.responses[httplib.OK])
-        elif '?action=start' in url:
-            return (httplib.OK, self.fixtures.load('start_container.json'), {},
-                    httplib.responses[httplib.OK])
-        else:
-            return (httplib.OK, self.fixtures.load('deploy_container.json'),
-                    {}, httplib.responses[httplib.OK])
-
-
 if __name__ == '__main__':
     sys.exit(unittest.main())