def free_threads(self,
                     request: AllocateThreadsRequest) -> AllocateResponse:
        url = "{}/free_threads".format(self.__url)
        body = request.to_dict()

        try:
            log.info("freeing threads remotely for workload: %s",
                     request.get_workload_id())
            response = requests.put(url,
                                    json=body,
                                    headers=self.__headers,
                                    timeout=self.__timeout)
        except requests.exceptions.Timeout as e:
            log.error("freeing threads remotely for workload: %s timed out",
                      request.get_workload_id())
            raise e

        if response.status_code == 200:
            log.info(
                "freed threads remotely with response code: %s for workload: %s",
                response.status_code, request.get_workload_id())
            return deserialize_response(response.headers, response.json())

        log.error(
            "failed to free threads remotely for workload: %s with status code: %d",
            request.get_workload_id(), response.status_code)
        raise CpuAllocationException("Failed to free threads: {}".format(
            response.text))
    def assign_threads(self, request: AllocateThreadsRequest) -> AllocateResponse:
        url = "{}/assign_threads".format(self.__url)
        body = request.to_dict()
        log.debug("url: {}, body: {}".format(url, body))
        response = requests.put(url, json=body, headers=self.__headers, timeout=self.__timeout)
        log.debug("assign_threads response code: {}".format(response.status_code))

        if response.status_code == 200:
            return deserialize_response(response.headers, response.json())

        raise CpuAllocationException("Failed to assign threads: {}".format(response.text))