add namespace to all apis

This commit is contained in:
tifayuki 2016-11-16 14:24:50 -08:00
commit 256de5d2cc
27 changed files with 248 additions and 204 deletions

View file

@ -6,7 +6,7 @@ from .base import Immutable, StreamingLog
class Action(Immutable): class Action(Immutable):
subsystem = 'audit' subsystem = 'audit'
endpoint = "/action" endpoint = "/action"
namespaced = False is_namespaced = False
@classmethod @classmethod
def _pk_key(cls): def _pk_key(cls):

View file

@ -12,6 +12,7 @@ from .http import send_request
HUB_INDEX = "https://index.docker.io/v1/" HUB_INDEX = "https://index.docker.io/v1/"
def authenticate(username, password): def authenticate(username, password):
verify_credential(username, password) verify_credential(username, password)
dockercloud.basic_auth = base64.b64encode("%s:%s" % (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) p = subprocess.Popen([cmd, 'get'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
out = p.communicate(input=HUB_INDEX)[0] out = p.communicate(input=HUB_INDEX)[0]
except: 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: try:
credential = json.loads(out) credential = json.loads(out)

View file

@ -16,18 +16,19 @@ logger = logging.getLogger("python-dockercloud")
class BasicObject(object): class BasicObject(object):
_api_version = 'v1' _api_version = 'v1'
def __init__(self, **kwargs):
pass
class Restful(BasicObject): class Restful(BasicObject):
_detail_uri = None is_namespaced = True
namespaced = True
def __init__(self, **kwargs): def __init__(self, namespace="", **kwargs):
"""Simply reflect all the values in kwargs""" """Simply reflect all the values in kwargs"""
for k, v in list(kwargs.items()): for k, v in list(kwargs.items()):
setattr(self, k, v) 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): def __addchanges__(self, name):
changed_attrs = self.__getchanges__() changed_attrs = self.__getchanges__()
@ -38,7 +39,7 @@ class Restful(BasicObject):
def __setattr__(self, name, value): def __setattr__(self, name, value):
"""Keeps track of what attributes have been set""" """Keeps track of what attributes have been set"""
current_value = getattr(self, name, None) current_value = getattr(self, name, None)
if value != current_value: if value != current_value and not name.startswith("_"):
self.__addchanges__(name) self.__addchanges__(name)
super(Restful, self).__setattr__(name, value) super(Restful, self).__setattr__(name, value)
@ -53,17 +54,10 @@ class Restful(BasicObject):
def _loaddict(self, dict): def _loaddict(self, dict):
"""Internal. Sets the model attributes to the dictionary values passed""" """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()): for k, v in list(dict.items()):
setattr(self, k, v) setattr(self, k, v)
if self.namespaced and dockercloud.namespace:
self._detail_uri = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, self._resource_uri = getattr(self, "resource_uri", None)
endpoint.strip("/"), self.pk])
else:
self._detail_uri = "/".join(["api", subsystem, self._api_version, endpoint.strip("/"), self.pk])
self.__setchanges__([]) self.__setchanges__([])
@property @property
@ -93,9 +87,9 @@ class Restful(BasicObject):
def _perform_action(self, action, params=None, data={}): def _perform_action(self, action, params=None, data={}):
"""Internal. Performs the specified action on the object remotely""" """Internal. Performs the specified action on the object remotely"""
success = False success = False
if not self._detail_uri: if not self._resource_uri:
raise ApiError("You must save the object before performing this operation") 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) json = send_request("POST", path, params=params, data=data)
if json: if json:
self._loaddict(json) self._loaddict(json)
@ -104,9 +98,9 @@ class Restful(BasicObject):
def _expand_attribute(self, attribute): def _expand_attribute(self, attribute):
"""Internal. Expands the given attribute from remote information""" """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") 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) json = send_request("GET", path)
if json: if json:
return json[attribute] return json[attribute]
@ -125,39 +119,43 @@ class Restful(BasicObject):
class Immutable(Restful): class Immutable(Restful):
@classmethod @classmethod
def fetch(cls, pk): def fetch(cls, pk, namespace=""):
instance = None
endpoint = getattr(cls, 'endpoint', None) endpoint = getattr(cls, 'endpoint', None)
subsystem = getattr(cls, 'subsystem', None) subsystem = getattr(cls, 'subsystem', None)
assert endpoint, "Endpoint not specified for %s" % cls.__name__ assert endpoint, "Endpoint not specified for %s" % cls.__name__
assert subsystem, "Subsystem 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: else:
detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk]) resource_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk])
json = send_request('GET', detail_uri) json = send_request('GET', resource_uri)
if json: if json:
instance = cls() instance = cls()
instance._loaddict(json) instance._loaddict(json)
return instance return instance
@classmethod @classmethod
def list(cls, limit=None, **kwargs): def list(cls, limit=None, namespace="", **kwargs):
restful = [] restful = []
endpoint = getattr(cls, 'endpoint', None) endpoint = getattr(cls, 'endpoint', None)
subsystem = getattr(cls, 'subsystem', None) subsystem = getattr(cls, 'subsystem', None)
assert endpoint, "Endpoint not specified for %s" % cls.__name__ assert endpoint, "Endpoint not specified for %s" % cls.__name__
assert subsystem, "Subsystem not specified for %s" % cls.__name__ assert subsystem, "Subsystem not specified for %s" % cls.__name__
if cls.namespaced and dockercloud.namespace: if not namespace:
detail_uri = "/".join(["api", subsystem, cls._api_version, dockercloud.namespace, endpoint.strip("/")]) namespace = dockercloud.namespace
if cls.is_namespaced and namespace:
resource_uri = "/".join(["api", subsystem, cls._api_version, namespace, endpoint.strip("/")])
else: else:
detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")]) resource_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/")])
objects = [] objects = []
while True: while True:
if limit and len(objects) >= limit: if limit and len(objects) >= limit:
break break
json = send_request('GET', detail_uri, params=kwargs) json = send_request('GET', resource_uri, params=kwargs)
objs = json.get('objects', []) objs = json.get('objects', [])
meta = json.get('meta', {}) meta = json.get('meta', {})
next_url = meta.get('next', '') next_url = meta.get('next', '')
@ -182,10 +180,10 @@ class Immutable(Restful):
if self.is_dirty and not force: if self.is_dirty and not force:
# We have local non-committed changes - rejecting the refresh # We have local non-committed changes - rejecting the refresh
success = False success = False
elif not self._detail_uri: elif not self._resource_uri:
raise ApiError("You must save the object before performing this operation") raise ApiError("You must save the object before performing this operation")
else: else:
json = send_request("GET", self._detail_uri) json = send_request("GET", self._resource_uri)
if json: if json:
self._loaddict(json) self._loaddict(json)
success = True success = True
@ -202,16 +200,17 @@ class Mutable(Immutable):
return cls(**kwargs) return cls(**kwargs)
def delete(self): def delete(self):
if not self._detail_uri: if not self._resource_uri:
raise ApiError("You must save the object before performing this operation") raise ApiError("You must save the object before performing this operation")
action = "DELETE" action = "DELETE"
url = self._detail_uri url = self._resource_uri
json = send_request(action, url) json = send_request(action, url)
if json: if json:
self._loaddict(json) self._loaddict(json)
self._resource_uri = None
else: else:
# Object deleted successfully and nothing came back - deleting PK reference. # 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 # setattr(self, self._pk_key(), None) -- doesn't work
self.__setchanges__([]) self.__setchanges__([])
return True return True
@ -228,15 +227,15 @@ class Mutable(Immutable):
assert endpoint, "Endpoint not specified for %s" % self.__class__.__name__ assert endpoint, "Endpoint not specified for %s" % self.__class__.__name__
assert subsystem, "Subsystem 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 # Figure out whether we should do a create or update
if not self._detail_uri: if not self._resource_uri:
action = "POST" action = "POST"
if cls.namespaced and dockercloud.namespace: if cls.is_namespaced and self._namespace:
path = "/".join(["api", subsystem, self._api_version, dockercloud.namespace, endpoint.lstrip("/")]) path = "/".join(["api", subsystem, self._api_version, self._namespace, endpoint.lstrip("/")])
else: else:
path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")]) path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")])
else: else:
action = "PATCH" action = "PATCH"
path = self._detail_uri path = self._resource_uri
# Construct the necessary params # Construct the necessary params
params = {} params = {}
for attr in self.__getchanges__(): for attr in self.__getchanges__():
@ -322,13 +321,16 @@ class StreamingAPI(BasicObject):
class StreamingLog(StreamingAPI): 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()) endpoint = "%s/%s/logs/?follow=%s" % (resource, uuid, str(follow).lower())
if tail: if tail:
endpoint = "%s&tail=%d" % (endpoint, 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, url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version,
dockercloud.namespace, endpoint.lstrip("/")]) self._namespace, endpoint.lstrip("/")])
else: else:
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version, url = "/".join([dockercloud.stream_host.rstrip("/"), "api", subsystem, self._api_version,
endpoint.lstrip("/")]) endpoint.lstrip("/")])
@ -348,11 +350,13 @@ class StreamingLog(StreamingAPI):
class Exec(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)) 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, url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version,
dockercloud.namespace, endpoint.lstrip("/")]) namespace, endpoint.lstrip("/")])
else: else:
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version, endpoint.lstrip("/")]) url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "app", self._api_version, endpoint.lstrip("/")])
super(self.__class__, self).__init__(url) super(self.__class__, self).__init__(url)

