dockercloud
This commit is contained in:
parent
86f4a232ff
commit
2d9586a8a1
41 changed files with 2701 additions and 2 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -2,8 +2,6 @@
|
|||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
|
|
@ -22,6 +20,7 @@ var/
|
|||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
venv/
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
|
|
@ -55,3 +54,8 @@ docs/_build/
|
|||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
|
||||
venv/
|
||||
|
|
|
|||
13
Makefile
Normal file
13
Makefile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
test:prepare
|
||||
venv/bin/python setup.py test
|
||||
|
||||
clean:
|
||||
rm -rf venv build dist *.egg-info
|
||||
find . -name '*.pyc' -delete
|
||||
|
||||
prepare:clean
|
||||
set -ex
|
||||
virtualenv venv
|
||||
venv/bin/pip install mock
|
||||
venv/bin/pip install -r requirements.txt
|
||||
venv/bin/python setup.py install
|
||||
78
README.md
78
README.md
|
|
@ -1,2 +1,80 @@
|
|||
# python-docker-cloud
|
||||
|
||||
Python library for Docker Cloud
|
||||
|
||||
## Installation
|
||||
|
||||
In order to install the Docker Cloud Python library, you can use pip install:
|
||||
|
||||
pip install python-dockercloud
|
||||
|
||||
It will install a Python module called dockercloud which you can use to interface with the API.
|
||||
|
||||
## Authorization
|
||||
|
||||
The authentication can be configured in the following ways:
|
||||
|
||||
* Manually set it in your Python initialization code:
|
||||
|
||||
import dockercloud
|
||||
dockercloud.user = "username"
|
||||
dockercloud.apikey = "apikey"
|
||||
|
||||
* Login with docker cli, and the library will read the configfile automatically:
|
||||
|
||||
$ docker login
|
||||
|
||||
* Set the environment variables DOCKERCLOUD_USER and DOCKERCLOUD_APIKEY:
|
||||
|
||||
export DOCKERCLOUD_USER=username
|
||||
export DOCKERCLOUD_APIKEY=apikey
|
||||
|
||||
## Errors
|
||||
|
||||
Errors in the HTTP API will be returned with status codes in the 4xx and 5xx ranges.
|
||||
|
||||
The Python library will detect this status codes and raise ApiError exceptions with the error message, which should be handled by the calling application accordingly.
|
||||
|
||||
|
||||
## Quick examples
|
||||
|
||||
### Services
|
||||
|
||||
>>> import dockercloud
|
||||
>>> dockercloud.Service.list()
|
||||
[<dockercloud.api.service.Service object at 0x10701ca90>, <dockercloud.api.service.Service object at 0x10701ca91>]
|
||||
>>> service = dockercloud.Service.fetch("fee900c6-97da-46b3-a21c-e2b50ed07015")
|
||||
<dockercloud.api.service.Service object at 0x106c45c10>
|
||||
>>> service.name
|
||||
"my-python-app"
|
||||
>>> service = dockercloud.Service.create(image="dockercloud/hello-world", name="my-new- app", target_num_containers=2)
|
||||
>>> service.save()
|
||||
True
|
||||
>>> service.target_num_containers = 3
|
||||
>>> service.save()
|
||||
True
|
||||
>>> service.stop()
|
||||
True
|
||||
>>> service.start()
|
||||
True
|
||||
>>> service.delete()
|
||||
True
|
||||
|
||||
### Containers
|
||||
|
||||
>>> import dockercloud
|
||||
>>> dockercloud.Container.list()
|
||||
[<dockercloud.api.container.Container object at 0x10701ca90>, <dockercloud.api.container.Container object at 0x10701ca91>]
|
||||
>>> container = dockercloud.Container.fetch("7d6696b7-fbaf-471d-8e6b-ce7052586c24")
|
||||
<dockercloud.api.container.Container object at 0x10701ca90>
|
||||
>>> container.public_dns = "my-web-app.example.com"
|
||||
>>> container.save()
|
||||
True
|
||||
>>> container.stop()
|
||||
True
|
||||
>>> container.start()
|
||||
True
|
||||
>>> container.logs()
|
||||
"2014-03-24 23:58:08,973 CRIT Supervisor running as root (no user in config file) [...]"
|
||||
>>> container.delete()
|
||||
True
|
||||
|
|
|
|||
49
dockercloud/__init__.py
Normal file
49
dockercloud/__init__.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import base64
|
||||
import logging
|
||||
import os
|
||||
|
||||
import requests
|
||||
from future.standard_library import install_aliases
|
||||
|
||||
install_aliases()
|
||||
|
||||
from dockercloud.api import auth
|
||||
from dockercloud.api.service import Service
|
||||
from dockercloud.api.container import Container
|
||||
from dockercloud.api.repository import Repository
|
||||
from dockercloud.api.node import Node
|
||||
from dockercloud.api.action import Action
|
||||
from dockercloud.api.nodecluster import NodeCluster
|
||||
from dockercloud.api.nodetype import NodeType
|
||||
from dockercloud.api.nodeprovider import Provider
|
||||
from dockercloud.api.noderegion import Region
|
||||
from dockercloud.api.tag import Tag
|
||||
from dockercloud.api.trigger import Trigger
|
||||
from dockercloud.api.stack import Stack
|
||||
from dockercloud.api.exceptions import ApiError, AuthError, ObjectNotFound, NonUniqueIdentifier
|
||||
from dockercloud.api.utils import Utils
|
||||
from dockercloud.api.events import Events
|
||||
from dockercloud.api.nodeaz import AZ
|
||||
|
||||
__version__ = '1.0.0'
|
||||
|
||||
dockercloud_auth = os.environ.get('DOCKERCLOUD_AUTH')
|
||||
basic_auth = auth.load_from_file("~/.docker/config.json")
|
||||
|
||||
if os.environ.get('DOCKERCLOUD_USER') and os.environ.get('DOCKERCLOUD_PASS'):
|
||||
basic_auth = base64.b64encode("%s:%s" % (os.environ.get('DOCKERCLOUD_USER'), os.environ.get('DOCKERCLOUD_PASS')))
|
||||
if os.environ.get('DOCKERCLOUD_USER') and os.environ.get('DOCKERCLOUD_APIKEY'):
|
||||
basic_auth = base64.b64encode("%s:%s" % (os.environ.get('DOCKERCLOUD_USER'), os.environ.get('DOCKERCLOUD_APIKEY')))
|
||||
|
||||
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/'
|
||||
|
||||
user_agent = None
|
||||
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger("python-dockercloud")
|
||||
|
||||
try:
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
except:
|
||||
pass
|
||||
0
dockercloud/api/__init__.py
Normal file
0
dockercloud/api/__init__.py
Normal file
23
dockercloud/api/action.py
Normal file
23
dockercloud/api/action.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Immutable, StreamingLog
|
||||
|
||||
|
||||
class Action(Immutable):
|
||||
subsystem = 'audit'
|
||||
endpoint = "/action"
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
return 'uuid'
|
||||
|
||||
def logs(self, tail, follow, log_handler=StreamingLog.default_log_handler):
|
||||
logs = StreamingLog(self.subsystem, self.endpoint, self.pk, tail, follow)
|
||||
logs.on_message(log_handler)
|
||||
logs.run_forever()
|
||||
|
||||
def cancel(self):
|
||||
return self._perform_action("cancel")
|
||||
|
||||
def retry(self):
|
||||
return self._perform_action("retry")
|
||||
67
dockercloud/api/auth.py
Normal file
67
dockercloud/api/auth.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
import dockercloud
|
||||
from .http import send_request
|
||||
|
||||
|
||||
def authenticate(username, password):
|
||||
verify_credential(username, password)
|
||||
dockercloud.basic_auth = base64.b64encode("%s:%s" % (username, password))
|
||||
|
||||
|
||||
def verify_credential(username, password):
|
||||
auth = HTTPBasicAuth(username, password)
|
||||
send_request("GET", "/auth", auth=auth)
|
||||
|
||||
|
||||
def is_authenticated():
|
||||
try:
|
||||
dockercloud.basic_auth = base64.b64encode("%s:%s" % (dockercloud.user, dockercloud.password))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
dockercloud.basic_auth = base64.b64encode("%s:%s" % (dockercloud.user, dockercloud.apikey))
|
||||
except:
|
||||
pass
|
||||
|
||||
return dockercloud.dockercloud_auth or dockercloud.basic_auth
|
||||
|
||||
|
||||
def logout():
|
||||
dockercloud.dockercloud_auth = None
|
||||
dockercloud.basic_auth = None
|
||||
|
||||
|
||||
def load_from_file(f="~/.docker/config.json"):
|
||||
try:
|
||||
with open(os.path.expanduser(f)) as config_file:
|
||||
data = json.load(config_file)
|
||||
|
||||
return data.get("auths", {}).get("https://index.docker.io/v1/", {}).get("auth", None)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def get_auth_header():
|
||||
try:
|
||||
dockercloud.basic_auth = base64.b64encode("%s:%s" % (dockercloud.user, dockercloud.password))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
dockercloud.basic_auth = base64.b64encode("%s:%s" % (dockercloud.user, dockercloud.apikey))
|
||||
except:
|
||||
pass
|
||||
|
||||
if dockercloud.dockercloud_auth:
|
||||
return {'Authorization': dockercloud.dockercloud_auth}
|
||||
if dockercloud.basic_auth:
|
||||
return {'Authorization': 'Basic %s' % dockercloud.basic_auth}
|
||||
return {}
|
||||
351
dockercloud/api/base.py
Normal file
351
dockercloud/api/base.py
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
from __future__ import absolute_import, print_function
|
||||
|
||||
import json as json_parser
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
import websocket
|
||||
|
||||
import dockercloud
|
||||
from .exceptions import ApiError, AuthError
|
||||
from .http import send_request
|
||||
|
||||
logger = logging.getLogger("python-dockercloud")
|
||||
|
||||
|
||||
class BasicObject(object):
|
||||
_api_version = 'v1'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class Restful(BasicObject):
|
||||
_detail_uri = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Simply reflect all the values in kwargs"""
|
||||
for k, v in list(kwargs.items()):
|
||||
setattr(self, k, v)
|
||||
|
||||
def __addchanges__(self, name):
|
||||
changed_attrs = self.__getchanges__()
|
||||
if not name in changed_attrs:
|
||||
changed_attrs.append(name)
|
||||
self.__setchanges__(changed_attrs)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
"""Keeps track of what attributes have been set"""
|
||||
current_value = getattr(self, name, None)
|
||||
if value != current_value:
|
||||
self.__addchanges__(name)
|
||||
super(Restful, self).__setattr__(name, value)
|
||||
|
||||
def __getchanges__(self):
|
||||
"""Internal. Convenience method to get the changed attrs list"""
|
||||
return getattr(self, '__changedattrs__', [])
|
||||
|
||||
def __setchanges__(self, val):
|
||||
"""Internal. Convenience method to set the changed attrs list"""
|
||||
# Use the super implementation to prevent infinite recursion
|
||||
super(Restful, self).__setattr__('__changedattrs__', val)
|
||||
|
||||
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)
|
||||
self._detail_uri = "/".join(["api", subsystem, self._api_version, endpoint.strip("/"), self.pk])
|
||||
self.__setchanges__([])
|
||||
|
||||
@property
|
||||
def pk(self):
|
||||
"""Returns the primary key for the object.
|
||||
|
||||
:returns: str -- the primary key for the object
|
||||
"""
|
||||
return getattr(self, self._pk_key(), None)
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
"""Internal. Returns the attribute name that acts as primary key of the model. Can be overridden by subclasses.
|
||||
|
||||
:returns: str -- the name of the primary key attribute for the model
|
||||
"""
|
||||
return 'uuid'
|
||||
|
||||
@property
|
||||
def is_dirty(self):
|
||||
"""Returns whether or not the object has unsaved changes
|
||||
|
||||
:returns: bool -- whether or not the object has unsaved changes
|
||||
"""
|
||||
return len(self.__getchanges__()) > 0
|
||||
|
||||
def _perform_action(self, action, params=None, data={}):
|
||||
"""Internal. Performs the specified action on the object remotely"""
|
||||
success = False
|
||||
if not self._detail_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
path = "/".join([self._detail_uri.rstrip("/"), action.lstrip("/")])
|
||||
json = send_request("POST", path, params=params, data=data)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
success = True
|
||||
return success
|
||||
|
||||
def _expand_attribute(self, attribute):
|
||||
"""Internal. Expands the given attribute from remote information"""
|
||||
if not self._detail_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
path = "/".join([self._detail_uri, attribute])
|
||||
json = send_request("GET", path)
|
||||
if json:
|
||||
return json[attribute]
|
||||
return None
|
||||
|
||||
def get_all_attributes(self):
|
||||
"""Returns a dict with all object attributes
|
||||
|
||||
:returns: dict -- all object attributes as a dict
|
||||
"""
|
||||
attributes = {}
|
||||
for attr in [attr for attr in vars(self) if not attr.startswith('_')]:
|
||||
attributes[attr] = getattr(self, attr, None)
|
||||
return attributes
|
||||
|
||||
|
||||
class Immutable(Restful):
|
||||
@classmethod
|
||||
def fetch(cls, pk):
|
||||
instance = None
|
||||
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__
|
||||
detail_uri = "/".join(["api", subsystem, cls._api_version, endpoint.strip("/"), pk])
|
||||
json = send_request('GET', detail_uri)
|
||||
if json:
|
||||
instance = cls()
|
||||
instance._loaddict(json)
|
||||
return instance
|
||||
|
||||
@classmethod
|
||||
def list(cls, limit=None, **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__
|
||||
|
||||
detail_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)
|
||||
objs = json.get('objects', [])
|
||||
meta = json.get('meta', {})
|
||||
next_url = meta.get('next', '')
|
||||
offset = meta.get('offset', 0)
|
||||
api_limit = meta.get('limit', 0)
|
||||
objects.extend(objs)
|
||||
if next_url:
|
||||
kwargs['offset'] = offset + api_limit
|
||||
kwargs['limit'] = api_limit
|
||||
else:
|
||||
break
|
||||
if limit:
|
||||
objects = objects[:limit]
|
||||
for obj in objects:
|
||||
instance = cls()
|
||||
instance._loaddict(obj)
|
||||
restful.append(instance)
|
||||
return restful
|
||||
|
||||
def refresh(self, force=False):
|
||||
success = False
|
||||
if self.is_dirty and not force:
|
||||
# We have local non-committed changes - rejecting the refresh
|
||||
success = False
|
||||
elif not self._detail_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
else:
|
||||
json = send_request("GET", self._detail_uri)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
success = True
|
||||
return success
|
||||
|
||||
|
||||
class Mutable(Immutable):
|
||||
@classmethod
|
||||
def create(cls, **kwargs):
|
||||
"""Returns a new instance of the model (without saving it) with the attributes specified in ``kwargs``
|
||||
|
||||
:returns: RESTModel -- a new local instance of the model
|
||||
"""
|
||||
return cls(**kwargs)
|
||||
|
||||
def delete(self):
|
||||
if not self._detail_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
action = "DELETE"
|
||||
url = self._detail_uri
|
||||
json = send_request(action, url)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
else:
|
||||
# Object deleted successfully and nothing came back - deleting PK reference.
|
||||
self._detail_uri = None
|
||||
# setattr(self, self._pk_key(), None) -- doesn't work
|
||||
self.__setchanges__([])
|
||||
return True
|
||||
|
||||
def save(self):
|
||||
success = False
|
||||
if not self.is_dirty:
|
||||
# No changes
|
||||
success = True
|
||||
else:
|
||||
cls = self.__class__
|
||||
endpoint = getattr(cls, 'endpoint', None)
|
||||
subsystem = getattr(cls, 'subsystem', None)
|
||||
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:
|
||||
action = "POST"
|
||||
path = "/".join(["api", subsystem, self._api_version, endpoint.lstrip("/")])
|
||||
else:
|
||||
action = "PATCH"
|
||||
path = self._detail_uri
|
||||
# Construct the necessary params
|
||||
params = {}
|
||||
for attr in self.__getchanges__():
|
||||
value = getattr(self, attr, None)
|
||||
params[attr] = value
|
||||
# Construct the json body
|
||||
payload = None
|
||||
if params:
|
||||
payload = json_parser.dumps(params)
|
||||
if not payload:
|
||||
payload = json_parser.dumps({})
|
||||
# Make the request
|
||||
success = False
|
||||
json = send_request(action, path, data=payload)
|
||||
if json:
|
||||
self._loaddict(json)
|
||||
success = True
|
||||
return success
|
||||
|
||||
|
||||
class Taggable(BasicObject):
|
||||
pass
|
||||
|
||||
|
||||
class Triggerable(BasicObject):
|
||||
pass
|
||||
|
||||
|
||||
class StreamingAPI(BasicObject):
|
||||
def __init__(self, url):
|
||||
self._ws_init(url)
|
||||
|
||||
def _ws_init(self, url):
|
||||
self.url = url
|
||||
|
||||
user_agent = 'python-dockercloud/%s' % dockercloud.__version__
|
||||
if dockercloud.user_agent:
|
||||
user_agent = "%s %s" % (dockercloud.user_agent, user_agent)
|
||||
header = {'User-Agent': user_agent}
|
||||
header.update(dockercloud.auth.get_auth_header())
|
||||
self.header = [": ".join([key, value]) for key, value in header.items()]
|
||||
logger.info("websocket: %s %s" % (self.url, self.header))
|
||||
self.open_handler = None
|
||||
self.message_handler = None
|
||||
self.error_handler = None
|
||||
self.close_handler = None
|
||||
self.auth_error = False
|
||||
|
||||
def _on_open(self, ws):
|
||||
if self.open_handler:
|
||||
self.open_handler()
|
||||
|
||||
def _on_message(self, ws, message):
|
||||
if self.message_handler:
|
||||
self.message_handler(message)
|
||||
|
||||
def _on_error(self, ws, error):
|
||||
if self.error_handler:
|
||||
self.error_handler(error)
|
||||
|
||||
def _on_close(self, ws):
|
||||
if self.close_handler:
|
||||
self.close_handler()
|
||||
|
||||
def on_open(self, handler):
|
||||
self.open_handler = handler
|
||||
|
||||
def on_message(self, handler):
|
||||
self.message_handler = handler
|
||||
|
||||
def on_error(self, handler):
|
||||
self.error_handler = handler
|
||||
|
||||
def on_close(self, handler):
|
||||
self.close_handler = handler
|
||||
|
||||
def run_forever(self, *args, **kwargs):
|
||||
while True:
|
||||
if getattr(self, "auth_error", False):
|
||||
raise AuthError("Not authorized")
|
||||
ws = websocket.WebSocketApp(self.url, header=self.header,
|
||||
on_open=self._on_open,
|
||||
on_message=self._on_message,
|
||||
on_error=self._on_error,
|
||||
on_close=self._on_close)
|
||||
ws.run_forever(ping_interval=5, ping_timeout=5, *args, **kwargs)
|
||||
|
||||
|
||||
class StreamingLog(StreamingAPI):
|
||||
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("/")])
|
||||
super(self.__class__, self).__init__(url)
|
||||
|
||||
@staticmethod
|
||||
def default_log_handler(message):
|
||||
print(message)
|
||||
|
||||
def run_forever(self, *args, **kwargs):
|
||||
ws = websocket.WebSocketApp(self.url, header=self.header,
|
||||
on_open=self._on_open,
|
||||
on_message=self._on_message,
|
||||
on_error=self._on_error,
|
||||
on_close=self._on_close)
|
||||
ws.run_forever(ping_interval=5, ping_timeout=5, *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("/")])
|
||||
super(self.__class__, self).__init__(url)
|
||||
|
||||
@staticmethod
|
||||
def default_message_handler(message):
|
||||
print(message)
|
||||
|
||||
def run_forever(self, *args, **kwargs):
|
||||
ws = websocket.WebSocketApp(self.url, header=self.header,
|
||||
on_open=self._on_open,
|
||||
on_message=self._on_message,
|
||||
on_error=self._on_error,
|
||||
on_close=self._on_close)
|
||||
ws.run_forever(ping_interval=5, ping_timeout=5, *args, **kwargs)
|
||||
33
dockercloud/api/container.py
Normal file
33
dockercloud/api/container.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Mutable, StreamingLog, Exec
|
||||
|
||||
|
||||
class Container(Mutable):
|
||||
subsystem = "app"
|
||||
endpoint = "/container"
|
||||
|
||||
def save(self):
|
||||
raise AttributeError("'save' is not supported in 'Container' object. "
|
||||
"Please use the related 'Service' object instead.")
|
||||
|
||||
def start(self):
|
||||
return self._perform_action("start")
|
||||
|
||||
def stop(self):
|
||||
return self._perform_action("stop")
|
||||
|
||||
def redeploy(self, reuse_volumes=True):
|
||||
params = {'reuse_volumes': reuse_volumes}
|
||||
return self._perform_action("redeploy", params=params)
|
||||
|
||||
def logs(self, tail, follow, log_handler=StreamingLog.default_log_handler):
|
||||
logs = StreamingLog(self.subsystem, self.endpoint, self.pk, tail, follow)
|
||||
logs.on_message(log_handler)
|
||||
logs.run_forever()
|
||||
|
||||
def execute(self, cmd, handler=Exec.default_message_handler):
|
||||
if hasattr(self, "uuid"):
|
||||
exec_obj = Exec(self.uuid, cmd)
|
||||
exec_obj.on_message(handler)
|
||||
exec_obj.run_forever()
|
||||
42
dockercloud/api/events.py
Normal file
42
dockercloud/api/events.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import json
|
||||
|
||||
import websocket
|
||||
|
||||
import dockercloud
|
||||
from .base import StreamingAPI
|
||||
from .exceptions import AuthError
|
||||
|
||||
|
||||
class Events(StreamingAPI):
|
||||
def __init__(self):
|
||||
endpoint = "events"
|
||||
url = "/".join([dockercloud.stream_host.rstrip("/"), "api", "audit", self._api_version, endpoint.lstrip("/")])
|
||||
super(self.__class__, self).__init__(url)
|
||||
|
||||
def _on_message(self, ws, message):
|
||||
try:
|
||||
event = json.loads(message)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
if event.get("type") == "error" and event.get("data", {}).get("errorMessage") == "UNAUTHORIZED":
|
||||
self.auth_error = True
|
||||
raise AuthError("Not authorized")
|
||||
if event.get("type") == "auth":
|
||||
return
|
||||
|
||||
if self.message_handler:
|
||||
self.message_handler(event)
|
||||
|
||||
def run_forever(self, *args, **kwargs):
|
||||
while True:
|
||||
if self.auth_error:
|
||||
raise AuthError("Not authorized")
|
||||
ws = websocket.WebSocketApp(self.url, header=self.header,
|
||||
on_open=self._on_open,
|
||||
on_message=self._on_message,
|
||||
on_error=self._on_error,
|
||||
on_close=self._on_close)
|
||||
ws.run_forever(ping_interval=5, ping_timeout=5, *args, **kwargs)
|
||||
16
dockercloud/api/exceptions.py
Normal file
16
dockercloud/api/exceptions.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
class ApiError(Exception):
|
||||
"""An error status code was returned when querying the HTTP API"""
|
||||
pass
|
||||
|
||||
|
||||
class AuthError(ApiError):
|
||||
"""An 401 Unauthorized status code was returned when querying the API"""
|
||||
pass
|
||||
|
||||
|
||||
class NonUniqueIdentifier(ApiError):
|
||||
pass
|
||||
|
||||
|
||||
class ObjectNotFound(ApiError):
|
||||
pass
|
||||
64
dockercloud/api/http.py
Normal file
64
dockercloud/api/http.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
|
||||
from requests import Request, Session
|
||||
from requests import utils
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import dockercloud
|
||||
from .exceptions import ApiError, AuthError
|
||||
|
||||
logger = logging.getLogger("python-dockercloud")
|
||||
|
||||
|
||||
def send_request(method, path, inject_header=True, **kwargs):
|
||||
json = None
|
||||
url = urljoin(dockercloud.rest_host.rstrip("/"), path.strip("/").encode("ascii", "ignore"))
|
||||
if not url.endswith("/"):
|
||||
url = "%s/" % url
|
||||
user_agent = 'python-dockercloud/%s' % dockercloud.__version__
|
||||
if dockercloud.user_agent:
|
||||
user_agent = "%s %s" % (dockercloud.user_agent, user_agent)
|
||||
|
||||
# construct headers
|
||||
headers = {'Content-Type': 'application/json', 'User-Agent': user_agent}
|
||||
headers.update(dockercloud.auth.get_auth_header())
|
||||
logger.info("Request: %s, %s, %s, %s" % (method, url, headers, kwargs))
|
||||
|
||||
# construct request
|
||||
s = Session()
|
||||
req = Request(method, url, headers=headers, **kwargs)
|
||||
|
||||
# get environment proxies
|
||||
env_proxies = utils.get_environ_proxies(url) or {}
|
||||
kw_args = {'proxies': env_proxies}
|
||||
|
||||
# make the request
|
||||
response = s.send(req.prepare(), **kw_args)
|
||||
status_code = getattr(response, 'status_code', None)
|
||||
logger.info("Response: Status %s, %s, %s" % (str(status_code), response.headers, response.text))
|
||||
|
||||
# handle the response
|
||||
if not status_code:
|
||||
# Most likely network trouble
|
||||
raise ApiError("No Response (%s %s)" % (method, url))
|
||||
elif 200 <= status_code <= 299:
|
||||
# Success
|
||||
if status_code != 204:
|
||||
# Try to parse the response.
|
||||
try:
|
||||
json = response.json()
|
||||
if response.headers and inject_header:
|
||||
json["dockercloud_action_uri"] = response.headers.get("X-DockerCloud-Action-URI", "")
|
||||
except TypeError:
|
||||
raise ApiError("JSON Parse Error (%s %s). Response: %s" % (method, url, response.text))
|
||||
else:
|
||||
json = None
|
||||
else:
|
||||
# Server returned an error
|
||||
if status_code == 401:
|
||||
raise AuthError("Not authorized")
|
||||
else:
|
||||
raise ApiError("Status %s (%s %s). Response: %s" % (str(status_code), method, url, response.text))
|
||||
return json
|
||||
19
dockercloud/api/node.py
Normal file
19
dockercloud/api/node.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Mutable, Taggable
|
||||
|
||||
|
||||
class Node(Mutable, Taggable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/node"
|
||||
|
||||
def save(self):
|
||||
if not self._detail_uri:
|
||||
raise AttributeError("Adding a new node is not supported via 'save' method")
|
||||
super(Node, self).save()
|
||||
|
||||
def deploy(self, tag=None):
|
||||
return self._perform_action("deploy")
|
||||
|
||||
def upgrade_docker(self):
|
||||
return self._perform_action("docker-upgrade")
|
||||
12
dockercloud/api/nodeaz.py
Normal file
12
dockercloud/api/nodeaz.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Immutable
|
||||
|
||||
|
||||
class AZ(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/az"
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
return 'name'
|
||||
22
dockercloud/api/nodecluster.py
Normal file
22
dockercloud/api/nodecluster.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Mutable, Taggable
|
||||
from .noderegion import Region
|
||||
from .nodetype import NodeType
|
||||
|
||||
|
||||
class NodeCluster(Mutable, Taggable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/nodecluster"
|
||||
|
||||
def deploy(self, tag=None):
|
||||
return self._perform_action("deploy")
|
||||
|
||||
@classmethod
|
||||
def create(cls, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
if key == "node_type" and isinstance(value, NodeType):
|
||||
kwargs[key] = getattr(value, "resource_uri", "")
|
||||
if key == "region" and isinstance(value, Region):
|
||||
kwargs[key] = getattr(value, "resource_uri", "")
|
||||
return cls(**kwargs)
|
||||
18
dockercloud/api/nodeprovider.py
Normal file
18
dockercloud/api/nodeprovider.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Immutable
|
||||
|
||||
|
||||
class Provider(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/provider"
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
return 'name'
|
||||
|
||||
def delete(self):
|
||||
raise AttributeError("'delete' is not supported in 'Provider'")
|
||||
|
||||
def save(self):
|
||||
raise AttributeError("'save' is not supported in 'Provider'")
|
||||
12
dockercloud/api/noderegion.py
Normal file
12
dockercloud/api/noderegion.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Immutable
|
||||
|
||||
|
||||
class Region(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/region"
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
return 'name'
|
||||
12
dockercloud/api/nodetype.py
Normal file
12
dockercloud/api/nodetype.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Immutable
|
||||
|
||||
|
||||
class NodeType(Immutable):
|
||||
subsystem = "infra"
|
||||
endpoint = "/nodetype"
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
return 'name'
|
||||
12
dockercloud/api/repository.py
Normal file
12
dockercloud/api/repository.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Mutable, Taggable
|
||||
|
||||
|
||||
class Repository(Mutable, Taggable):
|
||||
subsystem = "repo"
|
||||
endpoint = "/repository"
|
||||
|
||||
@classmethod
|
||||
def _pk_key(cls):
|
||||
return 'name'
|
||||
26
dockercloud/api/service.py
Normal file
26
dockercloud/api/service.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Mutable, Taggable, Triggerable, StreamingLog
|
||||
|
||||
|
||||
class Service(Mutable, Taggable, Triggerable):
|
||||
subsystem = "app"
|
||||
endpoint = "/service"
|
||||
|
||||
def start(self):
|
||||
return self._perform_action("start")
|
||||
|
||||
def stop(self):
|
||||
return self._perform_action("stop")
|
||||
|
||||
def redeploy(self, reuse_volumes=True):
|
||||
params = {'reuse_volumes': reuse_volumes}
|
||||
return self._perform_action("redeploy", params=params)
|
||||
|
||||
def scale(self):
|
||||
return self._perform_action("scale")
|
||||
|
||||
def logs(self, tail, follow, log_handler=StreamingLog.default_log_handler):
|
||||
logs = StreamingLog(self.subsystem, self.endpoint, self.pk, tail, follow)
|
||||
logs.on_message(log_handler)
|
||||
logs.run_forever()
|
||||
26
dockercloud/api/stack.py
Normal file
26
dockercloud/api/stack.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Mutable
|
||||
from .exceptions import ApiError
|
||||
from .http import send_request
|
||||
|
||||
|
||||
class Stack(Mutable):
|
||||
subsystem = "app"
|
||||
endpoint = "/stack"
|
||||
|
||||
def start(self):
|
||||
return self._perform_action("start")
|
||||
|
||||
def stop(self):
|
||||
return self._perform_action("stop")
|
||||
|
||||
def redeploy(self, reuse_volumes=True):
|
||||
params = {'reuse_volumes': reuse_volumes}
|
||||
return self._perform_action("redeploy", params=params)
|
||||
|
||||
def export(self):
|
||||
if not self._detail_uri:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
url = "/".join([self._detail_uri, "export"])
|
||||
return send_request("GET", url, inject_header=False)
|
||||
78
dockercloud/api/tag.py
Normal file
78
dockercloud/api/tag.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import Taggable, BasicObject
|
||||
from .exceptions import ApiError
|
||||
|
||||
|
||||
class Tag(BasicObject):
|
||||
def __init__(self):
|
||||
self.tags = []
|
||||
|
||||
def add(self, tagname):
|
||||
if isinstance(tagname, list):
|
||||
for t in tagname:
|
||||
self.taggable.tags.append({"name": t})
|
||||
else:
|
||||
self.taggable.tags.append({"name": tagname})
|
||||
|
||||
self.taggable.__addchanges__('tags')
|
||||
|
||||
@classmethod
|
||||
def create(cls, **kwargs):
|
||||
return cls(**kwargs)
|
||||
|
||||
def remove(self, tagname):
|
||||
if not self.taggable:
|
||||
raise ApiError("You must initialize the tag object before performing this operation")
|
||||
|
||||
_tags = []
|
||||
tagnames = []
|
||||
if isinstance(tagname, list):
|
||||
for n in tagname:
|
||||
tagnames.append(n)
|
||||
else:
|
||||
tagnames.append(tagname)
|
||||
|
||||
for t in self.taggable.tags:
|
||||
for tagname in tagnames:
|
||||
if t.get("name", "") == tagname:
|
||||
_tags.append(t)
|
||||
|
||||
if _tags:
|
||||
for _tag in _tags:
|
||||
self.taggable.tags.remove(_tag)
|
||||
self.taggable.__addchanges__('tags')
|
||||
|
||||
def delete(self, tagname):
|
||||
if not self.taggable:
|
||||
raise ApiError("You must initialize the tag object before performing this operation")
|
||||
|
||||
if self.taggable.is_dirty:
|
||||
raise ApiError("You must save the tab object before performing this operation")
|
||||
|
||||
self.remove(tagname)
|
||||
return self.save()
|
||||
|
||||
@classmethod
|
||||
def fetch(cls, taggable):
|
||||
if not isinstance(taggable, Taggable):
|
||||
raise ApiError("The object does not support tag")
|
||||
if not taggable._detail_uri:
|
||||
raise ApiError("You must save the taggable object before performing this operation")
|
||||
|
||||
tag = cls()
|
||||
tag.taggable = taggable
|
||||
|
||||
return tag
|
||||
|
||||
def list(self, **kwargs):
|
||||
if not self.taggable:
|
||||
raise ApiError("You must initialize the tag object before performing this operation")
|
||||
|
||||
return self.taggable.tags
|
||||
|
||||
def save(self):
|
||||
if not self.taggable:
|
||||
raise ApiError("You must initialize the tag object before performing this operation")
|
||||
|
||||
return self.taggable.save()
|
||||
102
dockercloud/api/trigger.py
Normal file
102
dockercloud/api/trigger.py
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
import json as json_parser
|
||||
|
||||
from .base import Triggerable, BasicObject
|
||||
from .exceptions import ApiError
|
||||
from .http import send_request
|
||||
|
||||
|
||||
class Trigger(BasicObject):
|
||||
def __init__(self):
|
||||
self.trigger = None
|
||||
|
||||
def add(self, name=None, operation=None):
|
||||
|
||||
if self.trigger is not None:
|
||||
raise ApiError("You must save the object before performing this operation")
|
||||
|
||||
trigger = {}
|
||||
if name:
|
||||
trigger['name'] = name
|
||||
if operation:
|
||||
trigger['operation'] = operation
|
||||
self.trigger = trigger
|
||||
|
||||
@classmethod
|
||||
def create(cls, **kwargs):
|
||||
"""Returns a new instance of the model (without saving it) with the attributes specified in ``kwargs``
|
||||
|
||||
:returns: trigger -- a new local instance of the Trigger
|
||||
"""
|
||||
return cls(**kwargs)
|
||||
|
||||
def delete(self, uuid):
|
||||
if not self.endpoint:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
action = "DELETE"
|
||||
url = "/".join([self.endpoint, uuid])
|
||||
send_request(action, url)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def fetch(cls, triggerable):
|
||||
if not isinstance(triggerable, Triggerable):
|
||||
raise ApiError("The object does not support trigger")
|
||||
|
||||
if not triggerable._detail_uri:
|
||||
raise ApiError("You must save the triggerable object before performing this operation")
|
||||
|
||||
trigger = cls()
|
||||
trigger.endpoint = "/".join([triggerable._detail_uri, "trigger"])
|
||||
handlers = []
|
||||
for t in trigger.list():
|
||||
triggername = t.get("name", "")
|
||||
if triggername:
|
||||
handlers.append({"name": triggername})
|
||||
return trigger
|
||||
|
||||
def list(self, **kwargs):
|
||||
if not self.endpoint:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
objects = []
|
||||
while True:
|
||||
json = send_request('GET', self.endpoint, params=kwargs)
|
||||
objs = json.get('objects', [])
|
||||
meta = json.get('meta', {})
|
||||
next_url = meta.get('next', '')
|
||||
offset = meta.get('offset', 0)
|
||||
limit = meta.get('limit', 0)
|
||||
objects.extend(objs)
|
||||
if next_url:
|
||||
kwargs['offset'] = offset + limit
|
||||
kwargs['limit'] = limit
|
||||
else:
|
||||
break
|
||||
|
||||
return objects
|
||||
|
||||
def save(self):
|
||||
if not self.endpoint:
|
||||
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))
|
||||
if json:
|
||||
self.clear()
|
||||
self.clear()
|
||||
return True
|
||||
|
||||
def call(self, uuid):
|
||||
if not self.endpoint:
|
||||
raise ApiError("You must initialize the Trigger object before performing this operation")
|
||||
|
||||
json = send_request("POST", "/".join([self.endpoint, uuid + "/call"]))
|
||||
if json:
|
||||
return True
|
||||
return False
|
||||
|
||||
def clear(self):
|
||||
self.trigger = None
|
||||
193
dockercloud/api/utils.py
Normal file
193
dockercloud/api/utils.py
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import re
|
||||
|
||||
from .action import Action
|
||||
from .container import Container
|
||||
from .exceptions import ApiError, ObjectNotFound, NonUniqueIdentifier
|
||||
from .node import Node
|
||||
from .nodecluster import NodeCluster
|
||||
from .service import Service
|
||||
from .stack import Stack
|
||||
|
||||
|
||||
def is_uuid4(identifier):
|
||||
uuid4_regexp = re.compile('^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}', re.I)
|
||||
match = uuid4_regexp.match(identifier)
|
||||
return bool(match)
|
||||
|
||||
|
||||
class Utils:
|
||||
@staticmethod
|
||||
def fetch_by_resource_uri(uri):
|
||||
if not isinstance(uri, basestring):
|
||||
raise ApiError("Uri format is invalid")
|
||||
terms = uri.strip("/").split("/")
|
||||
if len(terms) < 2:
|
||||
raise ApiError("Uri format is invalid")
|
||||
|
||||
id = terms[-1]
|
||||
resource_type = terms[-2]
|
||||
|
||||
if resource_type.lower() == "container":
|
||||
return Container.fetch(id)
|
||||
elif resource_type.lower() == "service":
|
||||
return Service.fetch(id)
|
||||
elif resource_type.lower() == "stack":
|
||||
return Stack.fetch(id)
|
||||
elif resource_type.lower() == "node":
|
||||
return Node.fetch(id)
|
||||
elif resource_type.lower() == "nodecluster":
|
||||
return NodeCluster.fetch(id)
|
||||
elif resource_type.lower() == "action":
|
||||
return Action.fetch(id)
|
||||
else:
|
||||
raise ApiError(
|
||||
"Unsupported resource type. Only support: action, container, node, nodecluster, service, stack")
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_container(identifier, raise_exceptions=True):
|
||||
try:
|
||||
if is_uuid4(identifier):
|
||||
try:
|
||||
return Container.fetch(identifier)
|
||||
except Exception:
|
||||
raise ObjectNotFound("Cannot find a container with the identifier '%s'" % identifier)
|
||||
else:
|
||||
if "." in identifier:
|
||||
terms = identifier.split(".", 2)
|
||||
objects_same_identifier = Container.list(name=terms[0], service__stack__name=terms[1])
|
||||
else:
|
||||
objects_same_identifier = Container.list(uuid__startswith=identifier) or \
|
||||
Container.list(name=identifier)
|
||||
|
||||
if len(objects_same_identifier) == 1:
|
||||
uuid = objects_same_identifier[0].uuid
|
||||
return Container.fetch(uuid)
|
||||
elif len(objects_same_identifier) == 0:
|
||||
raise ObjectNotFound("Cannot find a container with the identifier '%s'" % identifier)
|
||||
raise NonUniqueIdentifier("More than one container has the same identifier, please use the long uuid")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
return e
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_service(identifier, raise_exceptions=True):
|
||||
try:
|
||||
if is_uuid4(identifier):
|
||||
try:
|
||||
return Service.fetch(identifier)
|
||||
except Exception:
|
||||
raise ObjectNotFound("Cannot find a service with the identifier '%s'" % identifier)
|
||||
else:
|
||||
if "." in identifier:
|
||||
terms = identifier.split(".", 2)
|
||||
objects_same_identifier = Service.list(name=terms[0], stack__name=terms[1])
|
||||
else:
|
||||
objects_same_identifier = Service.list(uuid__startswith=identifier) or \
|
||||
Service.list(name=identifier)
|
||||
|
||||
if len(objects_same_identifier) == 1:
|
||||
uuid = objects_same_identifier[0].uuid
|
||||
return Service.fetch(uuid)
|
||||
elif len(objects_same_identifier) == 0:
|
||||
raise ObjectNotFound("Cannot find a service with the identifier '%s'" % identifier)
|
||||
raise NonUniqueIdentifier("More than one service has the same identifier, please use the long uuid")
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
return e
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_stack(identifier, raise_exceptions=True):
|
||||
try:
|
||||
if is_uuid4(identifier):
|
||||
try:
|
||||
return Stack.fetch(identifier)
|
||||
except Exception:
|
||||
raise ObjectNotFound("Cannot find a stack with the identifier '%s'" % identifier)
|
||||
else:
|
||||
objects_same_identifier = Stack.list(uuid__startswith=identifier) or \
|
||||
Stack.list(name=identifier)
|
||||
if len(objects_same_identifier) == 1:
|
||||
uuid = objects_same_identifier[0].uuid
|
||||
return Stack.fetch(uuid)
|
||||
elif len(objects_same_identifier) == 0:
|
||||
raise ObjectNotFound("Cannot find a stack with the identifier '%s'" % identifier)
|
||||
raise NonUniqueIdentifier("More than one stack has the same identifier, please use the long uuid")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
return e
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_node(identifier, raise_exceptions=True):
|
||||
try:
|
||||
if is_uuid4(identifier):
|
||||
try:
|
||||
return Node.fetch(identifier)
|
||||
except Exception:
|
||||
raise ObjectNotFound("Cannot find a node with the identifier '%s'" % identifier)
|
||||
else:
|
||||
objects_same_identifier = Node.list(uuid__startswith=identifier)
|
||||
if len(objects_same_identifier) == 1:
|
||||
uuid = objects_same_identifier[0].uuid
|
||||
return Node.fetch(uuid)
|
||||
elif len(objects_same_identifier) == 0:
|
||||
raise ObjectNotFound("Cannot find a node with the identifier '%s'" % identifier)
|
||||
raise NonUniqueIdentifier("More than one node has the same identifier, please use the long uuid")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
return e
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_nodecluster(identifier, raise_exceptions=True):
|
||||
try:
|
||||
if is_uuid4(identifier):
|
||||
try:
|
||||
return NodeCluster.fetch(identifier)
|
||||
except Exception:
|
||||
raise ObjectNotFound("Cannot find a node cluster with the identifier '%s'" % identifier)
|
||||
else:
|
||||
objects_same_identifier = NodeCluster.list(uuid__startswith=identifier) or \
|
||||
NodeCluster.list(name=identifier)
|
||||
if len(objects_same_identifier) == 1:
|
||||
uuid = objects_same_identifier[0].uuid
|
||||
return NodeCluster.fetch(uuid)
|
||||
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")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
return e
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def fetch_remote_action(identifier, raise_exceptions=True):
|
||||
try:
|
||||
if is_uuid4(identifier):
|
||||
try:
|
||||
return Action.fetch(identifier)
|
||||
except Exception:
|
||||
raise ObjectNotFound("Cannot find an action with the identifier '%s'" % identifier)
|
||||
else:
|
||||
objects_same_identifier = Action.list(uuid__startswith=identifier)
|
||||
if len(objects_same_identifier) == 1:
|
||||
uuid = objects_same_identifier[0].uuid
|
||||
return Action.fetch(uuid)
|
||||
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")
|
||||
|
||||
except (NonUniqueIdentifier, ObjectNotFound) as e:
|
||||
if not raise_exceptions:
|
||||
return e
|
||||
raise e
|
||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
backports.ssl-match-hostname==3.4.0.2
|
||||
future==0.15.0
|
||||
requests==2.7.0
|
||||
six==1.9.0
|
||||
websocket-client==0.32.0
|
||||
40
setup.py
Normal file
40
setup.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import codecs
|
||||
import os
|
||||
import re
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
|
||||
def read(*parts):
|
||||
path = os.path.join(os.path.dirname(__file__), *parts)
|
||||
with codecs.open(path, encoding='utf-8') as fobj:
|
||||
return fobj.read()
|
||||
|
||||
|
||||
def find_version(*file_paths):
|
||||
version_file = read(*file_paths)
|
||||
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
|
||||
version_file, re.M)
|
||||
if version_match:
|
||||
return version_match.group(1)
|
||||
raise RuntimeError('Unable to find version string.')
|
||||
|
||||
|
||||
with open('requirements.txt') as f:
|
||||
install_requires = f.read().splitlines()
|
||||
|
||||
setup(
|
||||
name="python-dockercloud",
|
||||
version=find_version('dockercloud', '__init__.py'),
|
||||
packages=find_packages(),
|
||||
install_requires=install_requires,
|
||||
provides=['docker'],
|
||||
include_package_data=True,
|
||||
author="Docker, Inc.",
|
||||
author_email="info@docker.com",
|
||||
description="Python Library for Dockercloud",
|
||||
license="Apache v2",
|
||||
keywords="docker cloud",
|
||||
url="http://cloud.docker.com/",
|
||||
test_suite="tests",
|
||||
)
|
||||
12
tests/__init__.py
Normal file
12
tests/__init__.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
__author__ = 'fermayo'
|
||||
|
||||
# Python 3.4.2 includes mock in-box, prefer that version
|
||||
# For other versions, patch it up to use the external mock library
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import sys
|
||||
|
||||
sys.modules['unittest'] = __import__('unittest')
|
||||
sys.modules['unittest.mock'] = __import__('mock')
|
||||
setattr(sys.modules['unittest'], 'mock', __import__('mock'))
|
||||
276
tests/fake_api.py
Normal file
276
tests/fake_api.py
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
import datetime
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
FAKE_USER = 'fake_user'
|
||||
FAKE_PASSWORD = 'fake_password'
|
||||
FAKE_DOCKERCLOUD_AUTH = 'fake_auth'
|
||||
FAKE_BASIC_AUTH = 'ZmFrZV91c2VyOmZha2VfcGFzc3dvcmQ='
|
||||
FAKE_APIKEY_AUTH = 'ZmFrZV90dXR1bV91c2VyOmZha2VfdHV0dW1fYXBpa2V5'
|
||||
FAKE_APIKEY = 'fake_apikey'
|
||||
FAKE_EMAIL = 'fake@docker.com'
|
||||
FAKE_UUID = 'b0374cc2-4003-4270-b131-25fc494ea2be'
|
||||
FAKE_UUIDS = ['b0374cc2-4003-4270-b131-25fc494ea2be', 'd89fc6f9-d7ec-4602-be94-429c65d6657d',
|
||||
'aeaa0b9f-a878-488a-b4a5-a5b54264edd7']
|
||||
|
||||
|
||||
def response(status_code=200, content='', headers=None, reason=None, elapsed=0,
|
||||
request=None):
|
||||
res = requests.Response()
|
||||
res.status_code = status_code
|
||||
content = json.dumps(content).encode('ascii')
|
||||
res._content = content
|
||||
res.headers = requests.structures.CaseInsensitiveDict(headers or {})
|
||||
res.reason = reason
|
||||
res.elapsed = datetime.timedelta(elapsed)
|
||||
res.request = request
|
||||
return res
|
||||
|
||||
|
||||
def fake_resp(fake_api_call):
|
||||
status_code, content = fake_api_call()
|
||||
return response(status_code=status_code, content=content)
|
||||
|
||||
|
||||
def fake_auth():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 1},' \
|
||||
'"objects": [{"key": "%s", "username": "%s"}]}' % (FAKE_APIKEY, FAKE_USER)
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_action_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 3}, ' \
|
||||
'"objects": [{"action": "Node Cluster Create", "end_date": "Mon, 29 Sep 2014 15:40:59 +0000", "ip": "207.41.188.212", "location": "New York, United States", "method": "POST", "object": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "path": "/api/v1/nodecluster/", "resource_uri": "/api/v1/action/7f62b667-2693-420a-ad2e-41cda5605322/", "start_date": "Mon, 29 Sep 2014 15:40:59 +0000", "state": "Success", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "7f62b667-2693-420a-ad2e-41cda5605322"}, ' \
|
||||
'{"action": "Node Cluster Deploy", "end_date": "Mon, 29 Sep 2014 15:41:01 +0000", "ip": "207.41.188.212", "location": "New York, United States", "method": "POST", "object": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "path": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/deploy/", "resource_uri": "/api/v1/action/db69b048-3bab-4a2e-bcbd-91265edf1a31/", "start_date": "Mon, 29 Sep 2014 15:41:00 +0000", "state": "Failed", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "db69b048-3bab-4a2e-bcbd-91265edf1a31"}, ' \
|
||||
'{"action": "Node Deploy", "end_date": "Mon, 29 Sep 2014 15:41:16 +0000", "ip": "207.41.188.212", "location": "New York, United States", "method": "POST", "object": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "path": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/deploy/", "resource_uri": "/api/v1/action/ce9ae16b-88fa-4be6-b12e-fc970b8d2445/", "start_date": "Mon, 29 Sep 2014 15:41:16 +0000", "state": "Failed", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "ce9ae16b-88fa-4be6-b12e-fc970b8d2445"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_action_fetch():
|
||||
status_code = 200
|
||||
resp = '{"action": "Node Cluster Create", "end_date": "Mon, 29 Sep 2014 15:40:59 +0000", "ip": "207.41.188.212", "location": "New York, United States", "logs": "", "method": "POST", "object": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "path": "/api/v1/nodecluster/", "resource_uri": "/api/v1/action/7f62b667-2693-420a-ad2e-41cda5605322/", "start_date": "Mon, 29 Sep 2014 15:40:59 +0000", "state": "Success", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "7f62b667-2693-420a-ad2e-41cda5605322"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_provider_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 1}, "objects": [{"available": true, "label": "Digital Ocean", "name": "digitalocean", "regions": ["/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/ams3/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/sgp1/"], "resource_uri": "/api/v1/provider/digitalocean/"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_provider_fetch():
|
||||
status_code = 200
|
||||
resp = '{"available": true, "label": "Digital Ocean", "name": "digitalocean", "regions": ["/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/ams3/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/sgp1/"], "resource_uri": "/api/v1/provider/digitalocean/"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_region_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 8}, ' \
|
||||
'"objects": [{"availability_zones": [], "available": true, "label": "Amsterdam 1", "name": "ams1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/"], "resource_uri": "/api/v1/region/digitalocean/ams1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "San Francisco 1", "name": "sfo1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/sfo1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "New York 2", "name": "nyc2", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/nyc2/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "Amsterdam 2", "name": "ams2", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/ams2/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "Singapore 1", "name": "sgp1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/sgp1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "London 1", "name": "lon1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/lon1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "New York 3", "name": "nyc3", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/nyc3/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "Amsterdam 3", "name": "ams3", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/ams3/"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_region_fetch():
|
||||
status_code = 200
|
||||
resp = '{"availability_zones": [], "available": true, "label": "Amsterdam 1", "name": "ams1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/"], "provider": "/api/v1/provider/digitalocean/", "resource_uri": "/api/v1/region/digitalocean/ams1/"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodetype_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 9}, ' \
|
||||
'"objects": [{"availability_zones": [], "available": true, "label": "512MB", "name": "512mb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/512mb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "1GB", "name": "1gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/1gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "2GB", "name": "2gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/2gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "4GB", "name": "4gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/4gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "8GB", "name": "8gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/8gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "16GB", "name": "16gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/16gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "32GB", "name": "32gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/32gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "48GB", "name": "48gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/48gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "64GB", "name": "64gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/64gb/"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodetype_fetch():
|
||||
status_code = 200
|
||||
resp = '{"availability_zones": [], "available": true, "label": "8GB", "name": "8gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/8gb/"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodeclster_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 2}, ' \
|
||||
'"objects": [{"current_num_nodes": 1, "deployed_datetime": "Mon, 29 Sep 2014 22:29:03 +0000", "destroyed_datetime": null, "name": "test", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "region": "/api/v1/region/digitalocean/sfo1/", "resource_uri": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "state": "Deployed", "target_num_nodes": 1, "uuid": "a02c3763-e639-46fc-a6db-587f4dbb5444"}, ' \
|
||||
'{"current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "test2", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "state": "Deploying", "target_num_nodes": 1, "uuid": "b616a720-6684-42c6-83bb-4d298b11b3f3"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodecluster_fetch():
|
||||
status_code = 200
|
||||
resp = '{"actions": ["/api/v1/action/bf02b00a-e2fc-4098-8b69-1424b659ef4a/", "/api/v1/action/f8dce6d4-5c41-46a9-9754-baa8f3cdf031/"], "current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "test2", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "nodes": ["/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "state": "Init", "target_num_nodes": 1, "uuid": "b616a720-6684-42c6-83bb-4d298b11b3f3"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodecluster_save():
|
||||
status_code = 201
|
||||
resp = '{"actions": ["/api/v1/action/f47e26a6-c60c-416f-a0a9-ddf14e3aae83/"], "current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "my_cluster", "node_type": "/api/v1/nodetype/digitalocean/1gb/", "nodes": ["/api/v1/node/2cfe7823-f551-4c7b-a82c-f6ab31d7ca25/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/e7915a74-618b-4908-9189-dce965465702/", "state": "Init", "target_num_nodes": 1, "uuid": "e7915a74-618b-4908-9189-dce965465702"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodecluster_deploy():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/f47e26a6-c60c-416f-a0a9-ddf14e3aae83/", "/api/v1/action/d110016e-e65d-4ce7-9f11-50c6302494a6/"], "current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "my_cluster", "node_type": "/api/v1/nodetype/digitalocean/1gb/", "nodes": ["/api/v1/node/2cfe7823-f551-4c7b-a82c-f6ab31d7ca25/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/e7915a74-618b-4908-9189-dce965465702/", "state": "Deploying", "target_num_nodes": 1, "uuid": "e7915a74-618b-4908-9189-dce965465702"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_nodecluster_delete():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/f47e26a6-c60c-416f-a0a9-ddf14e3aae83/", "/api/v1/action/d110016e-e65d-4ce7-9f11-50c6302494a6/", "/api/v1/action/e33b4bb1-192b-46a6-a1ba-eadfc494c2dd/"], "current_num_nodes": 1, "deployed_datetime": "Mon, 29 Sep 2014 23:45:45 +0000", "destroyed_datetime": null, "name": "my_cluster", "node_type": "/api/v1/nodetype/digitalocean/1gb/", "nodes": ["/api/v1/node/2cfe7823-f551-4c7b-a82c-f6ab31d7ca25/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/e7915a74-618b-4908-9189-dce965465702/", "state": "Terminating", "target_num_nodes": 0, "uuid": "e7915a74-618b-4908-9189-dce965465702"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_node_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 2}, ' \
|
||||
'"objects": [{"deployed_datetime": "Mon, 29 Sep 2014 22:29:03 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "fa9df19a-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:27:05 +0000", "node_cluster": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "198.199.97.190", "region": "/api/v1/region/digitalocean/sfo1/", "resource_uri": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "state": "Deployed", "uuid": "fa9df19a-162b-45b4-bb5a-152dfd1b133f"}, ' \
|
||||
'{"deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:27:06 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Deployed", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_node_fetch():
|
||||
status_code = 200
|
||||
resp = '{"actions": ["/api/v1/action/8f5b893b-826e-40b7-bb8b-2d96301425f2/"], "deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:30:06 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Deployed", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_node_delete():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/8f5b893b-826e-40b7-bb8b-2d96301425f2/", "/api/v1/action/83c66611-ea5d-45d7-a97d-914029a90524/"], "deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:38:12 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Terminating", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_node_deploy():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/8f5b893b-826e-40b7-bb8b-2d96301425f2/", "/api/v1/action/83c66611-ea5d-45d7-a97d-914029a90524/"], "deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:38:12 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Starting", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_image_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 1}, "objects": [{"base_image": false, "categories": [], "cluster_aware": true, "description": "", "docker_registry": "/api/v1/registry/docker.com/", "image_url": "", "imagetag_set": ["/api/v1/image/docker.com/tifayuki/mongodb/tag/latest/"], "is_private_image": true, "name": "docker.com/tifayuki/mongodb", "public_url": "", "resource_uri": "/api/v1/image/docker.com/tifayuki/mongodb/", "starred": false}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_image_fetch():
|
||||
status_code = 200
|
||||
resp = '{"base_image": false, "categories": [], "cluster_aware": true, "description": "", "docker_registry": {"created": true, "host": "registry.hub.docker.com", "id": 5, "image_url": "/_static/assets/images/dockerregistries/docker.png", "is_ssl": true, "is_tutum_registry": false, "modified": true, "name": "Docker.io", "resource_uri": "/api/v1/registry/registry.hub.docker.com/", "uuid": "d533039e-c44c-4cdc-951b-e0e03b8410c6"}, "image_url": "", "imagetag_set": [{"full_name": "tifayuki/cadvisor:latest", "image": {"author": "fake <fake@docker.com>", "docker_id": "9e2907ef52bf811b4da100f50ba8f0908ccc610c7054bd69087f0a9f4703efdd", "entrypoint": "", "image_creation": "Fri, 15 Aug 2014 15:19:04 +0000", "imageenvvar_set": [{"key": "CADVISOR_TAG", "value": "0.2.2"}, {"key": "DB_NAME", "value": "cadvisor"}, {"key": "DB_PASS", "value": "root"}, {"key": "DB_USER", "value": "root"}, {"key": "HOME", "value": "/"}, {"key": "PATH", "value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}], "imageport_set": [], "run_command": "/run.sh"}, "image_info": "/api/v1/image/tifayuki/cadvisor/", "name": "latest", "resource_uri": "/api/v1/image/tifayuki/cadvisor/tag/latest/"}], "is_private_image": true, "name": "tifayuki/cadvisor", "public_url": "https://registry.hub.docker.com/u/tifayuki/cadvisor/", "resource_uri": "/api/v1/image/tifayuki/cadvisor/", "starred": false}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_image_save():
|
||||
status_code = 202
|
||||
resp = '{"base_image": false, "categories": [], "cluster_aware": true, "description": "description", "docker_registry": {"created": true, "host": "registry.hub.docker.com", "id": 5, "image_url": "/_static/assets/images/dockerregistries/docker.png", "is_ssl": true, "is_tutum_registry": false, "modified": true, "name": "Docker.io", "resource_uri": "/api/v1/registry/registry.hub.docker.com/", "uuid": "d533039e-c44c-4cdc-951b-e0e03b8410c6"}, "image_url": "", "imagetag_set": [{"full_name": "tifayuki/cadvisor:latest", "image": {"author": "fake <fake@docker.com>", "docker_id": "9e2907ef52bf811b4da100f50ba8f0908ccc610c7054bd69087f0a9f4703efdd", "entrypoint": "", "image_creation": "Fri, 15 Aug 2014 15:19:04 +0000", "imageenvvar_set": [{"key": "CADVISOR_TAG", "value": "0.2.2"}, {"key": "DB_NAME", "value": "cadvisor"}, {"key": "DB_PASS", "value": "root"}, {"key": "DB_USER", "value": "root"}, {"key": "HOME", "value": "/"}, {"key": "PATH", "value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}], "imageport_set": [], "run_command": "/run.sh"}, "image_info": "/api/v1/image/tifayuki/cadvisor/", "name": "latest", "resource_uri": "/api/v1/image/tifayuki/cadvisor/tag/latest/"}], "is_private_image": true, "name": "tifayuki/cadvisor", "public_url": "https://registry.hub.docker.com/u/tifayuki/cadvisor/", "resource_uri": "/api/v1/image/tifayuki/cadvisor/", "starred": false}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_image_delete():
|
||||
status_code = 204
|
||||
resp = ''
|
||||
return status_code, resp
|
||||
|
||||
|
||||
def fake_service_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 1}, ' \
|
||||
'"objects": [{"autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "cpu_shares": null, "current_num_containers": 3, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "state": "Running", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 3, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_fetch():
|
||||
status_code = 200
|
||||
resp = '{"actions": ["/api/v1/action/e3ee01df-9f2f-4720-a114-ea1a236d47d2/", "/api/v1/action/c58213ab-8d5c-4a6d-b4c3-bd7157242dc2/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "containers": ["/api/v1/container/cff4dfa7-28a5-4599-a3f9-c7dc39353c11/", "/api/v1/container/4d966087-5169-4a0b-a2f0-78bbb878d872/", "/api/v1/container/0c84cd78-c239-40ad-939e-dbbc372ae345/"], "cpu_shares": null, "current_num_containers": 3, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "link_variables": {"HELLO_WORLD_1_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_1_ENV_HOME": "/", "HELLO_WORLD_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_1_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_1_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_1_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_2_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_2_ENV_HOME": "/", "HELLO_WORLD_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_2_PORT": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP_ADDR": "hello-world-2.a2f5a2e9-tifayuki.node.docker.io", "HELLO_WORLD_2_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_2_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_3_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_3_ENV_HOME": "/", "HELLO_WORLD_3_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_3_PORT": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP_ADDR": "hello-world-3.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_3_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_3_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_ENV_HOME": "/", "HELLO_WORLD_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "roles": [], "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "state": "Running", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 3, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_save():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/e3ee01df-9f2f-4720-a114-ea1a236d47d2/", "/api/v1/action/c58213ab-8d5c-4a6d-b4c3-bd7157242dc2/", "/api/v1/action/b3adfa79-dbd2-41a4-8c71-5e242ecce9bb/", "/api/v1/action/f82e25e7-d550-454e-a897-8599f2f530e5/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "containers": ["/api/v1/container/cff4dfa7-28a5-4599-a3f9-c7dc39353c11/", "/api/v1/container/4d966087-5169-4a0b-a2f0-78bbb878d872/", "/api/v1/container/0c84cd78-c239-40ad-939e-dbbc372ae345/"], "cpu_shares": null, "current_num_containers": 3, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "link_variables": {"HELLO_WORLD_1_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_1_ENV_HOME": "/", "HELLO_WORLD_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_1_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_1_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_1_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_2_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_2_ENV_HOME": "/", "HELLO_WORLD_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_2_PORT": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP_ADDR": "hello-world-2.a2f5a2e9-tifayuki.node.docker.io", "HELLO_WORLD_2_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_2_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_3_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_3_ENV_HOME": "/", "HELLO_WORLD_3_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_3_PORT": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP_ADDR": "hello-world-3.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_3_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_3_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_ENV_HOME": "/", "HELLO_WORLD_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "roles": [], "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "state": "Scaling", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 5, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8", "web_public_dns": ""}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_delete():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/e3ee01df-9f2f-4720-a114-ea1a236d47d2/", "/api/v1/action/c58213ab-8d5c-4a6d-b4c3-bd7157242dc2/", "/api/v1/action/b3adfa79-dbd2-41a4-8c71-5e242ecce9bb/", "/api/v1/action/f82e25e7-d550-454e-a897-8599f2f530e5/", "/api/v1/action/381c53a0-bf18-4a01-a1b0-be87051c35e8/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "containers": ["/api/v1/container/cff4dfa7-28a5-4599-a3f9-c7dc39353c11/", "/api/v1/container/4d966087-5169-4a0b-a2f0-78bbb878d872/", "/api/v1/container/0c84cd78-c239-40ad-939e-dbbc372ae345/", "/api/v1/container/6e74df59-83ee-4351-8ba9-3d26e0d64c34/", "/api/v1/container/7bbff9f0-af41-408f-9dd0-213cd67e4aa2/"], "cpu_shares": null, "current_num_containers": 5, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "link_variables": {"HELLO_WORLD_1_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_1_ENV_HOME": "/", "HELLO_WORLD_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_1_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_1_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_1_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_2_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_2_ENV_HOME": "/", "HELLO_WORLD_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_2_PORT": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP_ADDR": "hello-world-2.a2f5a2e9-tifayuki.node.docker.io", "HELLO_WORLD_2_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_2_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_3_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_3_ENV_HOME": "/", "HELLO_WORLD_3_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_3_PORT": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP_ADDR": "hello-world-3.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_3_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_3_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_4_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_4_ENV_HOME": "/", "HELLO_WORLD_4_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_4_PORT": "tcp://hello-world-4.5067d4f4-tifayuki.node.docker.io:49156", "HELLO_WORLD_4_PORT_80_TCP": "tcp://hello-world-4.5067d4f4-tifayuki.node.docker.io:49156", "HELLO_WORLD_4_PORT_80_TCP_ADDR": "hello-world-4.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_4_PORT_80_TCP_PORT": "49156", "HELLO_WORLD_4_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_5_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_5_ENV_HOME": "/", "HELLO_WORLD_5_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_5_PORT": "tcp://hello-world-5.fa9df19a-tifayuki.node.docker.io:49157", "HELLO_WORLD_5_PORT_80_TCP": "tcp://hello-world-5.fa9df19a-tifayuki.node.docker.io:49157", "HELLO_WORLD_5_PORT_80_TCP_ADDR": "hello-world-5.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_5_PORT_80_TCP_PORT": "49157", "HELLO_WORLD_5_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_ENV_HOME": "/", "HELLO_WORLD_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-t* Connection #0 to host dashboard.docker.com left intactifayuki.node.docker.io", "HELLO_WORLD_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "roles": [], "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 22:57:36 +0000", "state": "Terminating", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 0, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_start():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/a8aaf64b-3186-41e7-9256-6b3d69786036/", "/api/v1/action/2481790d-a860-4bb4-95d2-5676ae2d6748/", "/api/v1/action/799a0d06-efae-4bf1-b063-7141f722cbb1/", "/api/v1/action/ef6b9f59-1edb-44c7-bcc6-1b80f737e4b0/", "/api/v1/action/99b7ac29-d16d-448f-bac5-54dbd5dd3b7b/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 3306, "outer_port": null, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "containers": ["/api/v1/container/2a1c4057-7753-4393-98c6-35699c198e08/", "/api/v1/container/54ead360-698f-4354-96f7-538f686cdd69/"], "cpu_shares": null, "current_num_containers": 2, "deployed_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "link_variables": {"MYSQL_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "mysql", "resource_uri": "/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/", "roles": [], "run_command": "/run.sh", "running_num_containers": 0, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "state": "Starting", "stopped_datetime": "Tue, 30 Sep 2014 23:09:09 +0000", "stopped_num_containers": 2, "target_num_containers": 2, "unique_name": "mysql", "uuid": "5ecde92d-498b-4bbb-b773-a998e5e421dc"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_stop():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/a8aaf64b-3186-41e7-9256-6b3d69786036/", "/api/v1/action/2481790d-a860-4bb4-95d2-5676ae2d6748/", "/api/v1/action/799a0d06-efae-4bf1-b063-7141f722cbb1/", "/api/v1/action/ef6b9f59-1edb-44c7-bcc6-1b80f737e4b0/", "/api/v1/action/99b7ac29-d16d-448f-bac5-54dbd5dd3b7b/", "/api/v1/action/98816bfc-4fa7-4697-bea1-d926de69b48f/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 3306, "outer_port": null, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "containers": ["/api/v1/container/2a1c4057-7753-4393-98c6-35699c198e08/", "/api/v1/container/54ead360-698f-4354-96f7-538f686cdd69/"], "cpu_shares": null, "current_num_containers": 2, "deployed_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "link_variables": {"MYSQL_1_ENV_DEBIAN_FRONTEND": "noninteractive", "MYSQL_1_ENV_MYSQL_PASS": "**Random**", "MYSQL_1_ENV_MYSQL_USER": "admin", "MYSQL_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "MYSQL_1_ENV_REPLICATION_MASTER": "**False**", "MYSQL_1_ENV_REPLICATION_PASS": "replica", "MYSQL_1_ENV_REPLICATION_SLAVE": "**False**", "MYSQL_1_ENV_REPLICATION_USER": "replica", "MYSQL_1_PORT": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_1_PORT_3306_TCP": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_1_PORT_3306_TCP_ADDR": "mysql-1.fa9df19a-tifayuki.node.docker.io", "MYSQL_1_PORT_3306_TCP_PORT": "49156", "MYSQL_1_PORT_3306_TCP_PROTO": "tcp", "MYSQL_2_ENV_DEBIAN_FRONTEND": "noninteractive", "MYSQL_2_ENV_MYSQL_PASS": "**Random**", "MYSQL_2_ENV_MYSQL_USER": "admin", "MYSQL_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "MYSQL_2_ENV_REPLICATION_MASTER": "**False**", "MYSQL_2_ENV_REPLICATION_PASS": "replica", "MYSQL_2_ENV_REPLICATION_SLAVE": "**False**", "MYSQL_2_ENV_REPLICATION_USER": "replica", "MYSQL_2_PORT": "tcp://mysql-2.a2f5a2e9-tifayuki.node.docker.io:49156", "MYSQL_2_PORT_3306_TCP": "tcp://mysql-2.a2f5a2e9-tifayuki.node.docker.io:49156", "MYSQL_2_PORT_3306_TCP_ADDR": "mysql-2.a2f5a2e9-tifayuki.node.docker.io", "MYSQL_2_PORT_3306_TCP_PORT": "49156", "MYSQL_2_PORT_3306_TCP_PROTO": "tcp", "MYSQL_ENV_DEBIAN_FRONTEND": "noninteractive", "MYSQL_ENV_MYSQL_PASS": "**Random**", "MYSQL_ENV_MYSQL_USER": "admin", "MYSQL_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "MYSQL_ENV_REPLICATION_MASTER": "**False**", "MYSQL_ENV_REPLICATION_PASS": "replica", "MYSQL_ENV_REPLICATION_SLAVE": "**False**", "MYSQL_ENV_REPLICATION_USER": "replica", "MYSQL_PORT": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_PORT_3306_TCP": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_PORT_3306_TCP_ADDR": "mysql-1.fa9df19a-tifayuki.node.docker.io", "MYSQL_PORT_3306_TCP_PORT": "49156", "MYSQL_PORT_3306_TCP_PROTO": "tcp", "MYSQL_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "mysql", "resource_uri": "/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/", "roles": [], "run_command": "/run.sh", "running_num_containers": 1, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 23:50:59 +0000", "state": "Stopping", "stopped_datetime": "Tue, 30 Sep 2014 23:09:09 +0000", "stopped_num_containers": 0, "target_num_containers": 2, "unique_name": "mysql", "uuid": "5ecde92d-498b-4bbb-b773-a998e5e421dc"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_redeploy():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/a8aaf64b-3186-41e7-9256-6b3d69786036/", "/api/v1/action/2481790d-a860-4bb4-95d2-5676ae2d6748/", "/api/v1/action/799a0d06-efae-4bf1-b063-7141f722cbb1/", "/api/v1/action/ef6b9f59-1edb-44c7-bcc6-1b80f737e4b0/", "/api/v1/action/99b7ac29-d16d-448f-bac5-54dbd5dd3b7b/", "/api/v1/action/98816bfc-4fa7-4697-bea1-d926de69b48f/", "/api/v1/action/285e250f-7429-4f0a-a252-5594a05c8020/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 3306, "outer_port": null, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "containers": ["/api/v1/container/2a1c4057-7753-4393-98c6-35699c198e08/", "/api/v1/container/54ead360-698f-4354-96f7-538f686cdd69/"], "cpu_shares": null, "current_num_containers": 2, "deployed_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "link_variables": {"MYSQL_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "mysql", "resource_uri": "/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/", "roles": [], "run_command": "/run.sh", "running_num_containers": 0, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 23:50:59 +0000", "state": "Redeploying", "stopped_datetime": "Tue, 30 Sep 2014 23:51:52 +0000", "stopped_num_containers": 0, "target_num_containers": 2, "unique_name": "mysql", "uuid": "5ecde92d-498b-4bbb-b773-a998e5e421dc"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_service_logs():
|
||||
status_code = 200
|
||||
resp = r'{"logs": "[mysql-1] 2014-09-30T22:44:31.385643366Z => An empty or uninitialized MySQL volume is detected in /var/lib/mysql\n[mysql-1] 2014-09-30T22:44:31.386200239Z => Installing MySQL ...\n"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_container_list():
|
||||
status_code = 200
|
||||
resp = '{"meta": {"limit": 25, "next": null, "offset": 0, "previous": null, "total_count": 2}, ' \
|
||||
'"objects": [{"autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_ports": [{"endpoint_uri": "mysql://mysql-1.fa9df19a-tifayuki.node.docker.io:49159/", "inner_port": 3306, "outer_port": 49159, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:44:32 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "is_dead_backend": null, "memory": null, "memory_swap": null, "name": "mysql", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "mysql-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/567f1ff8-57bd-4689-a732-1e1705bc5082/", "run_command": "/run.sh", "service": "/api/v1/service/326a2daf-2069-4cd4-9e44-08faa068a62f/", "started_datetime": "Wed, 1 Oct 2014 14:44:32 +0000", "state": "Running", "stopped_datetime": null, "unique_name": "mysql-1", "uuid": "567f1ff8-57bd-4689-a732-1e1705bc5082"}, {"autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Running", "stopped_datetime": null, "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}]}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_container_fetch():
|
||||
status_code = 200
|
||||
resp = '{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Running", "stopped_datetime": null, "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_container_delete():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/", "/api/v1/action/5c435933-a1d9-449e-acb6-fbe7b5904b26/", "/api/v1/action/2508d37c-57a8-4ef1-88ff-3b5e20f88b7f/", "/api/v1/action/0438248f-b05c-41f2-b715-40a788735deb/", "/api/v1/action/6a5b82a0-b14a-4c05-94d0-117d730cb647/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": 0, "exit_code_msg": "Exit code 0 (Success)", "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 15:22:51 +0000", "state": "Terminating", "stopped_datetime": "Wed, 1 Oct 2014 15:20:58 +0000", "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_container_start():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/", "/api/v1/action/5c435933-a1d9-449e-acb6-fbe7b5904b26/", "/api/v1/action/2508d37c-57a8-4ef1-88ff-3b5e20f88b7f/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": 0, "exit_code_msg": "Exit code 0 (Success)", "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Starting", "stopped_datetime": "Wed, 1 Oct 2014 15:20:58 +0000", "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_container_stop():
|
||||
status_code = 202
|
||||
resp = '{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Stopping", "stopped_datetime": null, "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
return status_code, json.loads(resp)
|
||||
|
||||
|
||||
def fake_container_logs():
|
||||
status_code = 200
|
||||
resp = r'{"logs": "2014-10-01T14:54:23.173185119Z => An empty or uninitialized MySQL volume is detected in /var/lib/mysql\n2014-10-01T14:54:23.173350403Z => Installing MySQL ...\n2014-10-01T14:54:23.467005403Z => Done!\n"}'
|
||||
return status_code, json.loads(resp)
|
||||
35
tests/test_action.py
Normal file
35
tests/test_action.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class ActionTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_action_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"action": "Node Cluster Create", "end_date": "Mon, 29 Sep 2014 15:40:59 +0000", "ip": "207.41.188.212", "location": "New York, United States", "method": "POST", "object": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "path": "/api/v1/nodecluster/", "resource_uri": "/api/v1/action/7f62b667-2693-420a-ad2e-41cda5605322/", "start_date": "Mon, 29 Sep 2014 15:40:59 +0000", "state": "Success", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "7f62b667-2693-420a-ad2e-41cda5605322"}, ' \
|
||||
'{"action": "Node Cluster Deploy", "end_date": "Mon, 29 Sep 2014 15:41:01 +0000", "ip": "207.41.188.212", "location": "New York, United States", "method": "POST", "object": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "path": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/deploy/", "resource_uri": "/api/v1/action/db69b048-3bab-4a2e-bcbd-91265edf1a31/", "start_date": "Mon, 29 Sep 2014 15:41:00 +0000", "state": "Failed", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "db69b048-3bab-4a2e-bcbd-91265edf1a31"}, ' \
|
||||
'{"action": "Node Deploy", "end_date": "Mon, 29 Sep 2014 15:41:16 +0000", "ip": "207.41.188.212", "location": "New York, United States", "method": "POST", "object": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "path": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/deploy/", "resource_uri": "/api/v1/action/ce9ae16b-88fa-4be6-b12e-fc970b8d2445/", "start_date": "Mon, 29 Sep 2014 15:41:16 +0000", "state": "Failed", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "ce9ae16b-88fa-4be6-b12e-fc970b8d2445"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_action_list)
|
||||
actions = dockercloud.Action.list()
|
||||
for i in range(0, len(actions)):
|
||||
result = json.loads(json.dumps(actions[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_action_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"action": "Node Cluster Create", "end_date": "Mon, 29 Sep 2014 15:40:59 +0000", "ip": "207.41.188.212", "location": "New York, United States", "logs": "", "method":"POST", "object": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "path": "/api/v1/nodecluster/", "resource_uri": "/api/v1/action/7f62b667-2693-420a-ad2e-41cda5605322/", "start_date": "Mon, 29 Sep 2014 15:40:59 +0000", "state": "Success", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", "uuid": "7f62b667-2693-420a-ad2e-41cda5605322"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_action_fetch)
|
||||
action = dockercloud.Action.fetch("7f62b667-2693-420a-ad2e-41cda5605322")
|
||||
result = json.loads(json.dumps(action.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
89
tests/test_auth.py
Normal file
89
tests/test_auth.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class AuthTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.dockercloud_auth = dockercloud.dockercloud_auth
|
||||
self.basic_auth = dockercloud.basic_auth
|
||||
|
||||
def tearDown(self):
|
||||
dockercloud.dockercloud_auth = self.dockercloud_auth
|
||||
dockercloud.basic_auth = self.basic_auth
|
||||
|
||||
@mock.patch('dockercloud.api.auth.verify_credential')
|
||||
def test_auth_authenticate(self, mock_verify_credential):
|
||||
dockercloud.auth.authenticate(FAKE_USER, FAKE_PASSWORD)
|
||||
mock_verify_credential.assert_called_with(FAKE_USER, FAKE_PASSWORD)
|
||||
self.assertEqual(dockercloud.basic_auth, FAKE_BASIC_AUTH)
|
||||
self.tearDown()
|
||||
|
||||
def test_auth_is_authenticated(self):
|
||||
dockercloud.dockercloud_auth = FAKE_DOCKERCLOUD_AUTH
|
||||
dockercloud.basic_auth = FAKE_BASIC_AUTH
|
||||
self.assertTrue(dockercloud.auth.is_authenticated())
|
||||
|
||||
dockercloud.dockercloud_auth = None
|
||||
dockercloud.basic_auth = FAKE_BASIC_AUTH
|
||||
self.assertTrue(dockercloud.auth.is_authenticated())
|
||||
|
||||
dockercloud.dockercloud_auth = FAKE_DOCKERCLOUD_AUTH
|
||||
dockercloud.basic_auth = None
|
||||
dockercloud.apikey_auth = None
|
||||
self.assertTrue(dockercloud.auth.is_authenticated())
|
||||
|
||||
dockercloud.dockercloud_auth = None
|
||||
dockercloud.basic_auth = None
|
||||
self.assertFalse(dockercloud.auth.is_authenticated())
|
||||
|
||||
def test_auth_logout(self):
|
||||
dockercloud.dockercloud_auth = FAKE_DOCKERCLOUD_AUTH
|
||||
dockercloud.basic_auth = FAKE_BASIC_AUTH
|
||||
dockercloud.auth.logout()
|
||||
self.assertIsNone(dockercloud.dockercloud_auth)
|
||||
self.assertIsNone(dockercloud.basic_auth)
|
||||
|
||||
def test_auth_load_from_file(self):
|
||||
temp = tempfile.NamedTemporaryFile('w', delete=False)
|
||||
with temp as f:
|
||||
f.write('''{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "%s",
|
||||
"email": "tifayuki@gmail.com"
|
||||
}
|
||||
}
|
||||
}''' % FAKE_BASIC_AUTH)
|
||||
basic_auth = dockercloud.auth.load_from_file(f.name)
|
||||
self.assertEqual(basic_auth, FAKE_BASIC_AUTH)
|
||||
os.remove(temp.name)
|
||||
|
||||
def test_auth_load_from_file_with_exception(self):
|
||||
basic_auth = dockercloud.auth.load_from_file('abc')
|
||||
self.assertIsNone(basic_auth)
|
||||
|
||||
def test_auth_get_auth_header(self):
|
||||
dockercloud.dockercloud_auth = FAKE_DOCKERCLOUD_AUTH
|
||||
dockercloud.basic_auth = FAKE_BASIC_AUTH
|
||||
self.assertEqual({'Authorization': FAKE_DOCKERCLOUD_AUTH}, dockercloud.auth.get_auth_header())
|
||||
|
||||
print "===================="
|
||||
dockercloud.dockercloud_auth = None
|
||||
dockercloud.basic_auth = FAKE_BASIC_AUTH
|
||||
self.assertEqual({'Authorization': 'Basic %s' % (FAKE_BASIC_AUTH)}, dockercloud.auth.get_auth_header())
|
||||
|
||||
dockercloud.dockercloud_auth = FAKE_DOCKERCLOUD_AUTH
|
||||
dockercloud.basic_auth = None
|
||||
self.assertEqual({'Authorization': FAKE_DOCKERCLOUD_AUTH}, dockercloud.auth.get_auth_header())
|
||||
|
||||
dockercloud.dockercloud_auth = None
|
||||
dockercloud.basic_auth = None
|
||||
self.assertEqual({}, dockercloud.auth.get_auth_header())
|
||||
252
tests/test_base.py
Normal file
252
tests/test_base.py
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import json
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from dockercloud.api.base import Restful, Mutable, Immutable
|
||||
|
||||
|
||||
class RestfulTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.pk = Restful.pk
|
||||
Restful.pk = 'uuid'
|
||||
|
||||
def tearDown(self):
|
||||
Restful.pk = self.pk
|
||||
|
||||
def test_restful_init(self):
|
||||
model = Restful(key1='value1', key2='value2')
|
||||
self.assertEqual('value1', model.key1)
|
||||
self.assertEqual('value2', model.key2)
|
||||
|
||||
def test_restful_setattr(self):
|
||||
model = Restful()
|
||||
|
||||
setattr(model, 'key', 'value')
|
||||
self.assertEqual('value', model.key)
|
||||
self.assertEqual(['key'], model.__changedattrs__)
|
||||
|
||||
setattr(model, 'key', 'other value')
|
||||
self.assertEqual('other value', model.key)
|
||||
self.assertEqual(['key'], model.__changedattrs__)
|
||||
|
||||
setattr(model, 'another_key', 'another_value')
|
||||
self.assertEqual('another_value', model.another_key)
|
||||
self.assertEqual(['key', 'another_key'], model.__changedattrs__)
|
||||
|
||||
def test_restful_getchanges(self):
|
||||
model = Restful()
|
||||
self.assertEqual([], model.__getchanges__())
|
||||
|
||||
model.__changedattrs__ = ['dockercloud']
|
||||
self.assertEqual(['dockercloud'], model.__getchanges__())
|
||||
|
||||
def test_restful_setchanges(self):
|
||||
model = Restful()
|
||||
model.__setchanges__('abc')
|
||||
self.assertEqual('abc', model.__changedattrs__)
|
||||
|
||||
model.__setchanges__(None)
|
||||
self.assertIsNone(model.__changedattrs__)
|
||||
|
||||
def test_restful_loaddict(self):
|
||||
model = Restful()
|
||||
self.assertRaises(AssertionError, model._loaddict, {'key': 'value'})
|
||||
|
||||
model.endpoint = 'endpoint'
|
||||
model.subsystem = "subsystem"
|
||||
model._loaddict({'key': 'value'})
|
||||
self.assertEqual('value', model.key)
|
||||
self.assertEqual("/".join(["api", model.subsystem, model._api_version, model.endpoint.lstrip("/"), model.pk]),
|
||||
model._detail_uri)
|
||||
self.assertEqual([], model.__getchanges__())
|
||||
|
||||
def test_restful_pk(self):
|
||||
model = Restful()
|
||||
self.assertEqual(model.__class__._pk_key(), model.pk)
|
||||
|
||||
def test_restful_is_dirty(self):
|
||||
model = Restful()
|
||||
self.assertFalse(model.is_dirty)
|
||||
|
||||
model.key = 'value'
|
||||
self.assertTrue(model.is_dirty)
|
||||
|
||||
@mock.patch('dockercloud.api.base.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.subsystem = "subsystem"
|
||||
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'}))
|
||||
|
||||
finally:
|
||||
if hasattr(Restful, 'endpoint'):
|
||||
delattr(Restful, 'endpoint')
|
||||
|
||||
@mock.patch('dockercloud.api.base.send_request')
|
||||
def test_restful_expand_attribute(self, mock_send_request):
|
||||
model = Restful()
|
||||
self.assertRaises(dockercloud.ApiError, model._expand_attribute, 'attribute')
|
||||
|
||||
model._detail_uri = 'fake/uuid'
|
||||
mock_send_request.side_effect = [{'key': 'value'}, None]
|
||||
self.assertEqual('value', model._expand_attribute('key'))
|
||||
|
||||
self.assertIsNone(model._expand_attribute('key'))
|
||||
|
||||
def test_restful_get_all_attributes(self):
|
||||
model = Restful()
|
||||
model.key = 'value'
|
||||
self.assertDictEqual({'key': 'value'}, model.get_all_attributes())
|
||||
|
||||
|
||||
class ImmutableTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.pk = Immutable.pk
|
||||
Immutable.pk = 'uuid'
|
||||
|
||||
def tearDown(self):
|
||||
Immutable.pk = self.pk
|
||||
|
||||
@mock.patch('dockercloud.api.base.send_request')
|
||||
def test_immutable_fetch(self, mock_send_request):
|
||||
self.assertRaises(AssertionError, Immutable.fetch, 'uuid')
|
||||
|
||||
try:
|
||||
ret_json = {"key": "value"}
|
||||
mock_send_request.return_value = ret_json
|
||||
Immutable.endpoint = 'endpoint'
|
||||
Immutable.subsystem = "subsystem"
|
||||
model = Immutable.fetch('uuid')
|
||||
mock_send_request.assert_called_with('GET', 'api/subsystem/%s/endpoint/uuid' % Immutable._api_version)
|
||||
self.assertIsInstance(model, Immutable)
|
||||
self.assertEqual('value', model.key)
|
||||
finally:
|
||||
if hasattr(Immutable, 'endpoint'):
|
||||
delattr(Immutable, 'endpoint')
|
||||
|
||||
@mock.patch('dockercloud.api.base.send_request')
|
||||
def test_immutable_list(self, mock_send_request):
|
||||
self.assertRaises(AssertionError, Immutable.list)
|
||||
try:
|
||||
kwargs = {'key': 'value'}
|
||||
ret_json = {"meta": {"limit": 25, "next": None, "offset": 0, "previous": None, "total_count": 1},
|
||||
"objects": [{"key": "value1"}, {"key": "value2"}]}
|
||||
mock_send_request.return_value = ret_json
|
||||
Immutable.endpoint = 'fake'
|
||||
models = Immutable.list(**kwargs)
|
||||
mock_send_request.assert_called_with('GET', 'api/subsystem/%s/fake' % Immutable._api_version, params=kwargs)
|
||||
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)
|
||||
finally:
|
||||
if hasattr(Immutable, 'endpoint'):
|
||||
delattr(Immutable, 'endpoint')
|
||||
|
||||
@mock.patch('dockercloud.api.base.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)
|
||||
|
||||
Immutable.endpoint = 'endpoint'
|
||||
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))
|
||||
mock_send_request.assert_called_with('GET', model._detail_uri)
|
||||
finally:
|
||||
if hasattr(Immutable, 'endpoint'):
|
||||
delattr(Immutable, 'endpoint')
|
||||
|
||||
|
||||
class MutableTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.pk = Mutable.pk
|
||||
Mutable.pk = 'uuid'
|
||||
|
||||
def tearDown(self):
|
||||
Mutable.pk = self.pk
|
||||
|
||||
def test_mutable_create(self):
|
||||
self.assertIsInstance(Mutable.create(), Mutable)
|
||||
|
||||
@mock.patch('dockercloud.api.base.send_request')
|
||||
def test_mutable_delete(self, mock_send_request):
|
||||
try:
|
||||
model = Mutable()
|
||||
self.assertRaises(dockercloud.ApiError, model.delete)
|
||||
|
||||
Mutable.endpoint = 'fake'
|
||||
model._detail_uri = 'fake/uuid'
|
||||
mock_send_request.side_effect = [{'key': 'value'}, None]
|
||||
self.assertTrue(model.delete())
|
||||
self.assertEqual('value', model.key)
|
||||
mock_send_request.assert_called_with('DELETE', 'fake/uuid')
|
||||
|
||||
self.assertTrue(model.delete())
|
||||
self.assertIsNone(model._detail_uri)
|
||||
self.assertFalse(model.is_dirty)
|
||||
finally:
|
||||
if hasattr(Mutable, 'endpoint'):
|
||||
delattr(Mutable, 'endpoint')
|
||||
|
||||
@mock.patch('dockercloud.api.base.send_request')
|
||||
def test_mutable_save(self, mock_send_request):
|
||||
try:
|
||||
self.assertTrue(Mutable().save())
|
||||
|
||||
model = Mutable()
|
||||
model.key = 'value'
|
||||
self.assertRaises(AssertionError, model.save)
|
||||
|
||||
Mutable.endpoint = 'endpoint'
|
||||
Mutable.subsystem = 'subsystem'
|
||||
mock_send_request.return_value = None
|
||||
result = model.save()
|
||||
mock_send_request.assert_called_with('POST', 'api/subsystem/%s/endpoint' % Mutable._api_version,
|
||||
data=json.dumps({'key': 'value'}))
|
||||
self.assertFalse(result)
|
||||
|
||||
mock_send_request.return_value = {'newkey': 'newvalue'}
|
||||
result = model.save()
|
||||
mock_send_request.assert_called_with('POST', 'api/subsystem/%s/endpoint' % Mutable._api_version,
|
||||
data=json.dumps({'key': 'value'}))
|
||||
self.assertTrue(result)
|
||||
self.assertEqual('newvalue', model.newkey)
|
||||
|
||||
model.key = 'another value'
|
||||
mock_send_request.return_value = {'newkey2': 'newvalue2'}
|
||||
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')
|
||||
70
tests/test_container.py
Normal file
70
tests/test_container.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class ContainerTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_container_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_ports": [{"endpoint_uri": "mysql://mysql-1.fa9df19a-tifayuki.node.docker.io:49159/", "inner_port": 3306, "outer_port": 49159, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:44:32 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "is_dead_backend": null, "memory": null, "memory_swap": null, "name": "mysql", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "mysql-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/567f1ff8-57bd-4689-a732-1e1705bc5082/", "run_command": "/run.sh", "service": "/api/v1/service/326a2daf-2069-4cd4-9e44-08faa068a62f/", "started_datetime": "Wed, 1 Oct 2014 14:44:32 +0000", "state": "Running", "stopped_datetime": null, "unique_name": "mysql-1", "uuid": "567f1ff8-57bd-4689-a732-1e1705bc5082"}, {"autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Running", "stopped_datetime": null, "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_container_list)
|
||||
containers = dockercloud.Container.list()
|
||||
for i in range(0, len(containers)):
|
||||
result = json.loads(json.dumps(containers[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_container_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Running", "stopped_datetime": null, "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_container_fetch)
|
||||
container = dockercloud.Container.fetch('52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d')
|
||||
self.assertTrue(container.start())
|
||||
result = json.loads(json.dumps(container.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_container_delete(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/", "/api/v1/action/5c435933-a1d9-449e-acb6-fbe7b5904b26/", "/api/v1/action/2508d37c-57a8-4ef1-88ff-3b5e20f88b7f/", "/api/v1/action/0438248f-b05c-41f2-b715-40a788735deb/", "/api/v1/action/6a5b82a0-b14a-4c05-94d0-117d730cb647/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": 0, "exit_code_msg": "Exit code 0 (Success)", "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 15:22:51 +0000", "state": "Terminating", "stopped_datetime": "Wed, 1 Oct 2014 15:20:58 +0000", "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_container_fetch), fake_resp(fake_container_delete)]
|
||||
container = dockercloud.Container.fetch('52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d')
|
||||
self.assertTrue(container.delete())
|
||||
result = json.loads(json.dumps(container.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_container_start(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/", "/api/v1/action/5c435933-a1d9-449e-acb6-fbe7b5904b26/", "/api/v1/action/2508d37c-57a8-4ef1-88ff-3b5e20f88b7f/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": 0, "exit_code_msg": "Exit code 0 (Success)", "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Starting", "stopped_datetime": "Wed, 1 Oct 2014 15:20:58 +0000", "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_container_fetch), fake_resp(fake_container_start)]
|
||||
container = dockercloud.Container.fetch('52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d')
|
||||
self.assertTrue(container.start())
|
||||
result = json.loads(json.dumps(container.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_container_stop(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/62b1f681-5c0a-4b4e-8bc7-570f62020711/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": "http://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160/", "inner_port": 80, "outer_port": 49160, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}, {"endpoint_uri": "mysql://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161/", "inner_port": 3306, "outer_port": 49161, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "cpu_shares": null, "deployed_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "destroyed_datetime": null, "entrypoint": "", "exit_code": null, "exit_code_msg": null, "image_name": "tutum/wordpress:latest", "image_tag": "/api/v1/image/tutum/wordpress/tag/latest/", "is_dead_backend": null, "link_variables": {"WORDPRESS_1_ENV_HOME": "/", "WORDPRESS_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_1_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_1_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_1_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_1_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_3306_TCP_PORT": "49161", "WORDPRESS_1_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_1_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_1_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_1_PORT_80_TCP_PORT": "49160", "WORDPRESS_1_PORT_80_TCP_PROTO": "tcp", "WORDPRESS_ENV_HOME": "/", "WORDPRESS_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "WORDPRESS_ENV_PHP_POST_MAX_SIZE": "10M", "WORDPRESS_ENV_PHP_UPLOAD_MAX_FILESIZE": "10M", "WORDPRESS_PORT_3306_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49161", "WORDPRESS_PORT_3306_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_3306_TCP_PORT": "49161", "WORDPRESS_PORT_3306_TCP_PROTO": "tcp", "WORDPRESS_PORT_80_TCP": "tcp://wordpress-1.fa9df19a-tifayuki.node.docker.io:49160", "WORDPRESS_PORT_80_TCP_ADDR": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "WORDPRESS_PORT_80_TCP_PORT": "49160", "WORDPRESS_PORT_80_TCP_PROTO": "tcp"}, "memory": null, "memory_swap": null, "name": "wordpress", "node": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "public_dns": "wordpress-1.fa9df19a-tifayuki.node.docker.io", "resource_uri": "/api/v1/container/52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d/", "roles": [], "run_command": "/run.sh", "service": "/api/v1/service/81bbc30a-35de-4f5e-840d-87bc2573d818/", "started_datetime": "Wed, 1 Oct 2014 14:54:23 +0000", "state": "Stopping", "stopped_datetime": null, "unique_name": "wordpress-1", "uuid": "52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_container_fetch), fake_resp(fake_container_stop)]
|
||||
container = dockercloud.Container.fetch('52fffbca-88b2-4eac-a66d-8f8ca7e3ff2d')
|
||||
self.assertTrue(container.stop())
|
||||
result = json.loads(json.dumps(container.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
33
tests/test_http.py
Normal file
33
tests/test_http.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import requests
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from dockercloud.api.base import send_request
|
||||
from .fake_api import fake_resp
|
||||
|
||||
|
||||
class SendRequestTestCase(unittest.TestCase):
|
||||
@mock.patch('dockercloud.api.http.Request', return_value=requests.Request('GET', 'http://fake.com'))
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_http_send_request(self, mock_send, mock_Request):
|
||||
json_obj = {'key': 'value'}
|
||||
mock_send.return_value = fake_resp(lambda: (None, json_obj))
|
||||
self.assertRaises(dockercloud.ApiError, send_request, 'METHOD', 'path', data='data')
|
||||
headers = {'Content-Type': 'application/json', 'User-Agent': 'python-dockercloud/%s' % dockercloud.__version__}
|
||||
headers.update(dockercloud.auth.get_auth_header())
|
||||
|
||||
mock_send.return_value = fake_resp(lambda: (200, json_obj))
|
||||
self.assertEqual(json_obj, send_request('METHOD', 'path'))
|
||||
|
||||
mock_send.return_value = fake_resp(lambda: (204, json_obj))
|
||||
self.assertIsNone(send_request('METHOD', 'path'))
|
||||
|
||||
mock_send.return_value = fake_resp(lambda: (401, json_obj))
|
||||
self.assertRaises(dockercloud.AuthError, send_request, 'METHOD', 'path')
|
||||
|
||||
mock_send.return_value = fake_resp(lambda: (500, json_obj))
|
||||
self.assertRaises(dockercloud.ApiError, send_request, 'METHOD', 'path')
|
||||
61
tests/test_node.py
Normal file
61
tests/test_node.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class NodeTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_node_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"deployed_datetime": "Mon, 29 Sep 2014 22:29:03 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "fa9df19a-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:27:05 +0000", "node_cluster": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "198.199.97.190", "region": "/api/v1/region/digitalocean/sfo1/", "resource_uri": "/api/v1/node/fa9df19a-162b-45b4-bb5a-152dfd1b133f/", "state": "Deployed", "uuid": "fa9df19a-162b-45b4-bb5a-152dfd1b133f"}, ' \
|
||||
'{"deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:27:06 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Deployed", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_node_list)
|
||||
nodes = dockercloud.Node.list()
|
||||
for i in range(0, len(nodes)):
|
||||
result = json.loads(json.dumps(nodes[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
def test_node_save(self):
|
||||
self.assertRaises(AttributeError, dockercloud.Node().save)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_node_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/8f5b893b-826e-40b7-bb8b-2d96301425f2/"], "deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:30:06 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Deployed", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_node_fetch)
|
||||
node = dockercloud.Node.fetch('43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456')
|
||||
result = json.loads(json.dumps(node.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_node_delete(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/8f5b893b-826e-40b7-bb8b-2d96301425f2/", "/api/v1/action/83c66611-ea5d-45d7-a97d-914029a90524/"], "deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:38:12 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Terminating", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_node_delete)
|
||||
node = dockercloud.Node.fetch('43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456')
|
||||
self.assertTrue(node.delete())
|
||||
result = json.loads(json.dumps(node.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_node_deploy(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/8f5b893b-826e-40b7-bb8b-2d96301425f2/", "/api/v1/action/83c66611-ea5d-45d7-a97d-914029a90524/"], "deployed_datetime": "Mon, 29 Sep 2014 22:59:47 +0000", "destroyed_datetime": null, "docker_execdriver": "native-0.2", "docker_graphdriver": "aufs", "docker_version": "1.2.0", "external_fqdn": "43b5ebaf-tifayuki.node.docker.io", "last_seen": "Tue, 30 Sep 2014 15:38:12 +0000", "node_cluster": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "public_ip": "178.62.20.100", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/", "state": "Starting", "uuid": "43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_node_deploy)
|
||||
node = dockercloud.Node.fetch('43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456')
|
||||
self.assertTrue(node.deploy())
|
||||
result = json.loads(json.dumps(node.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
73
tests/test_nodecluster.py
Normal file
73
tests/test_nodecluster.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class NodeClusterTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodecluster_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"current_num_nodes": 1, "deployed_datetime": "Mon, 29 Sep 2014 22:29:03 +0000", "destroyed_datetime": null, "name": "test", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "region": "/api/v1/region/digitalocean/sfo1/", "resource_uri": "/api/v1/nodecluster/a02c3763-e639-46fc-a6db-587f4dbb5444/", "state": "Deployed", "target_num_nodes": 1, "uuid": "a02c3763-e639-46fc-a6db-587f4dbb5444"}, '
|
||||
'{"current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "test2", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "state": "Deploying", "target_num_nodes": 1, "uuid": "b616a720-6684-42c6-83bb-4d298b11b3f3"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_nodeclster_list)
|
||||
clusters = dockercloud.NodeCluster.list()
|
||||
for i in range(0, len(clusters)):
|
||||
result = json.loads(json.dumps(clusters[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodecluster_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/bf02b00a-e2fc-4098-8b69-1424b659ef4a/", "/api/v1/action/f8dce6d4-5c41-46a9-9754-baa8f3cdf031/"], "current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "test2", "node_type": "/api/v1/nodetype/digitalocean/512mb/", "nodes": ["/api/v1/node/43b5ebaf-5b9c-4ed3-a1e5-3d91cea70456/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/b616a720-6684-42c6-83bb-4d298b11b3f3/", "state": "Init", "target_num_nodes": 1, "uuid": "b616a720-6684-42c6-83bb-4d298b11b3f3"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_nodecluster_fetch)
|
||||
cluster = dockercloud.NodeCluster.fetch('b616a720-6684-42c6-83bb-4d298b11b3f3')
|
||||
result = json.loads(json.dumps(cluster.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodecluster_save(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/f47e26a6-c60c-416f-a0a9-ddf14e3aae83/"], "current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "my_cluster", "node_type": "/api/v1/nodetype/digitalocean/1gb/", "nodes": ["/api/v1/node/2cfe7823-f551-4c7b-a82c-f6ab31d7ca25/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/e7915a74-618b-4908-9189-dce965465702/", "state": "Init", "target_num_nodes": 1, "uuid": "e7915a74-618b-4908-9189-dce965465702"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_nodecluster_save)
|
||||
cluster = dockercloud.NodeCluster.create(name="my_cluster", region="/api/v1/region/digitalocean/lon1/",
|
||||
node_type="/api/v1/nodetype/digitalocean/1gb/")
|
||||
self.assertTrue(cluster.save())
|
||||
result = json.loads(json.dumps(cluster.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodecluster_deploy(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/f47e26a6-c60c-416f-a0a9-ddf14e3aae83/", "/api/v1/action/d110016e-e65d-4ce7-9f11-50c6302494a6/"], "current_num_nodes": 1, "deployed_datetime": null, "destroyed_datetime": null, "name": "my_cluster", "node_type": "/api/v1/nodetype/digitalocean/1gb/", "nodes": ["/api/v1/node/2cfe7823-f551-4c7b-a82c-f6ab31d7ca25/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/e7915a74-618b-4908-9189-dce965465702/", "state": "Deploying", "target_num_nodes": 1, "uuid": "e7915a74-618b-4908-9189-dce965465702"}'
|
||||
)
|
||||
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/",
|
||||
node_type="/api/v1/nodetype/digitalocean/1gb/")
|
||||
cluster.save()
|
||||
self.assertTrue(cluster.deploy())
|
||||
result = json.loads(json.dumps(cluster.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodecluster_delete(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/f47e26a6-c60c-416f-a0a9-ddf14e3aae83/", "/api/v1/action/d110016e-e65d-4ce7-9f11-50c6302494a6/", "/api/v1/action/e33b4bb1-192b-46a6-a1ba-eadfc494c2dd/"], "current_num_nodes": 1, "deployed_datetime": "Mon, 29 Sep 2014 23:45:45 +0000", "destroyed_datetime": null, "name": "my_cluster", "node_type": "/api/v1/nodetype/digitalocean/1gb/", "nodes": ["/api/v1/node/2cfe7823-f551-4c7b-a82c-f6ab31d7ca25/"], "region": "/api/v1/region/digitalocean/lon1/", "resource_uri": "/api/v1/nodecluster/e7915a74-618b-4908-9189-dce965465702/", "state": "Terminating", "target_num_nodes": 0, "uuid": "e7915a74-618b-4908-9189-dce965465702"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_nodecluster_delete)
|
||||
cluster = dockercloud.NodeCluster.fetch('e7915a74-618b-4908-9189-dce965465702')
|
||||
self.assertTrue(cluster.delete())
|
||||
result = json.loads(json.dumps(cluster.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
33
tests/test_nodeprovider.py
Normal file
33
tests/test_nodeprovider.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class ProviderTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_provider_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"available": true, "label": "Digital Ocean", "name": "digitalocean", "regions": ["/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/ams3/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/sgp1/"], "resource_uri": "/api/v1/provider/digitalocean/"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_provider_list)
|
||||
providers = dockercloud.Provider.list()
|
||||
for i in range(0, len(providers)):
|
||||
result = json.loads(json.dumps(providers[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_provider_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"available": true, "label": "Digital Ocean", "name": "digitalocean", "regions": ["/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/ams3/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/sgp1/"], "resource_uri": "/api/v1/provider/digitalocean/"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_provider_fetch)
|
||||
provider = dockercloud.Provider.fetch("digitalocean")
|
||||
result = json.loads(json.dumps(provider.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
41
tests/test_noderegion.py
Normal file
41
tests/test_noderegion.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class RegionTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_region_list(self, mock_send):
|
||||
attrributes = json.loads(
|
||||
'[{"availability_zones": [], "available": true, "label": "Amsterdam 1", "name": "ams1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/"], "resource_uri": "/api/v1/region/digitalocean/ams1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "San Francisco 1", "name": "sfo1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/sfo1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "New York 2", "name": "nyc2", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/nyc2/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "Amsterdam 2", "name": "ams2", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/ams2/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "Singapore 1", "name": "sgp1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/sgp1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "London 1", "name": "lon1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/lon1/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "New York 3", "name": "nyc3", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/nyc3/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "Amsterdam 3", "name": "ams3", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/", "/api/v1/nodetype/digitalocean/32gb/", "/api/v1/nodetype/digitalocean/48gb/", "/api/v1/nodetype/digitalocean/64gb/"], "resource_uri": "/api/v1/region/digitalocean/ams3/"}]'
|
||||
)
|
||||
|
||||
mock_send.return_value = fake_resp(fake_region_list)
|
||||
regions = dockercloud.Region.list()
|
||||
for i in range(0, len(regions)):
|
||||
result = json.loads(json.dumps(regions[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attrributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_region_fet(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"availability_zones": [], "available": true, "label": "Amsterdam 1", "name": "ams1", "node_types": ["/api/v1/nodetype/digitalocean/512mb/", "/api/v1/nodetype/digitalocean/1gb/", "/api/v1/nodetype/digitalocean/2gb/", "/api/v1/nodetype/digitalocean/4gb/", "/api/v1/nodetype/digitalocean/8gb/", "/api/v1/nodetype/digitalocean/16gb/"], "provider": "/api/v1/provider/digitalocean/", "resource_uri": "/api/v1/region/digitalocean/ams1/"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_region_fetch)
|
||||
region = dockercloud.Region.fetch('digitalocean/asm1')
|
||||
result = json.loads(json.dumps(region.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
41
tests/test_nodetype.py
Normal file
41
tests/test_nodetype.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class NodeTypeTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodetype_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"availability_zones": [], "available": true, "label": "512MB", "name": "512mb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/512mb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "1GB", "name": "1gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/1gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "2GB", "name": "2gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/2gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "4GB", "name": "4gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/4gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "8GB", "name": "8gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/8gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "16GB", "name": "16gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/16gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "32GB", "name": "32gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/32gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "48GB", "name": "48gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/48gb/"}, ' \
|
||||
'{"availability_zones": [], "available": true, "label": "64GB", "name": "64gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/64gb/"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_nodetype_list)
|
||||
nodetypes = dockercloud.NodeType.list()
|
||||
for i in range(0, len(nodetypes)):
|
||||
result = json.loads(json.dumps(nodetypes[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_nodetype_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"availability_zones": [], "available": true, "label": "8GB", "name": "8gb", "provider": "/api/v1/provider/digitalocean/", "regions": ["/api/v1/region/digitalocean/nyc1/", "/api/v1/region/digitalocean/ams1/", "/api/v1/region/digitalocean/sfo1/", "/api/v1/region/digitalocean/nyc2/", "/api/v1/region/digitalocean/ams2/", "/api/v1/region/digitalocean/sgp1/", "/api/v1/region/digitalocean/lon1/", "/api/v1/region/digitalocean/nyc3/", "/api/v1/region/digitalocean/ams3/"], "resource_uri": "/api/v1/nodetype/digitalocean/8gb/"}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_nodetype_fetch)
|
||||
nodetype = dockercloud.NodeType.fetch('digitalocean/8gb')
|
||||
result = json.loads(json.dumps(nodetype.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
52
tests/test_repository.py
Normal file
52
tests/test_repository.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class ImageTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_image_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"base_image": false, "categories": [], "cluster_aware": true, "description": "", "docker_registry": "/api/v1/registry/docker.com/", "image_url": "", "imagetag_set": ["/api/v1/image/docker.com/tifayuki/mongodb/tag/latest/"], "is_private_image": true, "name": "docker.com/tifayuki/mongodb", "public_url": "", "resource_uri": "/api/v1/image/docker.com/tifayuki/mongodb/", "starred": false}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_image_list)
|
||||
images = dockercloud.Repository.list()
|
||||
for i in range(0, len(images)):
|
||||
result = json.loads(json.dumps(images[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_image_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"base_image": false, "categories": [], "cluster_aware": true, "description": "", "docker_registry": {"created": true, "host": "registry.hub.docker.com", "id": 5, "image_url": "/_static/assets/images/dockerregistries/docker.png", "is_ssl": true, "is_tutum_registry": false, "modified": true, "name": "Docker.io", "resource_uri": "/api/v1/registry/registry.hub.docker.com/", "uuid": "d533039e-c44c-4cdc-951b-e0e03b8410c6"}, "image_url": "", "imagetag_set": [{"full_name": "tifayuki/cadvisor:latest", "image": {"author": "fake <fake@docker.com>", "docker_id": "9e2907ef52bf811b4da100f50ba8f0908ccc610c7054bd69087f0a9f4703efdd", "entrypoint": "", "image_creation": "Fri, 15 Aug 2014 15:19:04 +0000", "imageenvvar_set": [{"key": "CADVISOR_TAG", "value": "0.2.2"}, {"key": "DB_NAME", "value": "cadvisor"}, {"key": "DB_PASS", "value": "root"}, {"key": "DB_USER", "value": "root"}, {"key": "HOME", "value": "/"}, {"key": "PATH", "value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}], "imageport_set": [], "run_command": "/run.sh"}, "image_info": "/api/v1/image/tifayuki/cadvisor/", "name": "latest", "resource_uri": "/api/v1/image/tifayuki/cadvisor/tag/latest/"}], "is_private_image": true, "name": "tifayuki/cadvisor", "public_url": "https://registry.hub.docker.com/u/tifayuki/cadvisor/", "resource_uri": "/api/v1/image/tifayuki/cadvisor/", "starred": false}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_image_fetch)
|
||||
image = dockercloud.Repository.fetch('tifayuki/cadvisor')
|
||||
result = json.loads(json.dumps(image.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_image_save(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"base_image": false, "categories": [], "cluster_aware": true, "description": "description", "docker_registry": {"created": true, "host": "registry.hub.docker.com", "id": 5, "image_url": "/_static/assets/images/dockerregistries/docker.png", "is_ssl": true, "is_tutum_registry": false, "modified": true, "name": "Docker.io", "resource_uri": "/api/v1/registry/registry.hub.docker.com/", "uuid": "d533039e-c44c-4cdc-951b-e0e03b8410c6"}, "image_url": "", "imagetag_set": [{"full_name": "tifayuki/cadvisor:latest", "image": {"author": "fake <fake@docker.com>", "docker_id": "9e2907ef52bf811b4da100f50ba8f0908ccc610c7054bd69087f0a9f4703efdd", "entrypoint": "", "image_creation": "Fri, 15 Aug 2014 15:19:04 +0000", "imageenvvar_set": [{"key": "CADVISOR_TAG", "value": "0.2.2"}, {"key": "DB_NAME", "value": "cadvisor"}, {"key": "DB_PASS", "value": "root"}, {"key": "DB_USER", "value": "root"}, {"key": "HOME", "value": "/"}, {"key": "PATH", "value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}], "imageport_set": [], "run_command": "/run.sh"}, "image_info": "/api/v1/image/tifayuki/cadvisor/", "name": "latest", "resource_uri": "/api/v1/image/tifayuki/cadvisor/tag/latest/"}], "is_private_image": true, "name": "tifayuki/cadvisor", "public_url": "https://registry.hub.docker.com/u/tifayuki/cadvisor/", "resource_uri": "/api/v1/image/tifayuki/cadvisor/", "starred": false}'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_image_save)
|
||||
image = dockercloud.Repository.fetch('tifayuki/cadvisor')
|
||||
image.description = 'descripiton'
|
||||
self.assertTrue(image.save())
|
||||
result = json.loads(json.dumps(image.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_image_delete(self, mock_send):
|
||||
mock_send.side_effect = [fake_resp(fake_image_fetch), fake_resp(fake_image_delete)]
|
||||
image = dockercloud.Repository.fetch('tifayuki/cadvisor')
|
||||
self.assertTrue(image.delete())
|
||||
93
tests/test_service.py
Normal file
93
tests/test_service.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from .fake_api import *
|
||||
|
||||
|
||||
class ServiceTestCase(unittest.TestCase):
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_list(self, mock_send):
|
||||
attributes = json.loads(
|
||||
'[{"autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "cpu_shares": null, "current_num_containers": 3, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "state": "Running", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 3, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8"}]'
|
||||
)
|
||||
mock_send.return_value = fake_resp(fake_service_list)
|
||||
services = dockercloud.Service.list()
|
||||
for i in range(0, len(services)):
|
||||
result = json.loads(json.dumps(services[i].get_all_attributes()))
|
||||
target = json.loads(json.dumps(attributes[i]))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_fetch(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/e3ee01df-9f2f-4720-a114-ea1a236d47d2/", "/api/v1/action/c58213ab-8d5c-4a6d-b4c3-bd7157242dc2/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "containers": ["/api/v1/container/cff4dfa7-28a5-4599-a3f9-c7dc39353c11/", "/api/v1/container/4d966087-5169-4a0b-a2f0-78bbb878d872/", "/api/v1/container/0c84cd78-c239-40ad-939e-dbbc372ae345/"], "cpu_shares": null, "current_num_containers": 3, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "link_variables": {"HELLO_WORLD_1_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_1_ENV_HOME": "/", "HELLO_WORLD_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_1_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_1_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_1_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_2_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_2_ENV_HOME": "/", "HELLO_WORLD_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_2_PORT": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP_ADDR": "hello-world-2.a2f5a2e9-tifayuki.node.docker.io", "HELLO_WORLD_2_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_2_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_3_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_3_ENV_HOME": "/", "HELLO_WORLD_3_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_3_PORT": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP_ADDR": "hello-world-3.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_3_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_3_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_ENV_HOME": "/", "HELLO_WORLD_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "roles": [], "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "state": "Running", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 3, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8"}')
|
||||
mock_send.return_value = fake_resp(fake_service_fetch)
|
||||
service = dockercloud.Service.fetch('a2ac25c9-7cfe-4a1b-9d97-66de23642ee8')
|
||||
result = json.loads(json.dumps(service.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_save(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/e3ee01df-9f2f-4720-a114-ea1a236d47d2/", "/api/v1/action/c58213ab-8d5c-4a6d-b4c3-bd7157242dc2/", "/api/v1/action/b3adfa79-dbd2-41a4-8c71-5e242ecce9bb/", "/api/v1/action/f82e25e7-d550-454e-a897-8599f2f530e5/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "containers": ["/api/v1/container/cff4dfa7-28a5-4599-a3f9-c7dc39353c11/", "/api/v1/container/4d966087-5169-4a0b-a2f0-78bbb878d872/", "/api/v1/container/0c84cd78-c239-40ad-939e-dbbc372ae345/"], "cpu_shares": null, "current_num_containers": 3, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "link_variables": {"HELLO_WORLD_1_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_1_ENV_HOME": "/", "HELLO_WORLD_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_1_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_1_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_1_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_2_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_2_ENV_HOME": "/", "HELLO_WORLD_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_2_PORT": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP_ADDR": "hello-world-2.a2f5a2e9-tifayuki.node.docker.io", "HELLO_WORLD_2_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_2_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_3_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_3_ENV_HOME": "/", "HELLO_WORLD_3_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_3_PORT": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP_ADDR": "hello-world-3.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_3_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_3_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_ENV_HOME": "/", "HELLO_WORLD_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "roles": [], "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "state": "Scaling", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 5, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8", "web_public_dns": ""}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_service_fetch), fake_resp(fake_service_save)]
|
||||
service = dockercloud.Service.fetch('a2ac25c9-7cfe-4a1b-9d97-66de23642ee8')
|
||||
service.target_num_containers = 5
|
||||
self.assertTrue(service.save())
|
||||
result = json.loads(json.dumps(service.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_delete(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/e3ee01df-9f2f-4720-a114-ea1a236d47d2/", "/api/v1/action/c58213ab-8d5c-4a6d-b4c3-bd7157242dc2/", "/api/v1/action/b3adfa79-dbd2-41a4-8c71-5e242ecce9bb/", "/api/v1/action/f82e25e7-d550-454e-a897-8599f2f530e5/", "/api/v1/action/381c53a0-bf18-4a01-a1b0-be87051c35e8/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 80, "outer_port": null, "port_name": "http", "protocol": "tcp", "uri_protocol": "http"}], "containers": ["/api/v1/container/cff4dfa7-28a5-4599-a3f9-c7dc39353c11/", "/api/v1/container/4d966087-5169-4a0b-a2f0-78bbb878d872/", "/api/v1/container/0c84cd78-c239-40ad-939e-dbbc372ae345/", "/api/v1/container/6e74df59-83ee-4351-8ba9-3d26e0d64c34/", "/api/v1/container/7bbff9f0-af41-408f-9dd0-213cd67e4aa2/"], "cpu_shares": null, "current_num_containers": 5, "deployed_datetime": "Tue, 30 Sep 2014 16:07:36 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/hello-world:latest", "image_tag": "/api/v1/image/tutum/hello-world/tag/latest/", "link_variables": {"HELLO_WORLD_1_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_1_ENV_HOME": "/", "HELLO_WORLD_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_1_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_1_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_1_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_1_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_2_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_2_ENV_HOME": "/", "HELLO_WORLD_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_2_PORT": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP": "tcp://hello-world-2.a2f5a2e9-tifayuki.node.docker.io:49155", "HELLO_WORLD_2_PORT_80_TCP_ADDR": "hello-world-2.a2f5a2e9-tifayuki.node.docker.io", "HELLO_WORLD_2_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_2_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_3_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_3_ENV_HOME": "/", "HELLO_WORLD_3_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_3_PORT": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP": "tcp://hello-world-3.5067d4f4-tifayuki.node.docker.io:49155", "HELLO_WORLD_3_PORT_80_TCP_ADDR": "hello-world-3.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_3_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_3_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_4_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_4_ENV_HOME": "/", "HELLO_WORLD_4_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_4_PORT": "tcp://hello-world-4.5067d4f4-tifayuki.node.docker.io:49156", "HELLO_WORLD_4_PORT_80_TCP": "tcp://hello-world-4.5067d4f4-tifayuki.node.docker.io:49156", "HELLO_WORLD_4_PORT_80_TCP_ADDR": "hello-world-4.5067d4f4-tifayuki.node.docker.io", "HELLO_WORLD_4_PORT_80_TCP_PORT": "49156", "HELLO_WORLD_4_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_5_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_5_ENV_HOME": "/", "HELLO_WORLD_5_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_5_PORT": "tcp://hello-world-5.fa9df19a-tifayuki.node.docker.io:49157", "HELLO_WORLD_5_PORT_80_TCP": "tcp://hello-world-5.fa9df19a-tifayuki.node.docker.io:49157", "HELLO_WORLD_5_PORT_80_TCP_ADDR": "hello-world-5.fa9df19a-tifayuki.node.docker.io", "HELLO_WORLD_5_PORT_80_TCP_PORT": "49157", "HELLO_WORLD_5_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_ENV_DEBIAN_FRONTEND": "noninteractive", "HELLO_WORLD_ENV_HOME": "/", "HELLO_WORLD_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HELLO_WORLD_PORT": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP": "tcp://hello-world-1.fa9df19a-tifayuki.node.docker.io:49155", "HELLO_WORLD_PORT_80_TCP_ADDR": "hello-world-1.fa9df19a-t* Connection #0 to host dashboard.docker.com left intactifayuki.node.docker.io", "HELLO_WORLD_PORT_80_TCP_PORT": "49155", "HELLO_WORLD_PORT_80_TCP_PROTO": "tcp", "HELLO_WORLD_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "hello-world", "resource_uri": "/api/v1/service/a2ac25c9-7cfe-4a1b-9d97-66de23642ee8/", "roles": [], "run_command": "/run.sh", "running_num_containers": 3, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 22:57:36 +0000", "state": "Terminating", "stopped_datetime": null, "stopped_num_containers": 0, "target_num_containers": 0, "unique_name": "hello-world", "uuid": "a2ac25c9-7cfe-4a1b-9d97-66de23642ee8"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_service_fetch), fake_resp(fake_service_delete)]
|
||||
service = dockercloud.Service.fetch('a2ac25c9-7cfe-4a1b-9d97-66de23642ee8')
|
||||
self.assertTrue(service.delete())
|
||||
result = json.loads(json.dumps(service.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_start(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/a8aaf64b-3186-41e7-9256-6b3d69786036/", "/api/v1/action/2481790d-a860-4bb4-95d2-5676ae2d6748/", "/api/v1/action/799a0d06-efae-4bf1-b063-7141f722cbb1/", "/api/v1/action/ef6b9f59-1edb-44c7-bcc6-1b80f737e4b0/", "/api/v1/action/99b7ac29-d16d-448f-bac5-54dbd5dd3b7b/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 3306, "outer_port": null, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "containers": ["/api/v1/container/2a1c4057-7753-4393-98c6-35699c198e08/", "/api/v1/container/54ead360-698f-4354-96f7-538f686cdd69/"], "cpu_shares": null, "current_num_containers": 2, "deployed_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "link_variables": {"MYSQL_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "mysql", "resource_uri": "/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/", "roles": [], "run_command": "/run.sh", "running_num_containers": 0, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "state": "Starting", "stopped_datetime": "Tue, 30 Sep 2014 23:09:09 +0000", "stopped_num_containers": 2, "target_num_containers": 2, "unique_name": "mysql", "uuid": "5ecde92d-498b-4bbb-b773-a998e5e421dc"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_service_fetch), fake_resp(fake_service_start)]
|
||||
service = dockercloud.Service.fetch('a2ac25c9-7cfe-4a1b-9d97-66de23642ee8')
|
||||
self.assertTrue(service.start())
|
||||
result = json.loads(json.dumps(service.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_stop(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/a8aaf64b-3186-41e7-9256-6b3d69786036/", "/api/v1/action/2481790d-a860-4bb4-95d2-5676ae2d6748/", "/api/v1/action/799a0d06-efae-4bf1-b063-7141f722cbb1/", "/api/v1/action/ef6b9f59-1edb-44c7-bcc6-1b80f737e4b0/", "/api/v1/action/99b7ac29-d16d-448f-bac5-54dbd5dd3b7b/", "/api/v1/action/98816bfc-4fa7-4697-bea1-d926de69b48f/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 3306, "outer_port": null, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "containers": ["/api/v1/container/2a1c4057-7753-4393-98c6-35699c198e08/", "/api/v1/container/54ead360-698f-4354-96f7-538f686cdd69/"], "cpu_shares": null, "current_num_containers": 2, "deployed_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "link_variables": {"MYSQL_1_ENV_DEBIAN_FRONTEND": "noninteractive", "MYSQL_1_ENV_MYSQL_PASS": "**Random**", "MYSQL_1_ENV_MYSQL_USER": "admin", "MYSQL_1_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "MYSQL_1_ENV_REPLICATION_MASTER": "**False**", "MYSQL_1_ENV_REPLICATION_PASS": "replica", "MYSQL_1_ENV_REPLICATION_SLAVE": "**False**", "MYSQL_1_ENV_REPLICATION_USER": "replica", "MYSQL_1_PORT": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_1_PORT_3306_TCP": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_1_PORT_3306_TCP_ADDR": "mysql-1.fa9df19a-tifayuki.node.docker.io", "MYSQL_1_PORT_3306_TCP_PORT": "49156", "MYSQL_1_PORT_3306_TCP_PROTO": "tcp", "MYSQL_2_ENV_DEBIAN_FRONTEND": "noninteractive", "MYSQL_2_ENV_MYSQL_PASS": "**Random**", "MYSQL_2_ENV_MYSQL_USER": "admin", "MYSQL_2_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "MYSQL_2_ENV_REPLICATION_MASTER": "**False**", "MYSQL_2_ENV_REPLICATION_PASS": "replica", "MYSQL_2_ENV_REPLICATION_SLAVE": "**False**", "MYSQL_2_ENV_REPLICATION_USER": "replica", "MYSQL_2_PORT": "tcp://mysql-2.a2f5a2e9-tifayuki.node.docker.io:49156", "MYSQL_2_PORT_3306_TCP": "tcp://mysql-2.a2f5a2e9-tifayuki.node.docker.io:49156", "MYSQL_2_PORT_3306_TCP_ADDR": "mysql-2.a2f5a2e9-tifayuki.node.docker.io", "MYSQL_2_PORT_3306_TCP_PORT": "49156", "MYSQL_2_PORT_3306_TCP_PROTO": "tcp", "MYSQL_ENV_DEBIAN_FRONTEND": "noninteractive", "MYSQL_ENV_MYSQL_PASS": "**Random**", "MYSQL_ENV_MYSQL_USER": "admin", "MYSQL_ENV_PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "MYSQL_ENV_REPLICATION_MASTER": "**False**", "MYSQL_ENV_REPLICATION_PASS": "replica", "MYSQL_ENV_REPLICATION_SLAVE": "**False**", "MYSQL_ENV_REPLICATION_USER": "replica", "MYSQL_PORT": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_PORT_3306_TCP": "tcp://mysql-1.fa9df19a-tifayuki.node.docker.io:49156", "MYSQL_PORT_3306_TCP_ADDR": "mysql-1.fa9df19a-tifayuki.node.docker.io", "MYSQL_PORT_3306_TCP_PORT": "49156", "MYSQL_PORT_3306_TCP_PROTO": "tcp", "MYSQL_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "mysql", "resource_uri": "/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/", "roles": [], "run_command": "/run.sh", "running_num_containers": 1, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 23:50:59 +0000", "state": "Stopping", "stopped_datetime": "Tue, 30 Sep 2014 23:09:09 +0000", "stopped_num_containers": 0, "target_num_containers": 2, "unique_name": "mysql", "uuid": "5ecde92d-498b-4bbb-b773-a998e5e421dc"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_service_fetch), fake_resp(fake_service_stop)]
|
||||
service = dockercloud.Service.fetch('a2ac25c9-7cfe-4a1b-9d97-66de23642ee8')
|
||||
self.assertTrue(service.stop())
|
||||
result = json.loads(json.dumps(service.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
|
||||
@mock.patch.object(dockercloud.api.http.Session, 'send')
|
||||
def test_service_redeploy(self, mock_send):
|
||||
attribute = json.loads(
|
||||
'{"actions": ["/api/v1/action/a8aaf64b-3186-41e7-9256-6b3d69786036/", "/api/v1/action/2481790d-a860-4bb4-95d2-5676ae2d6748/", "/api/v1/action/799a0d06-efae-4bf1-b063-7141f722cbb1/", "/api/v1/action/ef6b9f59-1edb-44c7-bcc6-1b80f737e4b0/", "/api/v1/action/99b7ac29-d16d-448f-bac5-54dbd5dd3b7b/", "/api/v1/action/98816bfc-4fa7-4697-bea1-d926de69b48f/", "/api/v1/action/285e250f-7429-4f0a-a252-5594a05c8020/"], "autodestroy": "OFF", "autoreplace": "OFF", "autorestart": "OFF", "container_envvars": [], "container_ports": [{"endpoint_uri": null, "inner_port": 3306, "outer_port": null, "port_name": "mysql", "protocol": "tcp", "uri_protocol": "mysql"}], "containers": ["/api/v1/container/2a1c4057-7753-4393-98c6-35699c198e08/", "/api/v1/container/54ead360-698f-4354-96f7-538f686cdd69/"], "cpu_shares": null, "current_num_containers": 2, "deployed_datetime": "Tue, 30 Sep 2014 22:44:44 +0000", "destroyed_datetime": null, "entrypoint": "", "image_name": "tutum/mysql:latest", "image_tag": "/api/v1/image/tutum/mysql/tag/latest/", "link_variables": {"MYSQL_TUTUM_API_URL": "https://dashboard.docker.com/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/"}, "linked_from_service": [], "linked_to_service": [], "memory": null, "memory_swap": null, "name": "mysql", "resource_uri": "/api/v1/service/5ecde92d-498b-4bbb-b773-a998e5e421dc/", "roles": [], "run_command": "/run.sh", "running_num_containers": 0, "sequential_deployment": false, "started_datetime": "Tue, 30 Sep 2014 23:50:59 +0000", "state": "Redeploying", "stopped_datetime": "Tue, 30 Sep 2014 23:51:52 +0000", "stopped_num_containers": 0, "target_num_containers": 2, "unique_name": "mysql", "uuid": "5ecde92d-498b-4bbb-b773-a998e5e421dc"}'
|
||||
)
|
||||
mock_send.side_effect = [fake_resp(fake_service_fetch), fake_resp(fake_service_redeploy)]
|
||||
service = dockercloud.Service.fetch('a2ac25c9-7cfe-4a1b-9d97-66de23642ee8')
|
||||
self.assertTrue(service.redeploy())
|
||||
result = json.loads(json.dumps(service.get_all_attributes()))
|
||||
target = json.loads(json.dumps(attribute))
|
||||
self.assertDictEqual(target, result)
|
||||
221
tests/test_utils.py
Normal file
221
tests/test_utils.py
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
import unittest
|
||||
|
||||
import unittest.mock as mock
|
||||
|
||||
import dockercloud
|
||||
from dockercloud.api.exceptions import ObjectNotFound, ApiError, NonUniqueIdentifier
|
||||
|
||||
|
||||
class FetchRemoteObjectTestCase(unittest.TestCase):
|
||||
@mock.patch('dockercloud.Container.list')
|
||||
@mock.patch('dockercloud.Container.fetch')
|
||||
def test_fetch_remote_container(self, mock_fetch, mock_list):
|
||||
# test container exist queried with uuid4
|
||||
mock_fetch.return_value = 'returned'
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_container('7A4CFE51-03BB-42D6-825E-3B533888D8CD', True),
|
||||
'returned')
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_container('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
'returned')
|
||||
|
||||
# test container doesn't exist queried with uuid4
|
||||
mock_fetch.side_effect = ObjectNotFound
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_container,
|
||||
'7A4CFE51-03BB-42D6-825E-3B533888D8CD',
|
||||
True)
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_container('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
ObjectNotFound)
|
||||
|
||||
# test unique container found queried with short uuid
|
||||
container = dockercloud.Container.create()
|
||||
container.uuid = 'uuid'
|
||||
mock_list.side_effect = [[container], []]
|
||||
mock_fetch.side_effect = [container]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_container('shortuuid', True), container)
|
||||
mock_list.side_effect = [[container], []]
|
||||
mock_fetch.side_effect = [container]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_container('shortuuid', False), container)
|
||||
|
||||
# test unique container found queried with name
|
||||
mock_list.side_effect = [[], [container]]
|
||||
mock_fetch.side_effect = [container]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_container('name', True), container)
|
||||
mock_list.side_effect = [[], [container]]
|
||||
mock_fetch.side_effect = [container]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_container('name', False), container)
|
||||
|
||||
# test no container found
|
||||
mock_list.side_effect = [[], []]
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_container, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [[], []]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_container('uuid_or_name', False), ObjectNotFound)
|
||||
|
||||
# test multi-container found
|
||||
mock_list.side_effect = [['container1', 'container2'], []]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_container, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [['container1', 'container2'], []]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_container('uuid_or_name', False), NonUniqueIdentifier)
|
||||
mock_list.side_effect = [[], ['container1', 'container2']]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_container, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [[], ['container1', 'container2']]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_container('uuid_or_name', False), NonUniqueIdentifier)
|
||||
|
||||
# test api error
|
||||
mock_list.side_effect = [ApiError, ApiError]
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_container, 'uuid_or_name', True)
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_container, 'uuid_or_name', False)
|
||||
|
||||
@mock.patch('dockercloud.Service.list')
|
||||
@mock.patch('dockercloud.Service.fetch')
|
||||
def test_fetch_remote_service(self, mock_fetch, mock_list):
|
||||
# test cluster exist queried with uuid4
|
||||
mock_fetch.return_value = 'returned'
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_service('7A4CFE51-03BB-42D6-825E-3B533888D8CD', True),
|
||||
'returned')
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_service('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
'returned')
|
||||
|
||||
# test cluster doesn't exist queried with uuid4
|
||||
mock_fetch.side_effect = ObjectNotFound
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_service,
|
||||
'7A4CFE51-03BB-42D6-825E-3B533888D8CD',
|
||||
True)
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_service('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
ObjectNotFound)
|
||||
|
||||
# test unique cluster found queried with short uuid
|
||||
service = dockercloud.Service.create()
|
||||
service.uuid = 'uuid'
|
||||
mock_list.side_effect = [[service], []]
|
||||
mock_fetch.side_effect = [service]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_service('shortuuid', True), service)
|
||||
mock_list.side_effect = [[service], []]
|
||||
mock_fetch.side_effect = [service]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_service('shortuuid', False), service)
|
||||
|
||||
# test unique cluster found queried with name
|
||||
mock_list.side_effect = [[], [service]]
|
||||
mock_fetch.side_effect = [service]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_service('name', True), service)
|
||||
mock_list.side_effect = [[], [service]]
|
||||
mock_fetch.side_effect = [service]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_service('name', False), service)
|
||||
|
||||
# test no cluster found
|
||||
mock_list.side_effect = [[], []]
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_service, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [[], []]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_service('uuid_or_name', False), ObjectNotFound)
|
||||
|
||||
# test multi-cluster found
|
||||
mock_list.side_effect = [['cluster1', 'cluster2'], []]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_service, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [['cluster1', 'cluster2'], []]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_service('uuid_or_name', False), NonUniqueIdentifier)
|
||||
mock_list.side_effect = [[], ['cluster1', 'cluster2']]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_service, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [[], ['cluster1', 'cluster2']]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_service('uuid_or_name', False), NonUniqueIdentifier)
|
||||
|
||||
# test api error
|
||||
mock_list.side_effect = [ApiError, ApiError]
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_service, 'uuid_or_name', True)
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_service, 'uuid_or_name', False)
|
||||
|
||||
@mock.patch('dockercloud.Node.list')
|
||||
@mock.patch('dockercloud.Node.fetch')
|
||||
def test_fetch_remote_node(self, mock_fetch, mock_list):
|
||||
# test node exist queried with uuid4
|
||||
mock_fetch.return_value = 'returned'
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_node('7A4CFE51-03BB-42D6-825E-3B533888D8CD', True), 'returned')
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_node('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False), 'returned')
|
||||
|
||||
# test node doesn't exist queried with uuid4
|
||||
mock_fetch.side_effect = ObjectNotFound
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_node, '7A4CFE51-03BB-42D6-825E-3B533888D8CD',
|
||||
True)
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_node('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
ObjectNotFound)
|
||||
|
||||
# test unique node found queried with short uuid
|
||||
node = dockercloud.Node.create()
|
||||
node.uuid = 'uuid'
|
||||
mock_list.side_effect = [[node]]
|
||||
mock_fetch.side_effect = [node]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_node('uuid', True), node)
|
||||
mock_list.side_effect = [[node]]
|
||||
mock_fetch.side_effect = [node]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_node('uuid', False), node)
|
||||
|
||||
# test no node found
|
||||
mock_list.side_effect = [[]]
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_node, 'uuid', True)
|
||||
mock_list.side_effect = [[]]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_node('uuid', False), ObjectNotFound)
|
||||
|
||||
# test multi-node found
|
||||
mock_list.side_effect = [['node1', 'node2']]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_node, 'uuid', True)
|
||||
mock_list.side_effect = [['node1', 'node2']]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_node('uuid', False), NonUniqueIdentifier)
|
||||
|
||||
# test api error
|
||||
mock_list.side_effect = [ApiError, ApiError]
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_node, 'uuid', True)
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_node, 'uuid', False)
|
||||
|
||||
@mock.patch('dockercloud.NodeCluster.list')
|
||||
@mock.patch('dockercloud.NodeCluster.fetch')
|
||||
def test_fetch_remote_nodecluster(self, mock_fetch, mock_list):
|
||||
# test nodecluster exist queried with uuid4
|
||||
mock_fetch.return_value = 'returned'
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_nodecluster('7A4CFE51-03BB-42D6-825E-3B533888D8CD', True),
|
||||
'returned')
|
||||
self.assertEqual(dockercloud.Utils.fetch_remote_nodecluster('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
'returned')
|
||||
|
||||
# test nodecluster doesn't exist queried with uuid4
|
||||
mock_fetch.side_effect = ObjectNotFound
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_nodecluster,
|
||||
'7A4CFE51-03BB-42D6-825E-3B533888D8CD',
|
||||
True)
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_nodecluster('7A4CFE51-03BB-42D6-825E-3B533888D8CD', False),
|
||||
ObjectNotFound)
|
||||
|
||||
# test unique nodecluster found queried with short uuid
|
||||
nodecluster = dockercloud.NodeCluster.create()
|
||||
nodecluster.uuid = 'uuid'
|
||||
mock_list.side_effect = [[nodecluster], []]
|
||||
mock_fetch.side_effect = [nodecluster]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_nodecluster('shortuuid', True), nodecluster)
|
||||
mock_list.side_effect = [[nodecluster], []]
|
||||
mock_fetch.side_effect = [nodecluster]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_nodecluster('shortuuid', False), nodecluster)
|
||||
|
||||
# test unique nodecluster found queried with name
|
||||
mock_list.side_effect = [[], [nodecluster]]
|
||||
mock_fetch.side_effect = [nodecluster]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_nodecluster('name', True), nodecluster)
|
||||
mock_list.side_effect = [[], [nodecluster]]
|
||||
mock_fetch.side_effect = [nodecluster]
|
||||
self.assertEquals(dockercloud.Utils.fetch_remote_nodecluster('name', False), nodecluster)
|
||||
|
||||
# test no nodecluster found
|
||||
mock_list.side_effect = [[], []]
|
||||
self.assertRaises(ObjectNotFound, dockercloud.Utils.fetch_remote_nodecluster, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [[], []]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_nodecluster('uuid_or_name', False), ObjectNotFound)
|
||||
|
||||
# test multi-nodecluster found
|
||||
mock_list.side_effect = [['nodecluster1', 'nodecluster2'], []]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_nodecluster, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [['nodecluster1', 'nodecluster2'], []]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_nodecluster('uuid_or_name', False), NonUniqueIdentifier)
|
||||
mock_list.side_effect = [[], ['nodecluster1', 'nodecluster2']]
|
||||
self.assertRaises(NonUniqueIdentifier, dockercloud.Utils.fetch_remote_nodecluster, 'uuid_or_name', True)
|
||||
mock_list.side_effect = [[], ['nodecluster1', 'nodecluster2']]
|
||||
self.assertIsInstance(dockercloud.Utils.fetch_remote_nodecluster('uuid_or_name', False), NonUniqueIdentifier)
|
||||
|
||||
# test api error
|
||||
mock_list.side_effect = [ApiError, ApiError]
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_nodecluster, 'uuid_or_name', True)
|
||||
self.assertRaises(ApiError, dockercloud.Utils.fetch_remote_nodecluster, 'uuid_or_name', False)
|
||||
Loading…
Add table
Add a link
Reference in a new issue