diff --git a/samples/kill_all_jobs.py b/samples/kill_all_jobs.py new file mode 100644 index 000000000..9c5f52a50 --- /dev/null +++ b/samples/kill_all_jobs.py @@ -0,0 +1,47 @@ +#### +# This script demonstrates how to kill all of the running jobs +# +# To run the script, you must have installed Python 2.7.X or 3.3 and later. +#### + +import argparse +import getpass +import logging + +import tableauserverclient as TSC + + +def main(): + parser = argparse.ArgumentParser(description='Cancel all of the running background jobs') + parser.add_argument('--server', '-s', required=True, help='server address') + parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site') + parser.add_argument('--username', '-u', required=True, help='username to sign into server') + parser.add_argument('--password', '-p', default=None, help='password for the user') + + parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', + help='desired logging level (set to error by default)') + + args = parser.parse_args() + + if args.password is None: + password = getpass.getpass("Password: ") + else: + password = args.password + + # Set logging level based on user input, or error by default + logging_level = getattr(logging, args.logging_level.upper()) + logging.basicConfig(level=logging_level) + + # SIGN IN + tableau_auth = TSC.TableauAuth(args.username, password, args.site) + server = TSC.Server(args.server, use_server_version=True) + with server.auth.sign_in(tableau_auth): + req = TSC.RequestOptions() + + req.filter.add(TSC.Filter("progress", TSC.RequestOptions.Operator.LessThanOrEqual, 0)) + for job in TSC.Pager(server.jobs, request_opts=req): + print(server.jobs.cancel(job.id), job.id, job.status, job.type) + + +if __name__ == '__main__': + main() diff --git a/tableauserverclient/server/endpoint/endpoint.py b/tableauserverclient/server/endpoint/endpoint.py index 1efb32f89..994d2133d 100644 --- a/tableauserverclient/server/endpoint/endpoint.py +++ b/tableauserverclient/server/endpoint/endpoint.py @@ -76,7 +76,7 @@ def delete_request(self, url): # We don't return anything for a delete self._make_request(self.parent_srv.session.delete, url, auth_token=self.parent_srv.auth_token) - def put_request(self, url, xml_request, content_type='text/xml'): + def put_request(self, url, xml_request=None, content_type='text/xml'): return self._make_request(self.parent_srv.session.put, url, content=xml_request, auth_token=self.parent_srv.auth_token, diff --git a/tableauserverclient/server/endpoint/jobs_endpoint.py b/tableauserverclient/server/endpoint/jobs_endpoint.py index 007f550ae..f3432d605 100644 --- a/tableauserverclient/server/endpoint/jobs_endpoint.py +++ b/tableauserverclient/server/endpoint/jobs_endpoint.py @@ -1,5 +1,6 @@ from .endpoint import Endpoint, api from .. import JobItem, BackgroundJobItem, PaginationItem +from ..request_options import RequestOptionsBase import logging logger = logging.getLogger('tableau.endpoint.jobs') @@ -17,12 +18,20 @@ def get(self, job_id=None, req_options=None): import warnings warnings.warn("Jobs.get(job_id) is deprecated, update code to use Jobs.get_by_id(job_id)") return self.get_by_id(job_id) + if isinstance(job_id, RequestOptionsBase): + req_options = job_id + self.parent_srv.assert_at_least_version('3.1') server_response = self.get_request(self.baseurl, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) jobs = BackgroundJobItem.from_response(server_response.content, self.parent_srv.namespace) return jobs, pagination_item + @api(version='3.1') + def cancel(self, job_id): + url = '{0}/{1}'.format(self.baseurl, job_id) + return self.put_request(url) + @api(version='2.6') def get_by_id(self, job_id): logger.info('Query for information about job ' + job_id) diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index be00e8975..0e3601a25 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -13,20 +13,27 @@ class Operator: In = 'in' class Field: + Args = 'args' + CompletedAt = 'completedAt' CreatedAt = 'createdAt' DomainName = 'domainName' DomainNickname = 'domainNickname' HitsTotal = 'hitsTotal' IsLocal = 'isLocal' + JobType = 'jobType' LastLogin = 'lastLogin' MinimumSiteRole = 'minimumSiteRole' Name = 'name' + Notes = 'notes' OwnerDomain = 'ownerDomain' OwnerEmail = 'ownerEmail' OwnerName = 'ownerName' + Progress = 'progress' ProjectName = 'projectName' SiteRole = 'siteRole' + Subtitle = 'subtitle' Tags = 'tags' + Title = 'title' Type = 'type' UpdatedAt = 'updatedAt' UserCount = 'userCount' diff --git a/test/test_job.py b/test/test_job.py index 674e54c67..5da0f76fa 100644 --- a/test/test_job.py +++ b/test/test_job.py @@ -31,6 +31,7 @@ def test_get(self): created_at = datetime(2018, 5, 22, 13, 0, 29, tzinfo=utc) started_at = datetime(2018, 5, 22, 13, 0, 37, tzinfo=utc) ended_at = datetime(2018, 5, 22, 13, 0, 45, tzinfo=utc) + self.assertEquals(1, pagination_item.total_available) self.assertEquals('2eef4225-aa0c-41c4-8662-a76d89ed7336', job.id) self.assertEquals('Success', job.status) @@ -43,3 +44,8 @@ def test_get(self): def test_get_before_signin(self): self.server._auth_token = None self.assertRaises(TSC.NotSignedInError, self.server.jobs.get) + + def test_cancel(self): + with requests_mock.mock() as m: + m.put(self.baseurl + '/ee8c6e70-43b6-11e6-af4f-f7b0d8e20760', status_code=204) + self.server.jobs.cancel('ee8c6e70-43b6-11e6-af4f-f7b0d8e20760')