View file

@ -13,11 +13,14 @@ logger = logging.getLogger("python-dockercloud")
class Events(StreamingAPI): class Events(StreamingAPI):
def __init__(self): def __init__(self, namespace=""):
endpoint = "events" endpoint = "events"
if dockercloud.namespace:
if not namespace:
namespace = dockercloud.namespace
if namespace:
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version, url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version,
dockercloud.namespace, endpoint.lstrip("/")]) namespace, endpoint.lstrip("/")])
else: else:
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version, url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version,
endpoint.lstrip("/")]) endpoint.lstrip("/")])

View file

@ -8,7 +8,7 @@ class Node(Mutable, Taggable):
endpoint = "/node" endpoint = "/node"
def save(self): 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") raise AttributeError("Adding a new node is not supported via 'save' method")
super(Node, self).save() super(Node, self).save()

View file

@ -6,7 +6,7 @@ from .base import Immutable
class AZ(Immutable): class AZ(Immutable):
subsystem = "infra" subsystem = "infra"
endpoint = "/az" endpoint = "/az"
namespaced = False is_namespaced = False
@classmethod @classmethod
def _pk_key(cls): def _pk_key(cls):

View file

@ -16,7 +16,7 @@ class NodeCluster(Mutable, Taggable):
def create(cls, **kwargs): def create(cls, **kwargs):
for key, value in kwargs.items(): for key, value in kwargs.items():
if key == "node_type" and isinstance(value, NodeType): 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): if key == "region" and isinstance(value, Region):
kwargs[key] = getattr(value, "resource_uri", "") kwargs[key] = getattr(value, "_resource_uri", "")
return cls(**kwargs) return cls(**kwargs)

