Beispiel #1
0
def test_get_awsclient_args_missing_methodname():
    """Missing methodName raises."""
    context = Context({
        'k1': 'v1',
        'awsClientIn': {
            'serviceName': 'service name',
            'arbKey': 'arb_value'
        }
    })

    with pytest.raises(KeyNotInContextError) as err_info:
        contextargs.get_awsclient_args(context['awsClientIn'],
                                       'pypyraws.steps.client')

    assert str(err_info.value) == ("awsClientIn missing required key for "
                                   "pypyraws.steps.client: 'methodName'")
Beispiel #2
0
def test_get_awsclient_args_methodname_empty():
    """Whitespace serviceName raises."""
    context = Context({
        'k1': 'v1',
        'awsClientIn': {
            'serviceName': 'service name',
            'methodName': ' ',
            'arbKey': 'arb_value'
        }
    })

    with pytest.raises(KeyInContextHasNoValueError) as err_info:
        contextargs.get_awsclient_args(context['awsClientIn'],
                                       'pypyraws.steps.client')

    assert str(err_info.value) == ("methodName required in awsClientIn "
                                   "for pypyraws.steps.client")
Beispiel #3
0
def test_get_awsclient_args_missing_awsclientin():
    """Missing awsClientIn raises"""
    context = Context({'k1': 'v1'})

    with pytest.raises(KeyNotInContextError) as err_info:
        client_in, service_name, method_name = contextargs.get_awsclient_args(
            context, 'pypyraws.steps.client')

    assert repr(err_info.value) == (
        "KeyNotInContextError(\'awsClientIn not found in the pypyr "
        "context.',)")
Beispiel #4
0
def run_step(context):
    """Execute any low-level boto3 client method.

    All of the awsClientIn descendant values support {key}
    string interpolation.

    Args:
        context:
            Dictionary. Mandatory.
            Requires the following context keys in context:
                - awsClientIn. dict. mandatory. Contains keys:

            The awsClientIn dictionary should contain:
                - serviceName: mandatory. String for service name.
                               Available services here:
                  http://boto3.readthedocs.io/en/latest/reference/services/
                - methodName: mandatory. String. Name of method to execute.
                - clientArgs: optional. Dict. kwargs for the boto client ctor.
                - methodArgs: optional. Dict. kwargs for the client method call

    Returns: None. Although there is no return, this does add awsClientOut to
             context.

             Adds key to context for response from aws client:
                - awsClientOut. Dictionary containing the full aws response.

    Raises:
        botocore.exceptions.ClientError: Anything inside boto went wrong.
        pypyr.errors.KeyNotInContextError: awsClientIn missing in context.
        pypyr.errors.KeyInContextHasNoValueError: awsClientIn exists but is
                                                  None.
    """
    logger.debug("started")
    client_in, service_name, method_name = contextargs.get_awsclient_args(
        context, __name__)

    client_args = contextargs.get_formatted_iterable(input_dict=client_in,
                                                     field_name='clientArgs',
                                                     context=context)

    method_args = contextargs.get_formatted_iterable(input_dict=client_in,
                                                     field_name='methodArgs',
                                                     context=context)

    context['awsClientOut'] = pypyraws.aws.service.operation_exec(
        service_name=context.get_formatted_string(service_name),
        method_name=context.get_formatted_string(method_name),
        client_args=client_args,
        operation_args=method_args)

    logger.debug("aws response in context['awsClientOut']")
    logger.info(f"Executed {method_name} on aws {service_name}.")

    logger.debug("done")
Beispiel #5
0
def test_get_awsclient_args_missing_servicename():
    """Missing serviceName raises"""
    context = Context({
        'k1': 'v1',
        'awsClientIn': {
            'methodName': 'method_name',
            'arbKey': 'arb_value'
        }})

    with pytest.raises(KeyNotInContextError) as err_info:
        client_in, service_name, method_name = contextargs.get_awsclient_args(
            context, 'pypyraws.steps.client')

    assert repr(err_info.value) == (
        "KeyNotInContextError(\"awsClientIn missing required key for "
        "pypyraws.steps.client: 'serviceName'\",)")
Beispiel #6
0
def test_get_awsclient_args_servicename_empty():
    """Empty serviceName raises"""
    context = Context({
        'k1': 'v1',
        'awsClientIn': {
            'serviceName': '',
            'methodName': 'method_name',
            'arbKey': 'arb_value'
        }})

    with pytest.raises(KeyInContextHasNoValueError) as err_info:
        client_in, service_name, method_name = contextargs.get_awsclient_args(
            context, 'pypyraws.steps.client')

    assert repr(err_info.value) == (
        "KeyInContextHasNoValueError('serviceName required in awsClientIn "
        "for pypyraws.steps.client',)")
