From d2ec0d96e75f7a007447f7389e251c85dd4521ba Mon Sep 17 00:00:00 2001 From: tifayuki Date: Thu, 9 Jun 2016 19:58:23 +0200 Subject: [PATCH 1/4] add the support for team and orgs --- dockercloud/__init__.py | 2 ++ dockercloud/api/base.py | 34 ++++++++++++++++++++++++++++------ dockercloud/api/events.py | 7 ++++++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/dockercloud/__init__.py b/dockercloud/__init__.py index 1fd6d63..e970478 100644 --- a/dockercloud/__init__.py +++ b/dockercloud/__init__.py @@ -38,6 +38,8 @@ rest_host = os.environ.get("DOCKERCLOUD_REST_HOST") or 'https://cloud.docker.com/' stream_host = os.environ.get("DOCKERCLOUD_STREAM_HOST") or 'wss://ws.cloud.docker.com/' +namespace = os.environ.get('DOCKERCLOUD_NAMESPACE') + user_agent = None logging.basicConfig() diff --git a/dockercloud/api/base.py b/dockercloud/api/base.py index c6bf3d0..afe32fd 100644 --- a/dockercloud/api/base.py +++ b/dockercloud/api/base.py @@ -58,7 +58,11 @@ def _loaddict(self, dict): assert subsystem, "Subsystem not specified for %s" % self.__class__.__name__ for k, v in list(dict.items()): setattr(self, k, v) - self._detail_uri = "/".join(["api", subsystem, self._api_version, endpoint.strip("/"), self.pk]) + if dockercloud.namespace: + self._detail_uri = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, + endpoint.strip("/"), self.pk]) + else: + self._detail_uri = "/".join(["api", subsystem, self._api_version, endpoint.strip("/"), self.pk]) self.__setchanges__([]) @property @@ -126,7 +130,10 @@ def fetch(cls, pk): subsystem = getattr(cls, 'subsystem', None) assert endpoint, "Endpoint not specified for %s" % cls.__name__ assert subsystem, "Subsystem not specified for %s" % cls.__name__ - detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk]) + if dockercloud.namespace: + detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/"), pk]) + else: + detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk]) json = send_request('GET', detail_uri) if json: instance = cls() @@ -141,7 +148,10 @@ def list(cls, limit=None, **kwargs): assert endpoint, "Endpoint not specified for %s" % cls.__name__ assert subsystem, "Subsystem not specified for %s" % cls.__name__ - detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")]) + if dockercloud.namespace: + detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/")]) + else: + detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")]) objects = [] while True: if limit and len(objects) >= limit: @@ -219,7 +229,10 @@ def save(self): # Figure out whether we should do a create or update if not self._detail_uri: action = "POST" - path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")]) + if dockercloud.namespace: + path = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, endpoint.lstrip("/")]) + else: + path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")]) else: action = "PATCH" path = self._detail_uri @@ -316,7 +329,12 @@ def __init__(self, subsystem, resource, uuid, tail, follow): endpoint = "%s/%s/logs/?follow=%s" % (resource, uuid, str(follow).lower()) if tail: endpoint = "%s&tail=%d" % (endpoint, tail) - url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version, endpoint.lstrip("/")]) + if dockercloud.namespace: + url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version, + dockercloud.namespace, endpoint.lstrip("/")]) + else: + url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version, + endpoint.lstrip("/")]) super(self.__class__, self).__init__(url) @staticmethod @@ -335,7 +353,11 @@ def run_forever(self, *args, **kwargs): class Exec(StreamingAPI): def __init__(self, uuid, cmd='sh'): endpoint = "container/%s/exec/?command=%s" % (uuid, urllib.quote_plus(cmd)) - url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version, endpoint.lstrip("/")]) + if dockercloud.namespace: + url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version, + dockercloud.namespace, endpoint.lstrip("/")]) + else: + url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version, endpoint.lstrip("/")]) super(self.__class__, self).__init__(url) @staticmethod diff --git a/dockercloud/api/events.py b/dockercloud/api/events.py index f84e4aa..06f989a 100644 --- a/dockercloud/api/events.py +++ b/dockercloud/api/events.py @@ -15,7 +15,12 @@ class Events(StreamingAPI): def __init__(self): endpoint = "events" - url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version, endpoint.lstrip("/")]) + if dockercloud.namespace: + url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version, + dockercloud.namespace, endpoint.lstrip("/")]) + else: + url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version, + endpoint.lstrip("/")]) self.invaid_auth_headers = set() self.auth_error = "" super(self.__class__, self).__init__(url) From 655fcce56abd0d3f0da9b52e911636d931157443 Mon Sep 17 00:00:00 2001 From: tifayuki Date: Fri, 10 Jun 2016 11:22:07 +0200 Subject: [PATCH 2/4] bump version --- dockercloud/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockercloud/__init__.py b/dockercloud/__init__.py index e970478..12bb373 100644 --- a/dockercloud/__init__.py +++ b/dockercloud/__init__.py @@ -25,7 +25,7 @@ from dockercloud.api.events import Events from dockercloud.api.nodeaz import AZ -__version__ = '1.0.5' +__version__ = '1.0.6' dockercloud_auth = os.environ.get('DOCKERCLOUD_AUTH') basic_auth = auth.load_from_file("~/.docker/config.json") From 8b79e771d5dadccc093190d1ac839ca2343c663a Mon Sep 17 00:00:00 2001 From: tifayuki Date: Fri, 10 Jun 2016 16:51:14 +0200 Subject: [PATCH 3/4] Update Readme --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 5a82ce2..aea721e 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,19 @@ The authentication can be configured in the following ways: export DOCKERCLOUD_USER=username export DOCKERCLOUD_APIKEY=apikey +## Namespace + +To support teams and orgs, you can specify the namespace in the following ways: + +* Set it in the Python code: + + import dockercloud + dockercloud.namespace = "yourteam" + +* Set it in the environment variable: + + export DOCKERCLOUD_NAMESPACE=yourteam + ## Errors Errors in the HTTP API will be returned with status codes in the 4xx and 5xx ranges. From ef94b85a16eec02f6ff70a94d1d7d7f99e970a16 Mon Sep 17 00:00:00 2001 From: tifayuki Date: Fri, 10 Jun 2016 19:33:14 +0200 Subject: [PATCH 4/4] exclude az,nodetype,provider,region from namespace --- dockercloud/api/base.py | 9 +++++---- dockercloud/api/nodeaz.py | 1 + dockercloud/api/nodeprovider.py | 1 + dockercloud/api/noderegion.py | 1 + dockercloud/api/nodetype.py | 1 + 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dockercloud/api/base.py b/dockercloud/api/base.py index afe32fd..e9feeed 100644 --- a/dockercloud/api/base.py +++ b/dockercloud/api/base.py @@ -22,6 +22,7 @@ def __init__(self, **kwargs): class Restful(BasicObject): _detail_uri = None + namespaced = True def __init__(self, **kwargs): """Simply reflect all the values in kwargs""" @@ -58,7 +59,7 @@ def _loaddict(self, dict): assert subsystem, "Subsystem not specified for %s" % self.__class__.__name__ for k, v in list(dict.items()): setattr(self, k, v) - if dockercloud.namespace: + if self.namespaced and dockercloud.namespace: self._detail_uri = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, endpoint.strip("/"), self.pk]) else: @@ -130,7 +131,7 @@ def fetch(cls, pk): subsystem = getattr(cls, 'subsystem', None) assert endpoint, "Endpoint not specified for %s" % cls.__name__ assert subsystem, "Subsystem not specified for %s" % cls.__name__ - if dockercloud.namespace: + if cls.namespaced and dockercloud.namespace: detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/"), pk]) else: detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk]) @@ -148,7 +149,7 @@ def list(cls, limit=None, **kwargs): assert endpoint, "Endpoint not specified for %s" % cls.__name__ assert subsystem, "Subsystem not specified for %s" % cls.__name__ - if dockercloud.namespace: + if cls.namespaced and dockercloud.namespace: detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/")]) else: detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")]) @@ -229,7 +230,7 @@ def save(self): # Figure out whether we should do a create or update if not self._detail_uri: action = "POST" - if dockercloud.namespace: + if cls.namespaced and dockercloud.namespace: path = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, endpoint.lstrip("/")]) else: path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")]) diff --git a/dockercloud/api/nodeaz.py b/dockercloud/api/nodeaz.py index abc4d5f..25a153b 100644 --- a/dockercloud/api/nodeaz.py +++ b/dockercloud/api/nodeaz.py @@ -6,6 +6,7 @@ class AZ(Immutable): subsystem = "infra" endpoint = "/az" + namespaced = False @classmethod def _pk_key(cls): diff --git a/dockercloud/api/nodeprovider.py b/dockercloud/api/nodeprovider.py index 3d31f06..168bc72 100644 --- a/dockercloud/api/nodeprovider.py +++ b/dockercloud/api/nodeprovider.py @@ -6,6 +6,7 @@ class Provider(Immutable): subsystem = "infra" endpoint = "/provider" + namespaced = False @classmethod def _pk_key(cls): diff --git a/dockercloud/api/noderegion.py b/dockercloud/api/noderegion.py index 4d10bed..9a9c97a 100644 --- a/dockercloud/api/noderegion.py +++ b/dockercloud/api/noderegion.py @@ -6,6 +6,7 @@ class Region(Immutable): subsystem = "infra" endpoint = "/region" + namespaced = False @classmethod def _pk_key(cls): diff --git a/dockercloud/api/nodetype.py b/dockercloud/api/nodetype.py index 5274aaf..7416d63 100644 --- a/dockercloud/api/nodetype.py +++ b/dockercloud/api/nodetype.py @@ -6,6 +6,7 @@ class NodeType(Immutable): subsystem = "infra" endpoint = "/nodetype" + namespaced = False @classmethod def _pk_key(cls):