View file

@ -6,7 +6,7 @@ from .base import Immutable
class Provider(Immutable): class Provider(Immutable):
subsystem = "infra" subsystem = "infra"
endpoint = "/provider" endpoint = "/provider"
namespaced = False is_namespaced = False
@classmethod @classmethod
def _pk_key(cls): def _pk_key(cls):

View file

@ -6,7 +6,7 @@ from .base import Immutable
class Region(Immutable): class Region(Immutable):
subsystem = "infra" subsystem = "infra"
endpoint = "/region" endpoint = "/region"
namespaced = False is_namespaced = False
@classmethod @classmethod
def _pk_key(cls): def _pk_key(cls):

View file

@ -6,7 +6,7 @@ from .base import Immutable
class NodeType(Immutable): class NodeType(Immutable):
subsystem = "infra" subsystem = "infra"
endpoint = "/nodetype" endpoint = "/nodetype"
namespaced = False is_namespaced = False
@classmethod @classmethod
def _pk_key(cls): def _pk_key(cls):

View file

@ -20,7 +20,7 @@ class Stack(Mutable):
return self._perform_action("redeploy", params=params) return self._perform_action("redeploy", params=params)
def export(self): def export(self):
if not self._detail_uri: if not self.resource_uri:
raise ApiError("You must save the object before performing this operation") 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) return send_request("GET", url, inject_header=False)

