diff --git a/freezer/apiclient/backups.py b/freezer/apiclient/backups.py index b5456723..a92c97d4 100644 --- a/freezer/apiclient/backups.py +++ b/freezer/apiclient/backups.py @@ -32,6 +32,8 @@ class BackupsManager(object): return {'X-Auth-Token': self.client.auth_token} def create(self, backup_metadata): + if not backup_metadata.get('client_id', ''): + backup_metadata['client_id'] = self.client.client_id r = requests.post(self.endpoint, data=json.dumps(backup_metadata), headers=self.headers, @@ -48,7 +50,7 @@ class BackupsManager(object): if r.status_code != 204: raise exceptions.ApiClientException(r) - def list(self, limit=10, offset=0, search=None): + def list_all(self, limit=10, offset=0, search=None): """ Retrieves a list of backup infos @@ -70,6 +72,13 @@ class BackupsManager(object): return r.json()['backups'] + def list(self, limit=10, offset=0, search={}, client_id=None): + client_id = client_id or self.client.client_id + new_search = search.copy() + new_search['match'] = search.get('match', []) + new_search['match'].append({'client_id': client_id}) + return self.list_all(limit, offset, new_search) + def get(self, backup_id): endpoint = self.endpoint + backup_id r = requests.get(endpoint, headers=self.headers, verify=self.verify) diff --git a/freezer/scheduler/arguments.py b/freezer/scheduler/arguments.py index 65f19b32..6e494bc0 100644 --- a/freezer/scheduler/arguments.py +++ b/freezer/scheduler/arguments.py @@ -105,7 +105,16 @@ def get_common_opts(): default=False, dest='disable_exec', help='Allow Freezer Scheduler to deny jobs that execute ' - 'commands for security reasons') + 'commands for security reasons'), + cfg.BoolOpt('all', + default=False, + dest='all', + help='Used when querying the API, to retrieve any ' + 'document regardless of the client-id'), + cfg.BoolOpt('long', + default=False, + dest='long', + help='List additional fields in output') ] return _COMMON diff --git a/freezer/scheduler/scheduler_job.py b/freezer/scheduler/scheduler_job.py index 98a81646..3a943e8c 100644 --- a/freezer/scheduler/scheduler_job.py +++ b/freezer/scheduler/scheduler_job.py @@ -275,6 +275,7 @@ class Job(object): try: metadata = json.loads(metadata_string) if metadata: + metadata['job_id'] = self.id self.scheduler.upload_metadata(metadata) logging.info("[*] Job {0}, freezer action metadata uploaded" .format(self.id)) diff --git a/freezer/scheduler/shell.py b/freezer/scheduler/shell.py index 014399ca..b96f0583 100644 --- a/freezer/scheduler/shell.py +++ b/freezer/scheduler/shell.py @@ -21,6 +21,8 @@ import os import six import utils +from freezer.utils.utils import DateTime + from prettytable import PrettyTable try: @@ -191,21 +193,22 @@ def do_job_upload(client, args): def _job_list(client, args): + list_func = client.jobs.list_all if args.all else client.jobs.list search = {} if args.active_only: search = {"match_not": [{"status": "completed"}]} - client_docs = client.jobs.list(search=search) + client_docs = list_func(search=search) offset = 0 while client_docs: offset += len(client_docs) for doc in client_docs: yield doc - client_docs = client.jobs.list(offset=offset, search=search) + client_docs = list_func(offset=offset, search=search) raise StopIteration def do_job_list(client, args): - table = PrettyTable(["job_id", "description", "# actions", + table = PrettyTable(["job_id", "client-id", "description", "# actions", "status", "event", "result", "session_id"]) for doc in _job_list(client, args): job_scheduling = doc.get('job_schedule', {}) @@ -213,6 +216,7 @@ def do_job_list(client, args): job_event = job_scheduling.get('event', '') job_result = job_scheduling.get('result', '') table.add_row([doc['job_id'], + doc.get('client_id'), doc.get('description', ''), len(doc.get('job_actions', [])), job_status, @@ -235,3 +239,41 @@ def do_client_list(client, args): client_doc.get('description', '')]) l = client.registration.list(offset=offset) print(table) + + +def do_backup_list(client, args): + list_func = client.backups.list_all if args.all else client.backups.list + if args.long: + fields = ["backup uuid", "job-id", "client-id", "container", + "hostname", "backup name", "timestamp", "level", "path"] + else: + fields = ["backup uuid", "container", "backup name", "timestamp", + "level", "path"] + table = PrettyTable(fields) + l = list_func() + offset = 0 + while l: + offset += len(l) + for doc in l: + metadata_doc = doc['backup_metadata'] + timestamp = int(metadata_doc.get('time_stamp', 0)) + if args.long: + row = [doc['backup_uuid'], + metadata_doc.get('job_id', ''), + metadata_doc.get('client_id', ''), + metadata_doc.get('container', ''), + metadata_doc.get('hostname', ''), + metadata_doc.get('backup_name', ''), + str(DateTime(timestamp)), + metadata_doc.get('curr_backup_level', ''), + metadata_doc.get('fs_real_path', '')] + else: + row = [doc['backup_uuid'], + metadata_doc.get('container', ''), + metadata_doc.get('backup_name', ''), + str(DateTime(timestamp)), + metadata_doc.get('curr_backup_level', ''), + metadata_doc.get('fs_real_path', '')] + table.add_row(row) + l = list_func(offset=offset) + print(table) diff --git a/tests/unit/apiclient/test_apiclient_backup.py b/tests/unit/apiclient/test_apiclient_backup.py index f10571c7..74e4cbed 100644 --- a/tests/unit/apiclient/test_apiclient_backup.py +++ b/tests/unit/apiclient/test_apiclient_backup.py @@ -15,6 +15,7 @@ limitations under the License. """ +import json import unittest from mock import Mock, patch @@ -22,10 +23,30 @@ from freezer.apiclient import exceptions from freezer.apiclient import backups +class CallArgs(object): + + def __init__(self, mock_obj=Mock()): + self.args = mock_obj.call_args[0] + self.kwargs = mock_obj.call_args[1] + + def _check_arg(self, arg, value, load_json): + if load_json: + arg = json.loads(arg) + if (arg != value): + raise Exception("Argument doesn't match: {0} != {1}".format(arg, value)) + return + + def check_arg(self, pos, value, load_json=False): + if isinstance(pos, int): + return self._check_arg(self.args[pos], value, load_json) + return self._check_arg(self.kwargs[pos], value, load_json) + + class TestBackupManager(unittest.TestCase): def setUp(self): self.mock_client = Mock() + self.mock_client.client_id = "jumpingjack" self.mock_client.endpoint = 'http://testendpoint:9999' self.mock_client.auth_token = 'testtoken' self.b = backups.BackupsManager(self.mock_client) @@ -42,6 +63,25 @@ class TestBackupManager(unittest.TestCase): mock_response.json.return_value = {'backup_id': 'qwerqwer'} mock_requests.post.return_value = mock_response retval = self.b.create(backup_metadata={'backup': 'metadata'}) + ca = CallArgs(mock_requests.post) + ca.check_arg(0, 'http://testendpoint:9999/v1/backups/') + ca.check_arg('data', {"backup": "metadata", "client_id": "jumpingjack"}, load_json=True) + ca.check_arg('headers', {'X-Auth-Token': 'testtoken'}) + ca.check_arg('verify', True) + self.assertEqual('qwerqwer', retval) + + @patch('freezer.apiclient.backups.requests') + def test_create_ok_with_client_id(self, mock_requests): + mock_response = Mock() + mock_response.status_code = 201 + mock_response.json.return_value = {'backup_id': 'qwerqwer'} + mock_requests.post.return_value = mock_response + retval = self.b.create(backup_metadata={'backup': 'metadata', 'client_id': 'wahwah'}) + ca = CallArgs(mock_requests.post) + ca.check_arg(0, 'http://testendpoint:9999/v1/backups/') + ca.check_arg('data', {"backup": "metadata", "client_id": "wahwah"}, load_json=True) + ca.check_arg('headers', {'X-Auth-Token': 'testtoken'}) + ca.check_arg('verify', True) self.assertEqual('qwerqwer', retval) @patch('freezer.apiclient.backups.requests') @@ -112,12 +152,11 @@ class TestBackupManager(unittest.TestCase): retval = self.b.list(limit=5, offset=5, search={"time_before": 1428529956}) - mock_requests.get.assert_called_with( - 'http://testendpoint:9999/v1/backups/', - params={'limit': 5, 'offset': 5}, - data='{"time_before": 1428529956}', - headers={'X-Auth-Token': 'testtoken'}, - verify=True) + ca = CallArgs(mock_requests.get) + ca.check_arg(0, 'http://testendpoint:9999/v1/backups/') + ca.check_arg('data', {"time_before": 1428529956, "match": [{"client_id": "jumpingjack"}]}, load_json=True) + ca.check_arg('headers', {'X-Auth-Token': 'testtoken'}) + ca.check_arg('verify', True) self.assertEqual(backup_list, retval) @patch('freezer.apiclient.backups.requests')