diff --git a/actions.py b/actions.py new file mode 100644 index 0000000..80814c6 --- /dev/null +++ b/actions.py @@ -0,0 +1,101 @@ +""" +Copyright 2015 Hewlett-Packard + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This product includes cryptographic software written by Eric Young +(eay@cryptsoft.com). This product includes software written by Tim +Hudson (tjh@cryptsoft.com). +======================================================================== +""" + +import json +import requests +from freezer.apiclient import exceptions + + +class ActionManager(object): + + def __init__(self, client): + self.client = client + self.endpoint = self.client.endpoint + '/v1/actions/' + + @property + def headers(self): + return {'X-Auth-Token': self.client.auth_token} + + def create(self, doc): + r = requests.post(self.endpoint, + data=json.dumps(doc), + headers=self.headers) + if r.status_code != 201: + raise exceptions.MetadataCreationFailure( + "[*] Error {0}: {1}".format(r.status_code, r.text)) + action_id = r.json()['action_id'] + return action_id + + def delete(self, action_id): + endpoint = self.endpoint + action_id + r = requests.delete(endpoint, headers=self.headers) + if r.status_code != 204: + raise exceptions.MetadataDeleteFailure( + "[*] Error {0}".format(r.status_code)) + + def list(self, limit=10, offset=0, search=None): + """ + Retrieves a list of action info structures + + :param limit: number of result to return (optional, default 10) + :param offset: order of first document (optional, default 0) + :param search: structured query (optional) + can contain: + * "match": list of {field, value} + Example: + { "match": [ + {"description": "some search text here"}, + {"backup_name": "mydata"}, + ... + ], + } + """ + data = json.dumps(search) if search else None + query = {'limit': int(limit), 'offset': int(offset)} + r = requests.get(self.endpoint, headers=self.headers, + params=query, data=data) + if r.status_code != 200: + raise exceptions.MetadataGetFailure( + "[*] Error {0}: {1}".format(r.status_code, r.text)) + return r.json()['actions'] + + def get(self, action_id): + endpoint = self.endpoint + action_id + r = requests.get(endpoint, headers=self.headers) + if r.status_code == 200: + return r.json() + if r.status_code == 404: + return None + raise exceptions.MetadataGetFailure( + "[*] Error {0}".format(r.status_code)) + + def update(self, action_id, update_doc): + endpoint = self.endpoint + action_id + r = requests.patch(endpoint, + headers=self.headers, + data=json.dumps(update_doc)) + if r.status_code != 200: + raise exceptions.MetadataUpdateFailure( + "[*] Error {0}: {1}".format(r.status_code, r.text)) + return r.json()['version'] + + def set_status(self, action_id, new_status): + return self.update(action_id, {'status': new_status}) diff --git a/client.py b/client.py index 4ec3afe..34b4081 100644 --- a/client.py +++ b/client.py @@ -31,6 +31,7 @@ if os.path.exists(os.path.join(possible_topdir, 'freezer', '__init__.py')): from freezer.apiclient.backups import BackupsManager from freezer.apiclient.registration import RegistrationManager +from freezer.apiclient.actions import ActionManager import exceptions @@ -55,6 +56,7 @@ class Client(object): self._auth = None self.backups = BackupsManager(self) self.registration = RegistrationManager(self) + self.actions = ActionManager(self) def _update_api_endpoint(self): services = self.auth.services.list() diff --git a/exceptions.py b/exceptions.py index c91381f..ffdc03f 100644 --- a/exceptions.py +++ b/exceptions.py @@ -19,18 +19,44 @@ Hudson (tjh@cryptsoft.com). ======================================================================== """ - -class MetadataCreationFailure(Exception): - message = "Metadata creation failed: %reason" +import json -class MetadataGetFailure(Exception): - message = "Metadata read failed: %reason" +class ApiClientException(Exception): + def __init__(self, r): + try: + body = json.loads(r.text) + message = "[*] Error {0}: {1}".format( + r.status_code, + body['description']) + except: + message = r + super(ApiClientException, self).__init__(message) + + def __str__(self): + return self.message -class MetadataDeleteFailure(Exception): - message = "Metadata deletion failed: %reason" +class MetadataCreationFailure(ApiClientException): + def __init__(self, r=''): + super(self.__class__, self).__init__(r) -class AuthFailure(Exception): - message = "Authentication Error: %reason" +class MetadataGetFailure(ApiClientException): + def __init__(self, r=''): + super(self.__class__, self).__init__(r) + + +class MetadataDeleteFailure(ApiClientException): + def __init__(self, r=''): + super(self.__class__, self).__init__(r) + + +class AuthFailure(ApiClientException): + def __init__(self, r=''): + super(self.__class__, self).__init__(r) + + +class MetadataUpdateFailure(ApiClientException): + def __init__(self, r=''): + super(self.__class__, self).__init__(r)