add namespace to all apis
This commit is contained in:
parent
e9658aae73
commit
256de5d2cc
27 changed files with 248 additions and 204 deletions
|
|
@ -6,7 +6,7 @@ from .base import Immutable, StreamingLog
|
|||
class Action(Immutable):
|
||||
subsystem = 'audit'
|
||||
endpoint = "/action"
|
||||
namespaced = False
|
||||
is_namespaced = False
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from .http import send_request
|
|||
|
||||
HUB_INDEX = "https://index.docker.io/v1/"
|
||||
|
||||
|
||||
def authenticate(username, password):
|
||||
verify_credential(username, password)
|
||||
dockercloud.basic_auth = base64.b64encode("%s:%s" % (username, password))
|
||||
|
|
@ -55,7 +56,8 @@ def load_from_file(f="~/.docker/config.json"):
|
|||
p = subprocess.Popen([cmd, 'get'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
out = p.communicate(input=HUB_INDEX)[0]
|
||||
except:
|
||||
raise dockercloud.AuthError('error getting credentials - err: exec: "%s": executable file not found in $PATH, out: ``' % cmd)
|
||||
raise dockercloud.AuthError(
|
||||
'error getting credentials - err: exec: "%s": executable file not found in $PATH, out: ``' % cmd)
|
||||
|
||||
try:
|
||||
credential = json.loads(out)
|
||||
|
|
|
|||
|
|
@ -16,18 +16,19 @@ logger = logging.getLogger("python-dockercloud")
|
|||
class BasicObject(object):
|
||||
_api_version = 'v1'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class Restful(BasicObject):
|
||||
_detail_uri = None
|
||||
namespaced = True
|
||||
is_namespaced = True
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, namespace="", **kwargs):
|
||||
"""Simply reflect all the values in kwargs"""
|
||||
for k, v in list(kwargs.items()):
|
||||
setattr(self, k, v)
|
||||
if self.is_namespaced and namespace:
|
||||
self._namespace = namespace
|
||||
else:
|
||||
self._namespace = dockercloud.namespace
|
||||
self._resource_uri = ""
|
||||
|
||||
def __addchanges__(self, name):
|
||||
changed_attrs = self.__getchanges__()
|
||||
|
|
@ -38,7 +39,7 @@ class Restful(BasicObject):
|
|||
def __setattr__(self, name, value):
|
||||
"""Keeps track of what attributes have been set"""
|
||||
current_value = getattr(self, name, None)
|
||||
if value != current_value:
|
||||
if value != current_value and not name.startswith("_"):
|
||||
self.__addchanges__(name)
|
||||
super(Restful, self).__setattr__(name, value)
|
||||
|
||||
|
|
@ -53,17 +54,10 @@ class Restful(BasicObject):
|
|||
|
||||
def _loaddict(self, dict):
|
||||
"""Internal. Sets the model attributes to the dictionary values passed"""
|
||||
endpoint = getattr(self, 'endpoint', None)
|
||||
subsystem = getattr(self, 'subsystem', None)
|
||||
assert endpoint, "Endpoint not specified for %s" % self.__class__.__name__
|
||||
assert subsystem, "Subsystem not specified for %s" % self.__class__.__name__
|
||||
for k, v in list(dict.items()):
|
||||
setattr(self, k, v)
|
||||
if self.namespaced and 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._resource_uri = getattr(self, "resource_uri", None)
|
||||
self.__setchanges__([])
|
||||
|
||||
@property
|
||||
|
|
@ -93,9 +87,9 @@ class Restful(BasicObject):
|
|||
def _perform_action(self, action, params=None, data={}):
|
||||
"""Internal. Performs the specified action on the object remotely"""
|
||||
success = False
|
||||
if not self._detail_uri:
|
||||
if not self._resource_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
path = "/".join([self._detail_uri.rstrip("/"), action.lstrip("/")])
|
||||
path = "/".join([self._resource_uri.rstrip("/"), action.lstrip("/")])
|
||||
json = send_request("POST", path, params=params, data=data)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
|
|
@ -104,9 +98,9 @@ class Restful(BasicObject):
|
|||
|
||||
def _expand_attribute(self, attribute):
|
||||
"""Internal. Expands the given attribute from remote information"""
|
||||
if not self._detail_uri:
|
||||
if not self._resource_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
path = "/".join([self._detail_uri, attribute])
|
||||
path = "/".join([self._resource_uri, attribute])
|
||||
json = send_request("GET", path)
|
||||
if json:
|
||||
return json[attribute]
|
||||
|
|
@ -125,39 +119,43 @@ class Restful(BasicObject):
|
|||
|
||||
class Immutable(Restful):
|
||||
@classmethod
|
||||
def fetch(cls, pk):
|
||||
instance = None
|
||||
def fetch(cls, pk, namespace=""):
|
||||
endpoint = getattr(cls, 'endpoint', None)
|
||||
subsystem = getattr(cls, 'subsystem', None)
|
||||
assert endpoint, "Endpoint not specified for %s" % cls.__name__
|
||||
assert subsystem, "Subsystem not specified for %s" % cls.__name__
|
||||
if cls.namespaced and dockercloud.namespace:
|
||||
detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/"), pk])
|
||||
|
||||
if not namespace:
|
||||
namespace = dockercloud.namespace
|
||||
if cls.is_namespaced and namespace:
|
||||
resource_uri = "/".join(["api", subsystem, cls._api_version, namespace, endpoint.strip("/"), pk])
|
||||
else:
|
||||
detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk])
|
||||
json = send_request('GET', detail_uri)
|
||||
resource_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk])
|
||||
json = send_request('GET', resource_uri)
|
||||
if json:
|
||||
instance = cls()
|
||||
instance._loaddict(json)
|
||||
return instance
|
||||
|
||||
@classmethod
|
||||
def list(cls, limit=None, **kwargs):
|
||||
def list(cls, limit=None, namespace="", **kwargs):
|
||||
restful = []
|
||||
endpoint = getattr(cls, 'endpoint', None)
|
||||
subsystem = getattr(cls, 'subsystem', None)
|
||||
assert endpoint, "Endpoint not specified for %s" % cls.__name__
|
||||
assert subsystem, "Subsystem not specified for %s" % cls.__name__
|
||||
|
||||
if cls.namespaced and dockercloud.namespace:
|
||||
detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/")])
|
||||
if not namespace:
|
||||
namespace = dockercloud.namespace
|
||||
if cls.is_namespaced and namespace:
|
||||
resource_uri = "/".join(["api", subsystem, cls._api_version, namespace, endpoint.strip("/")])
|
||||
else:
|
||||
detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")])
|
||||
resource_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")])
|
||||
objects = []
|
||||
while True:
|
||||
if limit and len(objects) >= limit:
|
||||
break
|
||||
json = send_request('GET', detail_uri, params=kwargs)
|
||||
json = send_request('GET', resource_uri, params=kwargs)
|
||||
objs = json.get('objects', [])
|
||||
meta = json.get('meta', {})
|
||||
next_url = meta.get('next', '')
|
||||
|
|
@ -182,10 +180,10 @@ class Immutable(Restful):
|
|||
if self.is_dirty and not force:
|
||||
# We have local non-committed changes - rejecting the refresh
|
||||
success = False
|
||||
elif not self._detail_uri:
|
||||
elif not self._resource_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
else:
|
||||
json = send_request("GET", self._detail_uri)
|
||||
json = send_request("GET", self._resource_uri)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
success = True
|
||||
|
|
@ -202,16 +200,17 @@ class Mutable(Immutable):
|
|||
return cls(**kwargs)
|
||||
|
||||
def delete(self):
|
||||
if not self._detail_uri:
|
||||
if not self._resource_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
action = "DELETE"
|
||||
url = self._detail_uri
|
||||
url = self._resource_uri
|
||||
json = send_request(action, url)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
self._resource_uri = None
|
||||
else:
|
||||
# Object deleted successfully and nothing came back - deleting PK reference.
|
||||
self._detail_uri = None
|
||||
self._resource_uri = None
|
||||
# setattr(self, self._pk_key(), None) -- doesn't work
|
||||
self.__setchanges__([])
|
||||
return True
|
||||
|
|
@ -228,15 +227,15 @@ class Mutable(Immutable):
|
|||
assert endpoint, "Endpoint not specified for %s" % self.__class__.__name__
|
||||
assert subsystem, "Subsystem not specified for %s" % self.__class__.__name__
|
||||
# Figure out whether we should do a create or update
|
||||
if not self._detail_uri:
|
||||
if not self._resource_uri:
|
||||
action = "POST"
|
||||
if cls.namespaced and dockercloud.namespace:
|
||||
path = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, endpoint.lstrip("/")])
|
||||
if cls.is_namespaced and self._namespace:
|
||||
path = "/".join(["api", subsystem, self._api_version, self._namespace, endpoint.lstrip("/")])
|
||||
else:
|
||||
path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")])
|
||||
else:
|
||||
action = "PATCH"
|
||||
path = self._detail_uri
|
||||
path = self._resource_uri
|
||||
# Construct the necessary params
|
||||
params = {}
|
||||
for attr in self.__getchanges__():
|
||||
|
|
@ -322,13 +321,16 @@ class StreamingAPI(BasicObject):
|
|||
|
||||
|
||||
class StreamingLog(StreamingAPI):
|
||||
def __init__(self, subsystem, resource, uuid, tail, follow):
|
||||
def __init__(self, subsystem, resource, uuid, tail, follow, namespace=""):
|
||||
endpoint = "%s/%s/logs/?follow=%s" % (resource, uuid, str(follow).lower())
|
||||
if tail:
|
||||
endpoint = "%s&tail=%d" % (endpoint, tail)
|
||||
if dockercloud.namespace:
|
||||
|
||||
if not namespace:
|
||||
namespace = dockercloud.namespace
|
||||
if namespace:
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version,
|
||||
dockercloud.namespace, endpoint.lstrip("/")])
|
||||
self._namespace, endpoint.lstrip("/")])
|
||||
else:
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version,
|
||||
endpoint.lstrip("/")])
|
||||
|
|
@ -348,11 +350,13 @@ class StreamingLog(StreamingAPI):
|
|||
|
||||
|
||||
class Exec(StreamingAPI):
|
||||
def __init__(self, uuid, cmd='sh'):
|
||||
def __init__(self, uuid, cmd='sh', namespace=""):
|
||||
endpoint = "container/%s/exec/?command=%s" % (uuid, urllib.quote_plus(cmd))
|
||||
if dockercloud.namespace:
|
||||
if not namespace:
|
||||
namespace = dockercloud.namespace
|
||||
if namespace:
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version,
|
||||
dockercloud.namespace, endpoint.lstrip("/")])
|
||||
namespace, endpoint.lstrip("/")])
|
||||
else:
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version, endpoint.lstrip("/")])
|
||||
super(self.__class__, self).__init__(url)
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@ logger = logging.getLogger("python-dockercloud")
|
|||
|
||||
|
||||
class Events(StreamingAPI):
|
||||
def __init__(self):
|
||||
def __init__(self, namespace=""):
|
||||
endpoint = "events"
|
||||
if dockercloud.namespace:
|
||||
|
||||
if not namespace:
|
||||
namespace = dockercloud.namespace
|
||||
if namespace:
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version,
|
||||
dockercloud.namespace, endpoint.lstrip("/")])
|
||||
namespace, endpoint.lstrip("/")])
|
||||
else:
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version,
|
||||
endpoint.lstrip("/")])
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class Node(Mutable, Taggable):
|
|||
endpoint = "/node"
|
||||
|
||||
def save(self):
|
||||
if not self._detail_uri:
|
||||
if not self.resource_uri:
|
||||
raise AttributeError("Adding a new node is not supported via 'save' method")
|
||||
super(Node, self).save()
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from .base import Immutable
|
|||
class AZ(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/az"
|
||||
namespaced = False
|
||||
is_namespaced = False
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class NodeCluster(Mutable, Taggable):
|
|||
def create(cls, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
if key == "node_type" and isinstance(value, NodeType):
|
||||
kwargs[key] = getattr(value, "resource_uri", "")
|
||||
kwargs[key] = getattr(value, "_resource_uri", "")
|
||||
if key == "region" and isinstance(value, Region):
|
||||
kwargs[key] = getattr(value, "resource_uri", "")
|
||||
kwargs[key] = getattr(value, "_resource_uri", "")
|
||||
return cls(**kwargs)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from .base import Immutable
|
|||
class Provider(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/provider"
|
||||
namespaced = False
|
||||
is_namespaced = False
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from .base import Immutable
|
|||
class Region(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/region"
|
||||
namespaced = False
|
||||
is_namespaced = False
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from .base import Immutable
|
|||
class NodeType(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/nodetype"
|
||||
namespaced = False
|
||||
is_namespaced = False
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class Stack(Mutable):
|
|||
return self._perform_action("redeploy", params=params)
|
||||
|
||||
def export(self):
|
||||
if not self._detail_uri:
|
||||
if not self.resource_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
url = "/".join([self._detail_uri, "export"])
|
||||
url = "/".join([self.resource_uri, "export"])
|
||||
return send_request("GET", url, inject_header=False)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class Tag(BasicObject):
|
|||
def fetch(cls, taggable):
|
||||
if not isinstance(taggable, Taggable):
|
||||
raise ApiError("The object does not support tag")
|
||||
if not taggable._detail_uri:
|
||||
if not taggable.resource_uri:
|
||||
raise ApiError("You must save the taggable object before performing this operation")
|
||||
|
||||
tag = cls()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from .http import send_request
|
|||
class Trigger(BasicObject):
|
||||
def __init__(self):
|
||||
self.trigger = None
|
||||
self.resource_uri = None
|
||||
|
||||
def add(self, name=None, operation=None):
|
||||
|
||||
|
|
@ -30,11 +31,11 @@ class Trigger(BasicObject):
|
|||
return cls(**kwargs)
|
||||
|
||||
def delete(self, uuid):
|
||||
if not self.endpoint:
|
||||
if not self.resource_uri:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
action = "DELETE"
|
||||
url = "/".join([self.endpoint, uuid])
|
||||
url = "/".join([self.resource_uri, uuid])
|
||||
send_request(action, url)
|
||||
return True
|
||||
|
||||
|
|
@ -43,11 +44,11 @@ class Trigger(BasicObject):
|
|||
if not isinstance(triggerable, Triggerable):
|
||||
raise ApiError("The object does not support trigger")
|
||||
|
||||
if not triggerable._detail_uri:
|
||||
if not triggerable.resource_uri:
|
||||
raise ApiError("You must save the triggerable object before performing this operation")
|
||||
|
||||
trigger = cls()
|
||||
trigger.endpoint = "/".join([triggerable._detail_uri, "trigger"])
|
||||
trigger.resource_uri = "/".join([triggerable.resource_uri, "trigger"])
|
||||
handlers = []
|
||||
for t in trigger.list():
|
||||
triggername = t.get("name", "")
|
||||
|
|
@ -56,12 +57,12 @@ class Trigger(BasicObject):
|
|||
return trigger
|
||||
|
||||
def list(self, **kwargs):
|
||||
if not self.endpoint:
|
||||
if not self.resource_uri:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
objects = []
|
||||
while True:
|
||||
json = send_request('GET', self.endpoint, params=kwargs)
|
||||
json = send_request('GET', self.resource_uri, params=kwargs)
|
||||
objs = json.get('objects', [])
|
||||
meta = json.get('meta', {})
|
||||
next_url = meta.get('next', '')
|
||||
|
|
@ -77,23 +78,23 @@ class Trigger(BasicObject):
|
|||
return objects
|
||||
|
||||
def save(self):
|
||||
if not self.endpoint:
|
||||
if not self.resource_uri:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
if self.trigger is None:
|
||||
return True
|
||||
|
||||
json = send_request("POST", self.endpoint, data=json_parser.dumps(self.trigger))
|
||||
json = send_request("POST", self.resource_uri, data=json_parser.dumps(self.trigger))
|
||||
if json:
|
||||
self.clear()
|
||||
self.clear()
|
||||
return True
|
||||
|
||||
def call(self, uuid):
|
||||
if not self.endpoint:
|
||||
if not self.resource_uri:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
json = send_request("POST", "/".join([self.endpoint, uuid + "/call"]))
|
||||
json = send_request("POST", "/".join([self.resource_uri, uuid + "/call"]))
|
||||
if json:
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Utils:
|
|||
return Action.fetch(id)
|
||||
else:
|
||||
raise ApiError(
|
||||
"Unsupported resource type. Only support: action, container, node, nodecluster, service, stack")
|
||||
"Unsupported resource type. Only support: action, container, node, nodecluster, service, stack")
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_container(identifier, raise_exceptions=True):
|
||||
|
|
@ -162,7 +162,7 @@ class Utils:
|
|||
elif len(objects_same_identifier) == 0:
|
||||
raise ObjectNotFound("Cannot find a node cluster with the identifier '%s'" % identifier)
|
||||
raise NonUniqueIdentifier(
|
||||
"More than one node cluster has the same identifier, please use the long uuid")
|
||||
"More than one node cluster has the same identifier, please use the long uuid")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
|
|
@ -185,7 +185,7 @@ class Utils:
|
|||
elif len(objects_same_identifier) == 0:
|
||||
raise ObjectNotFound("Cannot find an action cluster with the identifier '%s'" % identifier)
|
||||
raise NonUniqueIdentifier(
|
||||
"More than one action has the same identifier, please use the long uuid")
|
||||
"More than one action has the same identifier, please use the long uuid")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue