client: Add REST client library

master
Dustin 2016-01-01 17:49:12 -06:00
parent d4dfb3cafd
commit 61eb0f1ee6
1 changed files with 130 additions and 0 deletions

130
src/rouse/client.py Normal file
View File

@ -0,0 +1,130 @@
from __future__ import unicode_literals
from . import host
from six.moves import urllib
import codecs
import json
import os
import six
DEFAULT_BASEURL = os.environ.get('ROUSE_URL', 'http://localhost/rouse')
class RouseError(Exception):
pass
class PUTRequest(urllib.request.Request):
def get_method(self):
return 'PUT'
class DELETERequest(urllib.request.Request):
def get_method(self):
return 'DELETE'
class Rouse(object):
def __init__(self, baseurl=DEFAULT_BASEURL):
self.baseurl = baseurl.rstrip('/')
def request(self, path, query=None, data=None, method=None):
if data is not None:
data = urllib.parse.urlencode([(k, v if v is not None else '')
for k, v in six.iteritems(data)])
data = data.encode('utf-8')
url = urllib.parse.urljoin(self.baseurl, path)
if query:
url += '?' + urllib.parse.urlencode(
[(k, v if v is not None else '')
for k, v in six.iteritems(query)]
)
if method == 'DELETE':
req = DELETERequest(url, data)
elif method == 'PUT':
req = PUTRequest(url, data)
else:
req = urllib.request.Request(url, data)
try:
res = urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
try:
content_length = int(e.info()['Content-Length'])
except (KeyError, ValueError):
content_length = 0
if content_length:
err = json.load(codecs.getreader('utf-8')(e))['error']
raise RouseError(err)
try:
try:
content_length = int(res.info()['Content-Length'])
except (KeyError, ValueError):
content_length = 0
if content_length:
return json.load(codecs.getreader('utf-8')(res))
finally:
res.close()
def delete(self, path, **keywords):
return self.request(path, keywords, method='DELETE')
def get(self, path, **keywords):
return self.request(path, keywords)
def post(self, path, **keywords):
return self.request(path, data=keywords)
def put(self, path, **keywords):
return self.request(path, data=keywords, method='PUT')
class Host(host.Host):
def __init__(self, macaddr=None, ipaddr=None, hostname=None):
self.id = None
self.macaddr = macaddr
self.ipaddr = ipaddr
self.hostname = hostname
self.rouse = None
@classmethod
def find(cls, rouse, **keywords):
for item in rouse.get('/', **keywords):
host = cls.from_dict(item)
host.rouse = rouse
yield host
@classmethod
def from_dict(cls, data):
self = cls()
self.__dict__.update(data)
return self
@classmethod
def get(cls, rouse, id):
host = cls.from_dict(rouse.get('/{}'.format(id)))
host.rouse = rouse
return host
def add(self, rouse):
self.rouse = rouse
self.id = self.rouse.post('/', **self.as_dict())['id']
def as_dict(self):
data = self.__dict__.copy()
del data['id']
del data['rouse']
for key in data:
if key.startswith('_'):
del data[key]
return data
def delete(self):
self.rouse.delete('/{}'.format(self.id))
def update(self):
self.rouse.put('/{}'.format(self.id), **self.as_dict())