def get_job_actions(self, sandbox_id):
        """Gets any pending job action for the given sandbox id.

        Args:
            sandbox_id: string, the sandbox id.

        Returns:
            A list of job actions.

        Note:
            The output list is of the following format:
            [
                {
                    "MessageMetadata": {
                        "PopReceipt": "AgAAAAMAAAAAAAAAPuDINxcZ0gE=",
                        "MessageId": "2e682df3-a6c6-4d23-afc2-40dc01c2a509"
                    },
                    "MessageSource'": "Queue",
                    "LockToken'": "00000000-0000-0000-0000-000000000000",
                    "JobId'": "6cbb98cc-d69a-46f0-a116-3b6094ceba6b"
                }
            ]
        """
        url = self.base_uri + "/automationAccounts/" + self.account_id + "/Sandboxes/" + sandbox_id + \
              "/jobs/getJobActions?api-version=" + self.protocol_version

        try:
            response = self.issue_request(lambda u: self.httpClient.get(u),
                                          url)
        except JrdsAuthorizationException:
            raise JrdsSandboxTerminated()

        if response.status_code == 200:
            try:
                if response.deserialized_data is None or "value" not in response.deserialized_data:
                    locallogger.log_info(
                        "INFO: Could not deserialize get_job_actions response body: %s"
                        % str(response.deserialized_data))
                    return []
            except TypeError:
                locallogger.log_info(
                    "INFO: Could not deserialize get_job_actions response body: %s"
                    % str(response.deserialized_data))
                return []
            job_actions = response.deserialized_data["value"]
            if len(job_actions) != 0:
                message_metadatas = [
                    action["MessageMetadata"] for action in job_actions
                ]
                self.acknowledge_job_action(sandbox_id, message_metadatas)
            return job_actions

        raise Exception("Unable to get job actions. [status=" +
                        str(response.status_code) + "]")
def trace_generic_hybrid_worker_event(event_id,
                                      task_name,
                                      message,
                                      t_id,
                                      keyword,
                                      activity_id=None,
                                      debug=False):
    """Write the trace to STDOUT / log file (on disk) / to MDS (in the cloud).

    Args:
        event_id    : int   , the event id. This event id doesn't have to map to an ETW event id in the cloud.
        task_name   : string, the task name.
        message     : string, the message.
        t_id        : int   , the thread id.
        keyword     : string, the keyword.
        activity_id : string, the activity id.
        debug       : boolean, the debug flag
    """
    # # # # # # # # # # # # # # # # # # # #
    # for tests, disregard tracer
    if os.getenv('test_mode', None) is not None:
        return
    # # # # # # # # # # # # # # # # # # # #

    if jrds_client is None or locallogger.default_logger is None:
        init()

    if debug and not configuration.get_debug_traces():
        return

    if task_name.startswith("log"):
        task_name = "_".join(task_name.split("_")[1:])
    task_name = task_name.title().replace("_", "")

    if isinstance(message, dict):
        message = dict_to_str(message)

    if activity_id is None:
        activity_id = u_activity_id

    # local trace
    # we prioritize cloud traces, do not raise exception if local tracing raises an exception
    locallogger.log_info(message)

    # MDS
    if not debug:
        format_and_issue_generic_hybrid_worker_trace(event_id, task_name,
                                                     message, t_id, keyword,
                                                     activity_id)
    def get_job_actions(self, sandbox_id):
        """Gets any pending job action for the given sandbox id.

        Args:
            sandbox_id: string, the sandbox id.

        Returns:
            A list of job actions.

        Note:
            The output list is of the following format:
            [
                {
                    "MessageMetadata": {
                        "PopReceipt": "AgAAAAMAAAAAAAAAPuDINxcZ0gE=",
                        "MessageId": "2e682df3-a6c6-4d23-afc2-40dc01c2a509"
                    },
                    "MessageSource'": "Queue",
                    "LockToken'": "00000000-0000-0000-0000-000000000000",
                    "JobId'": "6cbb98cc-d69a-46f0-a116-3b6094ceba6b"
                }
            ]
        """
        url = self.base_uri + "/automationAccounts/" + self.account_id + "/Sandboxes/" + sandbox_id + \
              "/jobs/getJobActions?api-version=" + self.protocol_version

        try:
            response = self.issue_request(lambda u: self.httpClient.get(u), url)
        except JrdsAuthorizationException:
            raise JrdsSandboxTerminated()

        if response.status_code == 200:
            try:
                if response.deserialized_data is None or "value" not in response.deserialized_data:
                    locallogger.log_info(
                        "INFO: Could not deserialize get_job_actions response body: %s" % str(response.deserialized_data))
                    return []
            except TypeError:
                locallogger.log_info(
                    "INFO: Could not deserialize get_job_actions response body: %s" % str(response.deserialized_data))
                return []
            job_actions = response.deserialized_data["value"]
            if len(job_actions) != 0:
                message_metadatas = [action["MessageMetadata"] for action in job_actions]
                self.acknowledge_job_action(sandbox_id, message_metadatas)
            return job_actions

        raise Exception("Unable to get job actions. [status=" + str(response.status_code) + "]")
    def issue_request(request_function, url):
        """Invokes request_funtion."""
        response = request_function(url)
        tries = 1
        max_tries = 5
        while response.status_code in transient_status_codes:
            if tries > max_tries:
                break
            locallogger.log_info("INFO: http code %d while trying to reach %s, retrying" %(response.status_code, url))
            time_to_wait = 3 * (2 ** tries)
            if time_to_wait > 60:
                time_to_wait = 60
            time.sleep(time_to_wait)
            response = request_function(url)
            tries += 1

        if response.status_code == 401:
            raise JrdsAuthorizationException()
        return response
    def get_sandbox_actions(self):
        """Gets any pending sandbox actions.

        Returns:
            A list of sandbox actions.

        Note:
            The output list is of the following format:
            [
                {
                    "SandboxId": "206738c8-b66a-4eee-95a6-ddc23e3833a9",
                    "ConnectionEndpoint": "",
                    "ConnectionPort": 0,
                    "SandboxCookie": "nQwdpZ3MK5s=",
                    "CredentialName": null,
                    "MSISecret": "NullableMSISecret"
                }
            ]
        """
        url = self.base_uri + "/automationAccounts/" + self.account_id + \
              "/Sandboxes/GetSandboxActions?HybridWorkerGroupName=" + self.HybridWorkerGroupName + \
              "&api-version=" + self.protocol_version
        response = self.issue_request(lambda u: self.httpClient.get(u), url)

        if response.status_code == 200:
            try:
                if response.deserialized_data is None or "value" not in response.deserialized_data:
                    locallogger.log_info(
                        "INFO: Could not deserialize get_sandbox_actions response body: %s"
                        % str(response.deserialized_data))
                    return None
            except TypeError:
                locallogger.log_info(
                    "INFO: Could not deserialize get_sandbox_actions response body: %s"
                    % str(response.deserialized_data))
                return None

            # success path
            return response.deserialized_data["value"]

        raise Exception("Unable to get sandbox actions. [status=" +
                        str(response.status_code) + "]")