View file

@ -57,7 +57,7 @@ class Tag(BasicObject):
def fetch(cls, taggable): def fetch(cls, taggable):
if not isinstance(taggable, Taggable): if not isinstance(taggable, Taggable):
raise ApiError("The object does not support tag") 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") raise ApiError("You must save the taggable object before performing this operation")
tag = cls() tag = cls()

View file

@ -8,6 +8,7 @@ from .http import send_request
class Trigger(BasicObject): class Trigger(BasicObject):
def __init__(self): def __init__(self):
self.trigger = None self.trigger = None
self.resource_uri = None
def add(self, name=None, operation=None): def add(self, name=None, operation=None):
@ -30,11 +31,11 @@ class Trigger(BasicObject):
return cls(**kwargs) return cls(**kwargs)
def delete(self, uuid): 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") raise ApiError("You must initialize the Trigger object before performing this operation")
action = "DELETE" action = "DELETE"
url = "/".join([self.endpoint, uuid]) url = "/".join([self.resource_uri, uuid])
send_request(action, url) send_request(action, url)
return True return True
@ -43,11 +44,11 @@ class Trigger(BasicObject):
if not isinstance(triggerable, Triggerable): if not isinstance(triggerable, Triggerable):
raise ApiError("The object does not support trigger") 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") raise ApiError("You must save the triggerable object before performing this operation")
trigger = cls() trigger = cls()
trigger.endpoint = "/".join([triggerable._detail_uri, "trigger"]) trigger.resource_uri = "/".join([triggerable.resource_uri, "trigger"])
handlers = [] handlers = []
for t in trigger.list(): for t in trigger.list():
triggername = t.get("name", "") triggername = t.get("name", "")
@ -56,12 +57,12 @@ class Trigger(BasicObject):
return trigger return trigger
def list(self, **kwargs): 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") raise ApiError("You must initialize the Trigger object before performing this operation")
objects = [] objects = []
while True: while True:
json = send_request('GET', self.endpoint, params=kwargs) json = send_request('GET', self.resource_uri, params=kwargs)
objs = json.get('objects', []) objs = json.get('objects', [])
meta = json.get('meta', {}) meta = json.get('meta', {})
next_url = meta.get('next', '') next_url = meta.get('next', '')
@ -77,23 +78,23 @@ class Trigger(BasicObject):
return objects return objects
def save(self): def save(self):
if not self.endpoint: if not self.resource_uri:
raise ApiError("You must initialize the Trigger object before performing this operation") raise ApiError("You must initialize the Trigger object before performing this operation")
if self.trigger is None: if self.trigger is None:
return True 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: if json:
self.clear() self.clear()
self.clear() self.clear()
return True return True
def call(self, uuid): 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") 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: if json:
return True return True
return False return False

View file

