def test_rest_client_post(self, mock_call):
        """Test post"""

        auth = mock.create_autospec(Credentials)

        with self.assertRaises(RestCallException):
            rest_client.post(auth, "http://test", {})


        mock_call.return_value.text = '{"key":"value"}'
        val = rest_client.post(auth, "http://test", {})
        mock_call.assert_called_with(auth, 'POST', "http://test",
                                     headers={},
                                     data=None)
        self.assertEqual(val, {"key":"value"})

        val = rest_client.post(auth, "http://test", {}, message={"msg":"test"})
        mock_call.assert_called_with(auth, 'POST', "http://test",
                                     headers={},
                                     data='{"msg": "test"}')

        del mock_call.return_value.text
        with self.assertRaises(RestCallException):
            rest_client.post(auth, "http://test", {})

        mock_call.side_effect = RestCallException(None, "Boom!", None)
        with self.assertRaises(RestCallException):
            rest_client.post(auth, "http://test", {})
    def test_rest_client_post(self, mock_call):
        """Test post"""

        auth = mock.create_autospec(Credentials)

        with self.assertRaises(RestCallException):
            rest_client.post(auth, "http://test", {})

        mock_call.return_value.text = '{"key":"value"}'
        val = rest_client.post(auth, "http://test", {})
        mock_call.assert_called_with(auth,
                                     'POST',
                                     "http://test",
                                     headers={},
                                     data=None)
        self.assertEqual(val, {"key": "value"})

        val = rest_client.post(auth,
                               "http://test", {},
                               message={"msg": "test"})
        mock_call.assert_called_with(auth,
                                     'POST',
                                     "http://test",
                                     headers={},
                                     data='{"msg": "test"}')

        del mock_call.return_value.text
        with self.assertRaises(RestCallException):
            rest_client.post(auth, "http://test", {})

        mock_call.side_effect = RestCallException(None, "Boom!", None)
        with self.assertRaises(RestCallException):
            rest_client.post(auth, "http://test", {})
Esempio n. 3
0
    def cancel_task(self, job_id, task):
        """Cancel a running task of a job in progress.

        :Args:
            - job_id (str): The ID of the job whose task will be cancelled.
            - task (int, str): The ID of the task to be cancelled.

        :Returns:
            - A :class:`.Response` object with the POST response, however this
              is not required if the call is successful. The call will only
              be successful if the task can be and is cancelled.
            - If the task is not running (and therefore cannot be cancelled),
              the call will fail and the :class:`.RestCallException` will be
              returned in the :class:`.Response` object.
            - Any other communication failures will also return a
              :class:`.RestCallException`.
        """
        self._log.debug("cancel_task, job_id={0}, task={1}".format(job_id, task))
        url = self.url("jobs/{jobid}/tasks/{taskid}/actions/cancel")
        url = url.format(url, jobid=job_id, taskid=task)

        try:
            resp = rest_client.post(self._auth, url, self.headers)

        except RestCallException as exp:
            return Response(False, exp)

        else:
            return Response(True, resp)
Esempio n. 4
0
    def reprocess(self, job_id):
        """
        Reprocesses any failed tasks in the job.
        This call will also re-activate a job if it has a 'Failed' status.

        :Args:
            - job_id (str): ID of the job to be reprocessed.

        :Returns:
            - A :class:`.Response` object containing a dictionary with the job
              ID of the reprocessed job and a URL to retrieve the job
              information (see :meth:`.BatchAppsApi.get_job()`).
            - If the call failed the response will hold the
              :class:`.RestCallException`.
        """
        self._log.debug("reprocess, job_id={0}".format(job_id))
        url = self.url("jobs/{jobid}/actions/reprocess").format(jobid=job_id)

        try:
            post_resp = rest_client.post(self._auth, url, self.headers)

        except RestCallException as exp:
            return Response(False, exp)

        else:
            return Response(True, post_resp)
