def cancel_job(self, job_id):
        logging.info("Cancelling Job=<{}>".format(job_id))

        params = {"mode": "cancel"}
        route = "{}/jobs/{}".format(self.path, job_id)

        try:
            handle_response(requests.patch(route, params=params))
            return self._await_job_termination(job_id)
        except HTTPError as e:
            raise JobIdNotFoundException(
                "Could not find job=<{}>. Reason=<{}>".format(
                    job_id, e.response.text))
    def run_job(self, jar_id, job_params=None):
        logger.info("Starting job for deployed JAR=<{}>".format(jar_id))
        route = "{}/jars/{}/run".format(self.path, jar_id)
        try:
            response = handle_response(requests.post(route, json=job_params))

            new_job_id = response["jobid"]
            logger.info("New job with job_id=<{}> deployed".format(new_job_id))

            return response
        except HTTPError as e:
            raise JobRunFailedException(
                "Unable to start running job from jar=<{}>. Reason=<{}>".
                format(jar_id, e.response.text))
    def submit_jar(self, jar_path):
        with open(jar_path, "rb") as jar:
            jar_name = os.path.basename(jar_path)
            file_dict = {'files': (jar_name, jar)}

            route = "{}/jars/upload".format(self.path)
            try:
                response = handle_response(
                    requests.post(route, files=file_dict))

                jar_id = os.path.basename(response['filename'])
                logger.info(
                    "Sucessfully uploaded JAR=<{}> to cluster".format(jar_id))
                return jar_id
            except HTTPError:
                logger.warning(
                    "Unable to upload JAR=<{}> to cluster".format(jar_path))
                raise NotValidJARException(
                    "File at {} is not a valid JAR".format(jar_path))
    def trigger_savepoint(self, job_id, target_dir, cancel_job=False):
        logger.info(
            "Cancelling Job=<{}> and adding savepoint to savepoint_path=<{}>".
            format(job_id, target_dir))
        route = "{}/jobs/{}/savepoints/".format(self.path, job_id)

        body = {"target-directory": target_dir, "cancel-job": cancel_job}

        try:
            response = handle_response(requests.post(route, json=body))

            if response is not None:
                request_id = response["request-id"]
                logger.info(
                    "Triggered savepoint for job=<{}>. Savepoint_request_id=<{}>"
                    .format(job_id, request_id))

                return self._await_savepoint_completion(job_id, request_id)
        except HTTPError as e:
            raise JobIdNotFoundException(
                "Could not find JobId=<{}>. Reason=<{}>".format(
                    job_id, e.response.text))
    def delete_jar(self, jar_id):
        route = "{}/jars/{}".format(self.path, jar_id)
        response = handle_response(requests.delete(route))

        return response
    def list_jars(self):
        route = "{}/jars".format(self.path)
        response = handle_response(requests.get(route))

        return response
    def job_info(self, job_id):
        route = "{}/jobs/{}".format(self.path, job_id)

        return handle_response(requests.get(route))
    def savepoint_trigger_info(self, job_id, request_id):
        route = "{}/jobs/{}/savepoints/{}".format(self.path, job_id,
                                                  request_id)

        return handle_response(requests.get(route))