Beispiel #7
0
def test_get_awsclient_args_pass():
    """get_awsclient_args pass."""
    context = Context({
        'k1': 'v1',
        'awsClientIn': {
            'serviceName': 'service name',
            'methodName': 'method_name',
            'arbKey': 'arb_value'
        }
    })
    (service_name, method_name, client_args,
     method_args) = contextargs.get_awsclient_args(context['awsClientIn'],
                                                   'pypyraws.steps.client')

    assert service_name == 'service name'
    assert method_name == 'method_name'
    assert client_args is None
    assert method_args is None
Beispiel #8
0
def test_get_awsclient_args_pass():
    """get_awsclient_args pass"""
    context = Context({
        'k1': 'v1',
        'awsClientIn': {
            'serviceName': 'service name',
            'methodName': 'method_name',
            'arbKey': 'arb_value'
        }})
    client_in, service_name, method_name = contextargs.get_awsclient_args(
        context, 'pypyraws.steps.client')

    assert client_in == {
        'serviceName': 'service name',
        'methodName': 'method_name',
        'arbKey': 'arb_value'
    }
    assert service_name == 'service name'
    assert method_name == 'method_name'
Beispiel #9
0
def run_step(context):
    """Custom waiter for any aws client operation.

    All of the awsWaitFor descendant values support {key}
    string interpolation, except waitForField.

    Args:
        context:
            Dictionary. Mandatory.
            Requires the following context keys in context:
                - awsWaitFor. dict. mandatory. Contains keys:
                    - awsClientIn. dict. mandatory. This is the same as for the
                      pypyraws.steps.client in step. Contains keys:
                      - serviceName: mandatory. String for service name.
                                       Available services here:
                        http://boto3.readthedocs.io/en/latest/reference/services/
                      - methodName: mandatory. String. Name of method to
                                    execute.
                      - clientArgs: optional. Dict. kwargs for the boto client
                                    ctor.
                      - methodArgs: optional. Dict. kwargs for the client
                                    method call
                    - waitForField: mandatory. string. format expression for
                                    field name to check in awsClient response.
                    - toBe: mandatory. string. string. Stop waiting when
                            waitForField equals this value.
                    - pollInterval: optional. int. In seconds. Default to 30.
                    - maxAttempts: optional. int. Default 10.
                    - errorOnWaitTimeout: optional. Default True. Throws error
                                          if maxAttempts exhausted without
                                          reaching toBe value. If false,
                                          step completes without raising
                                          error.

    Returns: None
             Adds key to context:
            - awsWaitForTimedOut: bool. Adds key with value True if
              errorOnWaitTimeout=False and max_attempts exhausted without
              reaching toBe. If steps completes successfully and waitForField's
              value becomes toBe, awsWaitForTimedOut == False.

    Raises:
        pypyr.errors.KeyNotInContextError: awsWaitFor missing in context.
        pypyr.errors.KeyInContextHasNoValueError: awsWaitFor exists but is
                                                None.
        pypyraws.errors.WaitTimeOut: maxAttempts exceeded without waitForField
                                  changing to toBe.
    """
    logger.debug("started")
    context.assert_key_has_value('awsWaitFor', __name__)
    wait_for = context['awsWaitFor']

    client_in, service_name, method_name = contextargs.get_awsclient_args(
        wait_for, __name__)

    service_name = context.get_formatted_string(service_name)
    method_name = context.get_formatted_string(method_name)

    client_args = contextargs.get_formatted_iterable(input_dict=client_in,
                                                     field_name='clientArgs',
                                                     context=context)

    method_args = contextargs.get_formatted_iterable(input_dict=client_in,
                                                     field_name='methodArgs',
                                                     context=context)

    (wait_for_field, to_be, poll_interval, max_attempts,
     error_on_wait_timeout) = get_poll_args(wait_for, context)

    wait_response = wait_until_true(
        interval=poll_interval,
        max_attempts=max_attempts)(execute_aws_client_method)(
            service_name=service_name,
            method_name=method_name,
            client_args=client_args,
            method_args=method_args,
            wait_for_field=wait_for_field,
            to_be=to_be)

    if wait_response:
        context['awsWaitForTimedOut'] = False
        logger.info(f"aws {service_name} {method_name} returned {to_be}. "
                    "Pipeline will now continue.")
    else:
        if error_on_wait_timeout:
            context['awsWaitForTimedOut'] = True
            logger.error(f"aws {service_name} {method_name} did not return "
                         f"{to_be} within {max_attempts}. errorOnWaitTimeout "
                         "is True, throwing error")
            raise WaitTimeOut(f"aws {service_name} {method_name} did not "
                              f"return {to_be} within {max_attempts} retries.")
        else:
            context['awsWaitForTimedOut'] = True
            logger.warn(f"aws {service_name} {method_name} did NOT return "
                        f" {to_be}. errorOnWaitTimeout is False, so pipeline "
                        "will proceed to the next step anyway.")

    logger.debug("done")