Esempio n. 5
0
    def cancel(self, job_id):
        """Cancels a running job.

        :Args:
            - job_id (str): The ID of the job to be cancelled.

        :Returns:
            - A :class:`.Response` object with the POST response, however this
              is not required if the call is successful. The call will only
              be successful if the job can be and is cancelled.
            - If the job is not running (and therefore cannot be cancelled),
              the call will fail and the :class:`.RestCallException` will be
              returned in the :class:`.Response` object.
            - Any other communication failures will also return a
              :class:`.RestCallException`.
        """
        self._log.debug("cancel, job_id={0}".format(job_id))
        url = self.url("jobs/{jobid}/actions/cancel").format(jobid=job_id)

        try:
            post_resp = rest_client.post(self._auth, url, self.headers)

        except RestCallException as exp:
            return Response(False, exp)

        else:
            return Response(True, post_resp)
Esempio n. 6
0
    def send_job(self, job_message):
        """Submits a job.

        :Args:
            - job_message (dict): A job specification formatted as a
              dictionary.

        :Returns:
            - A :class:`.Response` object containing a dictionary of the newly
              submitted job's ID and URL if successful. Otherwise the
              Response will contain the :exc:`.RestCallException`.

        :Raises:
            - :class:`.RestCallException` if new job dictionary is
              malformed / missing necessary keys.
        """
        self._log.debug("send_job, job_message={0}".format(job_message))
        url = self.url("jobs")

        try:
            post_resp = rest_client.post(self._auth, url, self.headers, message=job_message)

        except RestCallException as exp:
            return Response(False, exp)

        else:
            if utils.valid_keys(post_resp, ["jobId", "link"]):
                return Response(True, post_resp)

            return Response(False, RestCallException(KeyError, "incorrectly formatted job response", post_resp))
Esempio n. 7
0
    def resize_pool(self, pool_id, target_size):
        """
        Resize an existing pool.

        :Args:
            - pool_id (str): The ID of the pool to be resized.
            - target_size (int): The new size of the pool.

        :Returns:
            - :class:`.Response` with the POST response, however this is not
              required if the call was successful.
            - If the call failed a :class:`.Response` object with a
              :class:`.RestCallException`.
        """
        self._log.debug("resize_pool, pool_id={0}, " "target_size={1}".format(pool_id, target_size))
        url = self.url("pools/{poolid}/actions/resize")
        url = url.format(url, poolid=pool_id)

        message = {"targetDedicated": str(target_size)}

        try:
            resp = rest_client.post(self._auth, url, self.headers, message)

        except RestCallException as exp:
            return Response(False, exp)

        return Response(True, resp)
Esempio n. 8
0
    def add_pool(self, target_size=0, max_tasks=1, communication=False, certs=[]):
        """
        Add a new pool.

        :Kwargs:
            - target_size (int): The target size of the pool. The default is 0.
            - max_tasks (int): Max tasks that can run on a single TVM.
              The default is 1.
            - communication (bool): Indicates whether tasks running on TVMs
              in the pool need to ba able to communicate directly with each
              other. The default is ``False``.
            - certs (list): A list of certificates that need to be installed
              on the TVMs of the pool. The maximum number of certs that can
              be installed on a pool is 10.

        :Returns:
            - A :class:`.Response` object a dict with the new pool id and
              a link to the newly created pool.
              ``{'id': '', 'link': ''}``
            - If the call failed or if the response is incomplete/malformed
              a :class:`.Response` object with a :class:`.RestCallException`.
        """
        self._log.debug("add_pool")
        url = self.url("pools")

        if len(certs) > 10:
            certs = certs[0:10]

        try:
            message = {
                "targetDedicated": str(int(target_size)),
                "maxTasksPerTVM": str(int(max_tasks)),
                "communication": bool(communication),
                "certificateReferences": list(certs),
            }

        except ValueError as exp:
            return Response(False, RestCallException(ValueError, str(exp), exp))

        try:
            resp = rest_client.post(self._auth, url, self.headers, message)

        except RestCallException as exp:
            return Response(False, exp)

        if utils.valid_keys(resp, ["poolId", "link"]):
            return Response(True, resp)

        return Response(False, RestCallException(KeyError, "incorrectly formatted pool response", resp))
