Manage the StatusPage configuration.

    config
        Dictionary with the expected configuration of the StatusPage.
        The main level keys of this dictionary represent the endpoint name.
        If a certain endpoint does not exist in this structure, it will be ignored / not configured.

    page_id
        Page ID. Can also be specified in the config file.

    api_key
        API key. Can also be specified in the config file.

    api_version: 1
        API version. Can also be specified in the config file.

    api_url
        Custom API URL in case the user has a StatusPage service running in a custom environment.

    pace: 1
        Max requests per second allowed by the API.

    allow_empty: False
        Allow empty config.

    SLS example:

    .. code-block:: yaml

        my-statuspage-config:
            statuspage.managed:
                - config:
                    components:
                        - name: component1
                          group_id: uy4g37rf
                        - name: component2
                          group_id: 3n4uyu4gf
                    incidents:
                        - name: incident1
                          status: resolved
                          impact: major
                          backfilled: false
                        - name: incident2
                          status: investigating
                          impact: minor

def managed(name,
            config,
            api_url=None,
            page_id=None,
            api_key=None,
            api_version=None,
            pace=_PACE,
            allow_empty=False):
    '''
    Manage the StatusPage configuration.

    config
        Dictionary with the expected configuration of the StatusPage.
        The main level keys of this dictionary represent the endpoint name.
        If a certain endpoint does not exist in this structure, it will be ignored / not configured.

    page_id
        Page ID. Can also be specified in the config file.

    api_key
        API key. Can also be specified in the config file.

    api_version: 1
        API version. Can also be specified in the config file.

    api_url
        Custom API URL in case the user has a StatusPage service running in a custom environment.

    pace: 1
        Max requests per second allowed by the API.

    allow_empty: False
        Allow empty config.

    SLS example:

    .. code-block:: yaml

        my-statuspage-config:
            statuspage.managed:
                - config:
                    components:
                        - name: component1
                          group_id: uy4g37rf
                        - name: component2
                          group_id: 3n4uyu4gf
                    incidents:
                        - name: incident1
                          status: resolved
                          impact: major
                          backfilled: false
                        - name: incident2
                          status: investigating
                          impact: minor
    '''
    complete_diff = {}
    ret = _default_ret(name)
    if not config and not allow_empty:
        ret.update({
            'result': False,
            'comment': 'Cannot remove everything. To allow this, please set the option `allow_empty` as True.'
        })
        return ret
    is_empty = True
    for endpoint_name, endpoint_expected_config in six.iteritems(config):
        if endpoint_expected_config:
            is_empty = False
        endpoint_existing_config_ret = __salt__['statuspage.retrieve'](endpoint=endpoint_name,
                                                                       api_url=api_url,
                                                                       page_id=page_id,
                                                                       api_key=api_key,
                                                                       api_version=api_version)
        if not endpoint_existing_config_ret.get('result'):
            ret.update({
                'comment': endpoint_existing_config_ret.get('comment')
            })
            return ret  # stop at first error
        endpoint_existing_config = endpoint_existing_config_ret.get('out')
        complete_diff[endpoint_name] = _compute_diff(endpoint_expected_config, endpoint_existing_config)
    if is_empty and not allow_empty:
        ret.update({
            'result': False,
            'comment': 'Cannot remove everything. To allow this, please set the option `allow_empty` as True.'
        })
        return ret
    any_changes = False
    for endpoint_name, endpoint_diff in six.iteritems(complete_diff):
        if endpoint_diff.get('add') or endpoint_diff.get('update') or endpoint_diff.get('remove'):
            any_changes = True
    if not any_changes:
        ret.update({
            'result': True,
            'comment': 'No changes required.',
            'changes': {}
        })
        return ret
    ret.update({
        'changes': complete_diff
    })
    if __opts__.get('test'):
        ret.update({
            'comment': 'Testing mode. Would apply the following changes:',
            'result': None
        })
        return ret
    for endpoint_name, endpoint_diff in six.iteritems(complete_diff):
        endpoint_sg = endpoint_name[:-1]  # singular
        for new_endpoint in endpoint_diff.get('add'):
            log.debug('Defining new %s %s',
                      endpoint_sg,
                      new_endpoint
                      )
            adding = __salt__['statuspage.create'](endpoint=endpoint_name,
                                                   api_url=api_url,
                                                   page_id=page_id,
                                                   api_key=api_key,
                                                   api_version=api_version,
                                                   **new_endpoint)
            if not adding.get('result'):
                ret.update({
                    'comment': adding.get('comment')
                })
                return ret
            if pace:
                time.sleep(1/pace)
        for update_endpoint in endpoint_diff.get('update'):
            if 'id' not in update_endpoint:
                continue
            endpoint_id = update_endpoint.pop('id')
            log.debug('Updating %s #%s: %s',
                      endpoint_sg,
                      endpoint_id,
                      update_endpoint
                      )
            updating = __salt__['statuspage.update'](endpoint=endpoint_name,
                                                     id=endpoint_id,
                                                     api_url=api_url,
                                                     page_id=page_id,
                                                     api_key=api_key,
                                                     api_version=api_version,
                                                     **update_endpoint)
            if not updating.get('result'):
                ret.update({
                    'comment': updating.get('comment')
                })
                return ret
            if pace:
                time.sleep(1/pace)
        for remove_endpoint in endpoint_diff.get('remove'):
            if 'id' not in remove_endpoint:
                continue
            endpoint_id = remove_endpoint.pop('id')
            log.debug('Removing %s #%s',
                      endpoint_sg,
                      endpoint_id
                      )
            removing = __salt__['statuspage.delete'](endpoint=endpoint_name,
                                                     id=endpoint_id,
                                                     api_url=api_url,
                                                     page_id=page_id,
                                                     api_key=api_key,
                                                     api_version=api_version)
            if not removing.get('result'):
                ret.update({
                    'comment': removing.get('comment')
                })
                return ret
            if pace:
                time.sleep(1/pace)
    ret.update({
        'result': True,
        'comment': 'StatusPage updated.'
    })
    return ret