def trace_generic_hybrid_worker_event(event_id, task_name, message, t_id, keyword, activity_id=None, debug=False):
    """Write the trace to STDOUT / log file (on disk) / to MDS (in the cloud).

    Args:
        event_id    : int   , the event id. This event id doesn't have to map to an ETW event id in the cloud.
        task_name   : string, the task name.
        message     : string, the message.
        t_id        : int   , the thread id.
        keyword     : string, the keyword.
        activity_id : string, the activity id.
        debug       : boolean, the debug flag
    """
    # # # # # # # # # # # # # # # # # # # #
    # for tests, disregard tracer
    if os.getenv('test_mode', None) is not None:
        return
    # # # # # # # # # # # # # # # # # # # #

    if jrds_client is None or locallogger.default_logger is None:
        init()

    if debug and not configuration.get_debug_traces():
        return

    if task_name.startswith("log"):
        task_name = "_".join(task_name.split("_")[1:])
    task_name = task_name.title().replace("_", "")

    if isinstance(message, dict):
        message = dict_to_str(message)

    if activity_id is None:
        activity_id = u_activity_id

    # local trace
    # we prioritize cloud traces, do not raise exception if local tracing raises an exception
    locallogger.log_info(message)

    # MDS
    if not debug:
        format_and_issue_generic_hybrid_worker_trace(event_id, task_name, message, t_id, keyword, activity_id)
    def issue_request(request_function, url):
        """Invokes request_funtion."""
        response = request_function(url)
        tries = 1
        max_tries = 5
        while response.status_code in transient_status_codes:
            if tries > max_tries:
                break
            locallogger.log_info(
                "INFO: http code %d while trying to reach %s, retrying" %
                (response.status_code, url))
            time_to_wait = 3 * (2**tries)
            if time_to_wait > 60:
                time_to_wait = 60
            time.sleep(time_to_wait)
            response = request_function(url)
            tries += 1

        if response.status_code == 401:
            raise JrdsAuthorizationException()
        return response
    def get_sandbox_actions(self):
        """Gets any pending sandbox actions.

        Returns:
            A list of sandbox actions.

        Note:
            The output list is of the following format:
            [
                {
                    "SandboxId": "206738c8-b66a-4eee-95a6-ddc23e3833a9",
                    "ConnectionEndpoint": "",
                    "ConnectionPort": 0,
                    "SandboxCookie": "nQwdpZ3MK5s=",
                    "CredentialName": null
                }
            ]
        """
        url = self.base_uri + "/automationAccounts/" + self.account_id + \
              "/Sandboxes/GetSandboxActions?HybridWorkerGroupName=" + self.HybridWorkerGroupName + \
              "&api-version=" + self.protocol_version
        response = self.issue_request(lambda u: self.httpClient.get(u), url)

        if response.status_code == 200:
            try:
                if response.deserialized_data is None or "value" not in response.deserialized_data:
                    locallogger.log_info("INFO: Could not deserialize get_sandbox_actions response body: %s" % str(response.deserialized_data))
                    return None
            except TypeError:
                locallogger.log_info("INFO: Could not deserialize get_sandbox_actions response body: %s" % str(response.deserialized_data))
                return None

        # success path
        return response.deserialized_data["value"]

        raise Exception("Unable to get sandbox actions. [status=" + str(response.status_code) + "]")