Esempio n. 9
0
    def query_missing_files(self, files):
        """
        Checks whether user files are present in the cloud.
        As opposed to :meth:`.query_files()`, this call returns the files that
        are **not** present in the cloud.

        :Args:
            - files (dict, list): Either a file specification dictionary, or a
              list of file spec dictionaries.

        :Returns:
            - A :class:`.Response` object containing a list of the files that
              don't yet exist in the cloud. The files are represented as a
              dict with only a 'name' key.
            - If the call failed, a :class:`.Response` object containing
              a :class:`.RestCallException` is returned.
        """
        # TODO: Check whether 'FileHash' is supported.
        self._log.debug("query_missing_files, files={0}".format(files))
        url = self.url("files/query/missing")

        if type(files) == dict:
            files = [files]

        elif not (type(files) == list and len(files) >= 1 and type(files[0]) == dict):

            error = (
                "File query can be done with single userfile "
                "spec dict, or list of userfile spec dicts. "
                "Not {t}".format(t=type(files))
            )
            return Response(False, RestCallException(TypeError, error, None))

        message = {"Specifications": files}
        try:
            resp = rest_client.post(self._auth, url, self.headers, message)

        except RestCallException as exp:
            return Response(False, exp)

        if "files" not in resp or not isinstance(resp["files"], list):
            return Response(False, RestCallException(KeyError, "files key not in response message", resp))

        return Response(True, resp["files"])
Esempio n. 10
0
    def query_files(self, files):
        """
        Queries for user files matching specified criteria.
        This is used to detect whether user's files already exist in the cloud,
        and if they're up-to-date. Any number of files can be queried in a
        single call.

        :Args:
            - files (list, dict, str): The files to query.
              If this is in the form of a single filename, or list of
              filenames, the call will query for user files that match
              that filename. If this is in the form of a dict, or list of
              dicts, the call will query for a more specific match.
              Query dict should have the keys ``{'fileName', 'timestamp'}``
              and optionally ``{'originalPath'}``.

        :Returns:
            - If the query was by filename, a :class:`.Response` containing a
              list of all the files (as dicts) with that name will be
              returned.
            - If the query was by specification, a :class:`.Response`
              containing a list of all the matching files (as dicts) will
              be returned.
            - If the call failed, a :class:`.Response` object containing a
              :class:`.RestCallException` will be returned.
        """
        self._log.debug("query_files, files={0}".format(files))
        url = self.url("files/query/{queryby}")
        operations = {str: "byname", dict: "byspecification"}

        optype = type(files)
        if optype == list and len(files) >= 1:
            optype = type(files[0])
        elif optype == list and len(files) < 1:
            return Response(False, RestCallException(ValueError, "File list empty", ValueError("File list empty")))
        else:
            files = [files]

        if optype not in operations:
            error = (
                "File query can be done with single "
                "file name, list of names, or userfile "
                "spec dict. Not {t}".format(t=type(files))
            )

            return Response(False, RestCallException(TypeError, error, TypeError(error)))

        req_type = operations[optype]
        self._log.info("Querying files using {0}".format(req_type))
        url = url.format(queryby=req_type)

        if req_type == "byspecification":
            message = {"Specifications": files}
        else:
            message = {"Names": files}

        self._log.debug("File query url={0}, message={1}".format(url, message))
        try:
            resp = rest_client.post(self._auth, url, self.headers, message)

        except RestCallException as exp:
            return Response(False, exp)

        if "files" not in resp or not isinstance(resp["files"], list):
            return Response(False, RestCallException(KeyError, "files key not in response message", resp))

        return Response(True, resp["files"])