summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2015-10-01 18:19:02 -0400
committerSimo Sorce <simo@redhat.com>2015-10-19 12:18:10 -0400
commita94ac9cec35e12765bba61409cf4db88f564af4c (patch)
treef49eb76daf77270755c7c1335a963500e73e5b22
parent58d434e0fea2b2f9544e7ef1fba07bf50e07b7c0 (diff)
downloadcustodia-a94ac9cec35e12765bba61409cf4db88f564af4c.tar.gz
custodia-a94ac9cec35e12765bba61409cf4db88f564af4c.tar.xz
custodia-a94ac9cec35e12765bba61409cf4db88f564af4c.zip
Add client classes to query custodia servers
This makes it simpler to use a custodia server, whether exposed over HTTP, HTTPS or a unix socket with the http+unix schema. Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-by: Christian Heimes <cheimes@redhat.com>
-rw-r--r--custodia/client.py133
1 files changed, 133 insertions, 0 deletions
diff --git a/custodia/client.py b/custodia/client.py
new file mode 100644
index 0000000..d4b9c1a
--- /dev/null
+++ b/custodia/client.py
@@ -0,0 +1,133 @@
+# Copyright (C) 2015 Custodia Project Contributors - see LICENSE file
+
+import socket
+
+import requests
+
+from requests.adapters import HTTPAdapter
+from requests.compat import unquote, urlparse
+
+from requests.packages.urllib3.connection import HTTPConnection
+from requests.packages.urllib3.connectionpool import HTTPConnectionPool
+
+
+class HTTPUnixConnection(HTTPConnection):
+
+ def __init__(self, host, timeout=60, **kwargs):
+ super(HTTPConnection, self).__init__('localhost')
+ self.unix_socket = host
+ self.timeout = timeout
+
+ def connect(self):
+ s = socket.socket(family=socket.AF_UNIX)
+ s.settimeout(self.timeout)
+ s.connect(self.unix_socket)
+ self.sock = s
+
+
+class HTTPUnixConnectionPool(HTTPConnectionPool):
+
+ scheme = 'http+unix'
+ ConnectionCls = HTTPUnixConnection
+
+
+class HTTPUnixAdapter(HTTPAdapter):
+
+ def get_connection(self, url, proxies=None):
+ # proxies, silently ignored
+ path = unquote(urlparse(url).netloc)
+ return HTTPUnixConnectionPool(path)
+
+
+DEFAULT_HEADERS = {'Content-Type': 'application/json'}
+
+
+class CustodiaHTTPClient(object):
+
+ def __init__(self, url):
+ self.session = requests.Session()
+ self.session.mount('http+unix://', HTTPUnixAdapter())
+ self.headers = dict(DEFAULT_HEADERS)
+ self.url = url
+
+ def set_simple_auth_keys(self, name, key,
+ name_header='CUSTODIA_AUTH_ID',
+ key_header='CUSTODIA_AUTH_KEY'):
+ self.headers[name_header] = name
+ self.headers[key_header] = key
+
+ def _join_url(self, path):
+ return self.url.rstrip('/') + '/' + path.lstrip('/')
+
+ def _add_headers(self, **kwargs):
+ headers = kwargs.get('headers', None)
+ if headers is None:
+ headers = dict()
+ headers.update(self.headers)
+ return headers
+
+ def _request(self, cmd, path, **kwargs):
+ url = self._join_url(path)
+ kwargs['headers'] = self._add_headers(**kwargs)
+ return cmd(url, **kwargs)
+
+ def delete(self, path, **kwargs):
+ return self._request(self.session.delete, path, **kwargs)
+
+ def get(self, path, **kwargs):
+ return self._request(self.session.get, path, **kwargs)
+
+ def head(self, path, **kwargs):
+ return self._request(self.session.head, path, **kwargs)
+
+ def patch(self, path, **kwargs):
+ return self._request(self.session.patch, path, **kwargs)
+
+ def post(self, path, **kwargs):
+ return self._request(self.session.post, path, **kwargs)
+
+ def put(self, path, **kwargs):
+ return self._request(self.session.put, path, **kwargs)
+
+
+class CustodiaClient(CustodiaHTTPClient):
+
+ def create_container(self, name):
+ r = self.post(name if name.endswith('/') else name + '/')
+ r.raise_for_status()
+ return r
+
+ def delete_container(self, name):
+ r = self.delete(name if name.endswith('/') else name + '/')
+ r.raise_for_status()
+ return r
+
+ def list_container(self, name):
+ r = self.get(name if name.endswith('/') else name + '/')
+ r.raise_for_status()
+ return r
+
+ def get_key(self, name):
+ r = self.get(name)
+ r.raise_for_status()
+ return r
+
+ def set_key(self, name, data_to_json):
+ r = self.put(name, json=data_to_json)
+ r.raise_for_status()
+ return r
+
+ def del_key(self, name):
+ r = self.delete(name)
+ r.raise_for_status()
+ return r
+
+ def get_simple_key(self, name):
+ simple = self.get_key(name).json()
+ ktype = simple.get("type", None)
+ if ktype != "simple":
+ raise TypeError("Invalid key type: %s" % ktype)
+ return simple["value"]
+
+ def set_simple_key(self, name, value):
+ self.set_key(name, {"type": "simple", "value": value})