Ensure the spcifieda usage plan with the corresponding metrics is deployed

    .. versionadded:: 2017.7.0

    name
        name of the state

    plan_name
        [Required] name of the usage plan

    throttle
        [Optional] throttling parameters expressed as a dictionary.
        If provided, at least one of the throttling parameters must be present

        rateLimit
            rate per second at which capacity bucket is populated

        burstLimit
            maximum rate allowed

    quota
        [Optional] quota on the number of api calls permitted by the plan.
        If provided, limit and period must be present

        limit
            [Required] number of calls permitted per quota period

        offset
            [Optional] number of calls to be subtracted from the limit at the beginning of the period

        period
            [Required] period to which quota applies. Must be DAY, WEEK or MONTH

    .. code-block:: yaml

        UsagePlanPresent:
          boto_apigateway.usage_plan_present:
            - plan_name: my_usage_plan
            - throttle:
                rateLimit: 70
                burstLimit: 100
            - quota:
                limit: 1000
                offset: 0
                period: DAY
            - profile: my_profile

def usage_plan_present(name, plan_name, description=None, throttle=None, quota=None, region=None, key=None, keyid=None,
                       profile=None):
    '''
    Ensure the spcifieda usage plan with the corresponding metrics is deployed

    .. versionadded:: 2017.7.0

    name
        name of the state

    plan_name
        [Required] name of the usage plan

    throttle
        [Optional] throttling parameters expressed as a dictionary.
        If provided, at least one of the throttling parameters must be present

        rateLimit
            rate per second at which capacity bucket is populated

        burstLimit
            maximum rate allowed

    quota
        [Optional] quota on the number of api calls permitted by the plan.
        If provided, limit and period must be present

        limit
            [Required] number of calls permitted per quota period

        offset
            [Optional] number of calls to be subtracted from the limit at the beginning of the period

        period
            [Required] period to which quota applies. Must be DAY, WEEK or MONTH

    .. code-block:: yaml

        UsagePlanPresent:
          boto_apigateway.usage_plan_present:
            - plan_name: my_usage_plan
            - throttle:
                rateLimit: 70
                burstLimit: 100
            - quota:
                limit: 1000
                offset: 0
                period: DAY
            - profile: my_profile

    '''
    func_params = locals()

    ret = {'name': name,
           'result': True,
           'comment': '',
           'changes': {}
           }

    try:
        common_args = dict([('region', region),
                            ('key', key),
                            ('keyid', keyid),
                            ('profile', profile)])

        existing = __salt__['boto_apigateway.describe_usage_plans'](name=plan_name, **common_args)
        if 'error' in existing:
            ret['result'] = False
            ret['comment'] = 'Failed to describe existing usage plans'
            return ret

        if not existing['plans']:
            # plan does not exist, we need to create it
            if __opts__['test']:
                ret['comment'] = 'a new usage plan {0} would be created'.format(plan_name)
                ret['result'] = None
                return ret

            result = __salt__['boto_apigateway.create_usage_plan'](name=plan_name,
                                                                   description=description,
                                                                   throttle=throttle,
                                                                   quota=quota,
                                                                   **common_args)
            if 'error' in result:
                ret['result'] = False
                ret['comment'] = 'Failed to create a usage plan {0}, {1}'.format(plan_name, result['error'])
                return ret

            ret['changes']['old'] = {'plan': None}
            ret['comment'] = 'A new usage plan {0} has been created'.format(plan_name)

        else:
            # need an existing plan modified to match given value
            plan = existing['plans'][0]
            needs_updating = False

            modifiable_params = (('throttle', ('rateLimit', 'burstLimit')), ('quota', ('limit', 'offset', 'period')))
            for p, fields in modifiable_params:
                for f in fields:
                    actual_param = {} if func_params.get(p) is None else func_params.get(p)
                    if plan.get(p, {}).get(f, None) != actual_param.get(f, None):
                        needs_updating = True
                        break

            if not needs_updating:
                ret['comment'] = 'usage plan {0} is already in a correct state'.format(plan_name)
                ret['result'] = True
                return ret

            if __opts__['test']:
                ret['comment'] = 'a new usage plan {0} would be updated'.format(plan_name)
                ret['result'] = None
                return ret

            result = __salt__['boto_apigateway.update_usage_plan'](plan['id'],
                                                                   throttle=throttle,
                                                                   quota=quota,
                                                                   **common_args)
            if 'error' in result:
                ret['result'] = False
                ret['comment'] = 'Failed to update a usage plan {0}, {1}'.format(plan_name, result['error'])
                return ret

            ret['changes']['old'] = {'plan': plan}
            ret['comment'] = 'usage plan {0} has been updated'.format(plan_name)

        newstate = __salt__['boto_apigateway.describe_usage_plans'](name=plan_name, **common_args)
        if 'error' in existing:
            ret['result'] = False
            ret['comment'] = 'Failed to describe existing usage plans after updates'
            return ret

        ret['changes']['new'] = {'plan': newstate['plans'][0]}

    except (ValueError, IOError) as e:
        ret['result'] = False
        ret['comment'] = '{0}'.format(e.args)

    return ret