@ -43,7 +43,7 @@ class Utils:
return Action.fetch(id) return Action.fetch(id)
else: else:
raise ApiError( 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 @staticmethod
def fetch_remote_container(identifier, raise_exceptions=True): def fetch_remote_container(identifier, raise_exceptions=True):
@ -162,7 +162,7 @@ class Utils:
elif len(objects_same_identifier) == 0: elif len(objects_same_identifier) == 0:
raise ObjectNotFound("Cannot find a node cluster with the identifier '%s'" % identifier) raise ObjectNotFound("Cannot find a node cluster with the identifier '%s'" % identifier)
raise NonUniqueIdentifier( 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: except (NonUniqueIdentifier, ObjectNotFound) as e:
if not raise_exceptions: if not raise_exceptions:
@ -185,7 +185,7 @@ class Utils:
elif len(objects_same_identifier) == 0: elif len(objects_same_identifier) == 0:
raise ObjectNotFound("Cannot find an action cluster with the identifier '%s'" % identifier) raise ObjectNotFound("Cannot find an action cluster with the identifier '%s'" % identifier)
raise NonUniqueIdentifier( 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: except (NonUniqueIdentifier, ObjectNotFound) as e:
if not raise_exceptions: if not raise_exceptions:

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -4,7 +4,10 @@ import os
import tempfile import tempfile
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *
@ -75,7 +78,6 @@ class AuthTestCase(unittest.TestCase):
dockercloud.basic_auth = FAKE_BASIC_AUTH dockercloud.basic_auth = FAKE_BASIC_AUTH
self.assertEqual({'Authorization': FAKE_DOCKERCLOUD_AUTH}, dockercloud.auth.get_auth_header()) self.assertEqual({'Authorization': FAKE_DOCKERCLOUD_AUTH}, dockercloud.auth.get_auth_header())
print "===================="
dockercloud.dockercloud_auth = None dockercloud.dockercloud_auth = None
dockercloud.basic_auth = FAKE_BASIC_AUTH dockercloud.basic_auth = FAKE_BASIC_AUTH
self.assertEqual({'Authorization': 'Basic %s' % (FAKE_BASIC_AUTH)}, dockercloud.auth.get_auth_header()) self.assertEqual({'Authorization': 'Basic %s' % (FAKE_BASIC_AUTH)}, dockercloud.auth.get_auth_header())

View file

@ -3,7 +3,10 @@ from __future__ import absolute_import
import json import json
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from dockercloud.api.base import Restful, Mutable, Immutable from dockercloud.api.base import Restful, Mutable, Immutable
@ -54,14 +57,12 @@ class RestfulTestCase(unittest.TestCase):
def test_restful_loaddict(self): def test_restful_loaddict(self):
model = Restful() model = Restful()
self.assertRaises(AssertionError, model._loaddict, {'key': 'value'}) model.endpoint = 'resource_uri'
model.endpoint = 'endpoint'
model.subsystem = "subsystem" model.subsystem = "subsystem"
model._loaddict({'key': 'value'}) resource_uri = "/".join(["api", model.subsystem, model._api_version, model.endpoint.lstrip("/"), model.pk])
model._loaddict({'key': 'value', "resource_uri": resource_uri})
self.assertEqual('value', model.key) self.assertEqual('value', model.key)
self.assertEqual("/".join(["api", model.subsystem, model._api_version, model.endpoint.lstrip("/"), model.pk]), self.assertEqual(resource_uri, model._resource_uri)
model._detail_uri)
self.assertEqual([], model.__getchanges__()) self.assertEqual([], model.__getchanges__())
def test_restful_pk(self): def test_restful_pk(self):
@ -77,32 +78,29 @@ class RestfulTestCase(unittest.TestCase):
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_restful_perform_action(self, mock_send_request): def test_restful_perform_action(self, mock_send_request):
try:
model = Restful()
self.assertRaises(dockercloud.ApiError, model._perform_action, 'action')
model.endpoint = 'fake' model = Restful()
model.subsystem = "subsystem" self.assertRaises(dockercloud.ApiError, model._perform_action, 'action')
model._detail_uri = "/".join(
["api", model.subsystem, model._api_version, model.endpoint.lstrip("/"), model.pk])
mock_send_request.side_effect = [{'key': 'value'}, None]
self.assertTrue(model._perform_action('action', params={'k': 'v'}, data={'key': 'value'}))
self.assertEqual('value', model.key)
mock_send_request.assert_called_with('POST', "/".join([model._detail_uri, "action"]), data={'key': 'value'},
params={'k': 'v'})
self.assertFalse(model._perform_action('action', {'key': 'value'})) model.endpoint = 'fake'
model.subsystem = "subsystem"
model.resource_uri = "/".join(
["api", model.subsystem, model._api_version, model.endpoint.lstrip("/"), model.pk])
model._resource_uri = model.resource_uri
mock_send_request.side_effect = [{'key': 'value'}, None]
self.assertTrue(model._perform_action('action', params={'k': 'v'}, data={'key': 'value'}))
self.assertEqual('value', model.key)
mock_send_request.assert_called_with('POST', "/".join([model._resource_uri, "action"]), data={'key': 'value'},
params={'k': 'v'})
finally: self.assertFalse(model._perform_action('action', {'key': 'value'}))
if hasattr(Restful, 'endpoint'):
delattr(Restful, 'endpoint')
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_restful_expand_attribute(self, mock_send_request): def test_restful_expand_attribute(self, mock_send_request):
model = Restful() model = Restful()
self.assertRaises(dockercloud.ApiError, model._expand_attribute, 'attribute') self.assertRaises(dockercloud.ApiError, model._expand_attribute, 'attribute')
model._detail_uri = 'fake/uuid' model._resource_uri = 'fake/uuid'
mock_send_request.side_effect = [{'key': 'value'}, None] mock_send_request.side_effect = [{'key': 'value'}, None]
self.assertEqual('value', model._expand_attribute('key')) self.assertEqual('value', model._expand_attribute('key'))
@ -124,63 +122,65 @@ class ImmutableTestCase(unittest.TestCase):
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_immutable_fetch(self, mock_send_request): def test_immutable_fetch(self, mock_send_request):
try:
delattr(Immutable, 'endpoint')
delattr(Immutable, 'subsystem')
except:
pass
self.assertRaises(AssertionError, Immutable.fetch, 'uuid') self.assertRaises(AssertionError, Immutable.fetch, 'uuid')
try: ret_json = {"key": "value"}
ret_json = {"key": "value"} mock_send_request.return_value = ret_json
mock_send_request.return_value = ret_json Immutable.endpoint = 'resource_uri'
Immutable.endpoint = 'endpoint' Immutable.subsystem = "subsystem"
Immutable.subsystem = "subsystem" model = Immutable.fetch('uuid')
model = Immutable.fetch('uuid') mock_send_request.assert_called_with('GET', 'api/subsystem/%s/resource_uri/uuid' % Immutable._api_version)
mock_send_request.assert_called_with('GET', 'api/subsystem/%s/endpoint/uuid' % Immutable._api_version) self.assertIsInstance(model, Immutable)
self.assertIsInstance(model, Immutable) self.assertEqual('value', model.key)
self.assertEqual('value', model.key)
finally:
if hasattr(Immutable, 'endpoint'):
delattr(Immutable, 'endpoint')
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_immutable_list(self, mock_send_request): def test_immutable_list(self, mock_send_request):
self.assertRaises(AssertionError, Immutable.list)
try: try:
kwargs = {'key': 'value'} delattr(Immutable, 'endpoint')
ret_json = {"meta": {"limit": 25, "next": None, "offset": 0, "previous": None, "total_count": 1}, delattr(Immutable, 'subsystem')
"objects": [{"key": "value1"}, {"key": "value2"}]} except:
mock_send_request.return_value = ret_json pass
Immutable.endpoint = 'fake' self.assertRaises(AssertionError, Immutable.list)
models = Immutable.list(**kwargs)
mock_send_request.assert_called_with('GET', 'api/subsystem/%s/fake' % Immutable._api_version, params=kwargs) kwargs = {'key': 'value'}
self.assertEqual(2, len(models)) ret_json = {"meta": {"limit": 25, "next": None, "offset": 0, "previous": None, "total_count": 1},
self.assertIsInstance(models[0], Immutable) "objects": [{"key": "value1"}, {"key": "value2"}]}
self.assertEqual('value1', models[0].key) mock_send_request.return_value = ret_json
self.assertIsInstance(models[1], Immutable) Immutable.endpoint = 'fake'
self.assertEqual('value2', models[1].key) Immutable.subsystem = "subsystem"
finally: models = Immutable.list(**kwargs)
if hasattr(Immutable, 'endpoint'): mock_send_request.assert_called_with('GET', 'api/subsystem/%s/fake' % Immutable._api_version, params=kwargs)
delattr(Immutable, 'endpoint') self.assertEqual(2, len(models))
self.assertIsInstance(models[0], Immutable)
self.assertEqual('value1', models[0].key)
self.assertIsInstance(models[1], Immutable)
self.assertEqual('value2', models[1].key)
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_immutable_refresh(self, mock_send_request): def test_immutable_refresh(self, mock_send_request):
try:
model = Immutable()
model.key = 'value'
self.assertFalse(model.refresh(force=False))
self.assertRaises(dockercloud.ApiError, model.refresh, force=True) model = Immutable()
model.key = 'value'
self.assertFalse(model.refresh(force=False))
Immutable.endpoint = 'endpoint' self.assertRaises(dockercloud.ApiError, model.refresh, force=True)
Immutable.subsystem = 'subsystem'
model._detail_uri = 'api/subsystem/%s/endpoint/uuid' % Immutable._api_version
mock_send_request.side_effect = [{'newkey': 'newvalue'}, None]
self.assertTrue(model.refresh(force=True))
self.assertEqual('newvalue', model.newkey)
mock_send_request.assert_called_with('GET', model._detail_uri)
self.assertFalse(model.refresh(force=True)) Immutable.endpoint = 'resource_uri'
mock_send_request.assert_called_with('GET', model._detail_uri) Immutable.subsystem = 'subsystem'
finally: model.resource_uri = 'api/subsystem/%s/resource_uri/uuid' % Immutable._api_version
if hasattr(Immutable, 'endpoint'): model._resource_uri = model.resource_uri
delattr(Immutable, 'endpoint') mock_send_request.side_effect = [{'newkey': 'newvalue'}, None]
self.assertTrue(model.refresh(force=True))
self.assertEqual('newvalue', model.newkey)
mock_send_request.assert_called_with('GET', model._resource_uri)
self.assertFalse(model.refresh(force=True))
mock_send_request.assert_called_with('GET', model._resource_uri)
class MutableTestCase(unittest.TestCase): class MutableTestCase(unittest.TestCase):
@ -196,57 +196,56 @@ class MutableTestCase(unittest.TestCase):
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_mutable_delete(self, mock_send_request): def test_mutable_delete(self, mock_send_request):
try: model = Mutable()
model = Mutable() self.assertRaises(dockercloud.ApiError, model.delete)
self.assertRaises(dockercloud.ApiError, model.delete)
Mutable.endpoint = 'fake' Mutable.endpoint = 'fake'
model._detail_uri = 'fake/uuid' model._resource_uri = 'fake/uuid'
mock_send_request.side_effect = [{'key': 'value'}, None] mock_send_request.side_effect = [{'key': 'value'}, None]
self.assertTrue(model.delete()) self.assertTrue(model.delete())
self.assertEqual('value', model.key) self.assertEqual('value', model.key)
mock_send_request.assert_called_with('DELETE', 'fake/uuid') mock_send_request.assert_called_with('DELETE', 'fake/uuid')
self.assertTrue(model.delete()) model = Mutable()
self.assertIsNone(model._detail_uri) model._resource_uri = 'fake/uuid'
self.assertFalse(model.is_dirty) self.assertTrue(model.delete())
finally: self.assertIsNone(model._resource_uri)
if hasattr(Mutable, 'endpoint'): self.assertFalse(model.is_dirty)
delattr(Mutable, 'endpoint')
@mock.patch('dockercloud.api.base.send_request') @mock.patch('dockercloud.api.base.send_request')
def test_mutable_save(self, mock_send_request): def test_mutable_save(self, mock_send_request):
self.assertTrue(Mutable().save())
model = Mutable()
model.key = 'value'
try: try:
self.assertTrue(Mutable().save()) delattr(Immutable, 'endpoint')
delattr(Immutable, 'subsystem')
except:
pass
self.assertRaises(AssertionError, model.save)
model = Mutable() Mutable.endpoint = 'resource_uri'
model.key = 'value' Mutable.subsystem = 'subsystem'
self.assertRaises(AssertionError, model.save) mock_send_request.return_value = None
result = model.save()
mock_send_request.assert_called_with('POST', 'api/subsystem/%s/resource_uri' % Mutable._api_version,
data=json.dumps({'key': 'value'}))
self.assertFalse(result)
Mutable.endpoint = 'endpoint' mock_send_request.return_value = {'newkey': 'newvalue'}
Mutable.subsystem = 'subsystem' result = model.save()
mock_send_request.return_value = None mock_send_request.assert_called_with('POST', 'api/subsystem/%s/resource_uri' % Mutable._api_version,
result = model.save() data=json.dumps({'key': 'value'}))
mock_send_request.assert_called_with('POST', 'api/subsystem/%s/endpoint' % Mutable._api_version, self.assertTrue(result)
data=json.dumps({'key': 'value'})) self.assertEqual('newvalue', model.newkey)
self.assertFalse(result)
mock_send_request.return_value = {'newkey': 'newvalue'} model.key = 'another value'
result = model.save() mock_send_request.return_value = {'newkey2': 'newvalue2'}
mock_send_request.assert_called_with('POST', 'api/subsystem/%s/endpoint' % Mutable._api_version, model._resource_uri = 'api/subsystem/%s/resource_uri/uuid' % Immutable._api_version
data=json.dumps({'key': 'value'})) result = model.save()
self.assertTrue(result) mock_send_request.assert_called_with('PATCH', 'api/subsystem/%s/resource_uri/uuid' % Mutable._api_version,
self.assertEqual('newvalue', model.newkey) data=json.dumps({'key': 'another value'}))
self.assertTrue(result)
model.key = 'another value' self.assertEqual('another value', model.key)
mock_send_request.return_value = {'newkey2': 'newvalue2'} self.assertEqual('newvalue2', model.newkey2)
model._detail_uri = 'api/subsystem/%s/endpoint/uuid' % Immutable._api_version
result = model.save()
mock_send_request.assert_called_with('PATCH', 'api/subsystem/%s/endpoint/uuid' % Mutable._api_version,
data=json.dumps({'key': 'another value'}))
self.assertTrue(result)
self.assertEqual('another value', model.key)
self.assertEqual('newvalue2', model.newkey2)
finally:
if hasattr(Mutable, 'endpoint'):
delattr(Mutable, 'endpoint')

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -1,9 +1,12 @@
from __future__ import absolute_import from __future__ import absolute_import
import requests
import unittest import unittest
import requests try:
import unittest.mock as mock import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from dockercloud.api.base import send_request from dockercloud.api.base import send_request

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *
@ -40,7 +43,7 @@ class NodeClusterTestCase(unittest.TestCase):
) )
mock_send.return_value = fake_resp(fake_nodecluster_save) mock_send.return_value = fake_resp(fake_nodecluster_save)
cluster = dockercloud.NodeCluster.create(name="my_cluster", region="/api/v1/region/digitalocean/lon1/", cluster = dockercloud.NodeCluster.create(name="my_cluster", region="/api/v1/region/digitalocean/lon1/",
node_type="/api/v1/nodetype/digitalocean/1gb/") node_type="/api/v1/nodetype/digitalocean/1gb/")
self.assertTrue(cluster.save()) self.assertTrue(cluster.save())
result = json.loads(json.dumps(cluster.get_all_attributes())) result = json.loads(json.dumps(cluster.get_all_attributes()))
target = json.loads(json.dumps(attribute)) target = json.loads(json.dumps(attribute))
@ -53,7 +56,7 @@ class NodeClusterTestCase(unittest.TestCase):
) )
mock_send.side_effect = [fake_resp(fake_nodecluster_save), fake_resp(fake_nodecluster_deploy)] mock_send.side_effect = [fake_resp(fake_nodecluster_save), fake_resp(fake_nodecluster_deploy)]
cluster = dockercloud.NodeCluster.create(name="my_cluster", region="/api/v1/region/digitalocean/lon1/", cluster = dockercloud.NodeCluster.create(name="my_cluster", region="/api/v1/region/digitalocean/lon1/",
node_type="/api/v1/nodetype/digitalocean/1gb/") node_type="/api/v1/nodetype/digitalocean/1gb/")
cluster.save() cluster.save()
self.assertTrue(cluster.deploy()) self.assertTrue(cluster.deploy())
result = json.loads(json.dumps(cluster.get_all_attributes())) result = json.loads(json.dumps(cluster.get_all_attributes()))

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -2,7 +2,10 @@ from __future__ import absolute_import
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from .fake_api import * from .fake_api import *

View file

@ -1,6 +1,9 @@
import unittest import unittest
import unittest.mock as mock try:
import mock
except ImportError:
import unittest.mock as mock
import dockercloud import dockercloud
from dockercloud.api.exceptions import ObjectNotFound, ApiError, NonUniqueIdentifier from dockercloud.api.exceptions import ObjectNotFound, ApiError, NonUniqueIdentifier