示例#1
0
def main():
    # define the available arguments/parameters that a user can pass to
    # the module

    application_arg_spec = dict(
        id=dict(type='str'),
        name=dict(type='str'),
    )

    rule_arg_spec = dict(
        policy=dict(type='str', choices=['deny'], default='deny'),
        type=dict(type='str',
                  choices=[
                      'application', 'application_category',
                      'blacklisted_countries', 'host', 'ip_range', 'port',
                      'whitelisted_countries'
                  ]),
        ip_range=dict(type='str'),
        application=dict(type='dict',
                         default=None,
                         options=application_arg_spec),
        host=dict(type='str'),
        port=dict(type='str'),
        countries=dict(type='list'),
    )

    argument_spec = meraki_argument_spec()
    argument_spec.update(
        state=dict(type='str', choices=['present', 'query'],
                   default='present'),
        net_name=dict(type='str'),
        net_id=dict(type='str'),
        rules=dict(type='list',
                   default=None,
                   elements='dict',
                   options=rule_arg_spec),
        categories=dict(type='bool'),
    )

    # seed the result dict in the object
    # we primarily care about changed and state
    # change is if this module effectively modified the target
    # state will include any data that you want your module to pass back
    # for consumption, for example, in a subsequent task
    result = dict(changed=False, )
    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )
    meraki = MerakiModule(module, function='mx_l7_firewall')

    # check for argument completeness
    if meraki.params['rules']:
        for rule in meraki.params['rules']:
            if rule['type'] == 'application' and rule['application'] is None:
                meraki.fail_json(
                    msg=
                    "application argument is required when type is application."
                )
            elif rule['type'] == 'application_category' and rule[
                    'application'] is None:
                meraki.fail_json(
                    msg=
                    "application argument is required when type is application_category."
                )
            elif rule['type'] == 'blacklisted_countries' and rule[
                    'countries'] is None:
                meraki.fail_json(
                    msg=
                    "countries argument is required when type is blacklisted_countries."
                )
            elif rule['type'] == 'host' and rule['host'] is None:
                meraki.fail_json(
                    msg="host argument is required when type is host.")
            elif rule['type'] == 'port' and rule['port'] is None:
                meraki.fail_json(
                    msg="port argument is required when type is port.")
            elif rule['type'] == 'whitelisted_countries' and rule[
                    'countries'] is None:
                meraki.fail_json(
                    msg=
                    "countries argument is required when type is whitelisted_countries."
                )

    meraki.params['follow_redirects'] = 'all'

    query_urls = {'mx_l7_firewall': '/networks/{net_id}/l7FirewallRules/'}
    query_category_urls = {
        'mx_l7_firewall':
        '/networks/{net_id}/l7FirewallRules/applicationCategories'
    }
    update_urls = {'mx_l7_firewall': '/networks/{net_id}/l7FirewallRules/'}

    meraki.url_catalog['get_all'].update(query_urls)
    meraki.url_catalog['get_categories'] = (query_category_urls)
    meraki.url_catalog['update'] = update_urls

    payload = None

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    org_id = meraki.params['org_id']
    orgs = None
    if org_id is None:
        orgs = meraki.get_orgs()
        for org in orgs:
            if org['name'] == meraki.params['org_name']:
                org_id = org['id']
    net_id = meraki.params['net_id']
    if net_id is None:
        if orgs is None:
            orgs = meraki.get_orgs()
        net_id = meraki.get_net_id(net_name=meraki.params['net_name'],
                                   data=meraki.get_nets(org_id=org_id))

    if meraki.params['state'] == 'query':
        if meraki.params['categories'] is True:  # Output only applications
            meraki.result['data'] = get_applications(meraki, net_id)
        else:
            meraki.result['data'] = restructure_response(
                get_rules(meraki, net_id))
    elif meraki.params['state'] == 'present':
        rules = get_rules(meraki, net_id)
        path = meraki.construct_path('get_all', net_id=net_id)
        if meraki.params['rules']:
            payload = {'rules': []}
            for rule in meraki.params['rules']:
                payload['rules'].append(assemble_payload(meraki, net_id, rule))
        else:
            payload = dict()
        '''
        The rename_* functions are needed because the key is id and
        is_update_required() by default ignores id.
        '''
        rules = rename_id_to_appid(rules)
        payload = rename_id_to_appid(payload)
        if meraki.is_update_required(rules, payload):
            rules = rename_appid_to_id(rules)
            payload = rename_appid_to_id(payload)
            if meraki.module.check_mode is True:
                response = restructure_response(payload)
                diff = recursive_diff(restructure_response(rules), response)
                meraki.result['diff'] = {
                    'before': diff[0],
                    'after': diff[1],
                }
                meraki.result['data'] = response
                meraki.result['changed'] = True
                meraki.exit_json(**meraki.result)
            response = meraki.request(path,
                                      method='PUT',
                                      payload=json.dumps(payload))
            response = restructure_response(response)
            if meraki.status == 200:
                diff = recursive_diff(restructure_response(rules), response)
                meraki.result['diff'] = {
                    'before': diff[0],
                    'after': diff[1],
                }
                meraki.result['data'] = response
                meraki.result['changed'] = True
        else:
            rules = rename_appid_to_id(rules)
            payload = rename_appid_to_id(payload)
            if meraki.module.check_mode is True:
                meraki.result['data'] = rules
                meraki.result['changed'] = False
                meraki.exit_json(**meraki.result)
            meraki.result['data'] = payload

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)
def main():
    # define the available arguments/parameters that a user can pass to
    # the module

    fw_rules = dict(
        policy=dict(type='str', choices=['allow', 'deny']),
        protocol=dict(type='str', choices=['tcp', 'udp', 'icmp', 'any']),
        dest_port=dict(type='str'),
        dest_cidr=dict(type='str'),
        src_port=dict(type='str'),
        src_cidr=dict(type='str'),
        comment=dict(type='str'),
        syslog_enabled=dict(type='bool', default=False),
    )

    argument_spec = meraki_argument_spec()
    argument_spec.update(
        state=dict(type='str', choices=['present', 'query'],
                   default='present'),
        net_name=dict(type='str'),
        net_id=dict(type='str'),
        rules=dict(type='list',
                   default=None,
                   elements='dict',
                   options=fw_rules),
        syslog_default_rule=dict(type='bool'),
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )
    meraki = MerakiModule(module, function='mx_l3_firewall')

    meraki.params['follow_redirects'] = 'all'

    query_urls = {'mx_l3_firewall': '/networks/{net_id}/l3FirewallRules/'}
    update_urls = {'mx_l3_firewall': '/networks/{net_id}/l3FirewallRules/'}

    meraki.url_catalog['get_all'].update(query_urls)
    meraki.url_catalog['update'] = update_urls

    payload = None

    # execute checks for argument completeness

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    org_id = meraki.params['org_id']
    if org_id is None:
        orgs = meraki.get_orgs()
        for org in orgs:
            if org['name'] == meraki.params['org_name']:
                org_id = org['id']
    net_id = meraki.params['net_id']
    if net_id is None:
        net_id = meraki.get_net_id(net_name=meraki.params['net_name'],
                                   data=meraki.get_nets(org_id=org_id))

    if meraki.params['state'] == 'query':
        meraki.result['data'] = get_rules(meraki, net_id)
    elif meraki.params['state'] == 'present':
        rules = get_rules(meraki, net_id)
        path = meraki.construct_path('get_all', net_id=net_id)
        if meraki.params['rules'] is not None:
            payload = assemble_payload(meraki)
        else:
            payload = dict()
        update = False
        if meraki.params['syslog_default_rule'] is not None:
            payload['syslogDefaultRule'] = meraki.params['syslog_default_rule']
        try:
            if meraki.params['rules'] is not None:
                if len(rules) - 1 != len(
                        payload['rules']
                ):  # Quick and simple check to avoid more processing
                    update = True
            if meraki.params['syslog_default_rule'] is not None:
                if rules[len(rules) - 1]['syslogEnabled'] != meraki.params[
                        'syslog_default_rule']:
                    update = True
            if update is False:
                default_rule = rules[len(rules) - 1].copy()
                del rules[len(rules) - 1]  # Remove default rule for comparison
                if len(rules) - 1 == 0:
                    normalize_case(rules[0])
                    normalize_case(payload['rules'][0])
                    # meraki.fail_json(msg='Compare', original=rules, payload=payload)
                    if meraki.is_update_required(rules[0],
                                                 payload['rules'][0]) is True:
                        update = True
                else:
                    for r in range(len(rules) - 1):
                        normalize_case(rules[r])
                        normalize_case(payload['rules'][r])
                        # meraki.fail_json(msg='Full Compare', original=rules, payload=payload)
                        if meraki.is_update_required(
                                rules[r], payload['rules'][r]) is True:
                            update = True
                rules.append(default_rule)
        except KeyError:
            pass
        if update is True:
            if meraki.check_mode is True:
                if meraki.params['rules'] is not None:
                    data = payload['rules']
                    data.append(rules[len(rules) -
                                      1])  # Append the default rule
                    if meraki.params['syslog_default_rule'] is not None:
                        data[len(payload) -
                             1]['syslog_enabled'] = meraki.params[
                                 'syslog_default_rule']
                else:
                    if meraki.params['syslog_default_rule'] is not None:
                        data = rules
                        data[len(data) - 1]['syslogEnabled'] = meraki.params[
                            'syslog_default_rule']
                meraki.result['data'] = data
                meraki.result['changed'] = True
                meraki.exit_json(**meraki.result)
            response = meraki.request(path,
                                      method='PUT',
                                      payload=json.dumps(payload))
            if meraki.status == 200:
                meraki.result['data'] = response
                meraki.result['changed'] = True
        else:
            meraki.result['data'] = rules

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)
示例#3
0
def main():

    # define the available arguments/parameters that a user can pass to
    # the module
    argument_spec = meraki_argument_spec()
    argument_spec.update(
        clone=dict(type='str'),
        state=dict(type='str',
                   choices=['absent', 'present', 'query'],
                   default='present'),
        org_name=dict(type='str', aliases=['name', 'organization']),
        org_id=dict(type='str', aliases=['id']),
        delete_confirm=dict(type='str'),
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )
    meraki = MerakiModule(module, function='organizations')

    meraki.params['follow_redirects'] = 'all'

    create_urls = {'organizations': '/organizations'}
    update_urls = {'organizations': '/organizations/{org_id}'}
    delete_urls = {'organizations': '/organizations/{org_id}'}
    clone_urls = {'organizations': '/organizations/{org_id}/clone'}

    meraki.url_catalog['create'] = create_urls
    meraki.url_catalog['update'] = update_urls
    meraki.url_catalog['clone'] = clone_urls
    meraki.url_catalog['delete'] = delete_urls

    payload = None

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    orgs = meraki.get_orgs()
    if meraki.params['state'] == 'query':
        if meraki.params['org_name']:  # Query by organization name
            module.warn(
                'All matching organizations will be returned, even if there are duplicate named organizations'
            )
            for o in orgs:
                if o['name'] == meraki.params['org_name']:
                    meraki.result['data'] = o
        elif meraki.params['org_id']:
            for o in orgs:
                if o['id'] == meraki.params['org_id']:
                    meraki.result['data'] = o
        else:  # Query all organizations, no matter what
            meraki.result['data'] = orgs
    elif meraki.params['state'] == 'present':
        if meraki.params['clone']:  # Cloning
            payload = {'name': meraki.params['org_name']}
            response = meraki.request(meraki.construct_path(
                'clone', org_name=meraki.params['clone']),
                                      payload=json.dumps(payload),
                                      method='POST')
            if meraki.status != 201:
                meraki.fail_json(msg='Organization clone failed')
            meraki.result['data'] = response
            meraki.result['changed'] = True
        elif not meraki.params['org_id'] and meraki.params[
                'org_name']:  # Create new organization
            payload = {'name': meraki.params['org_name']}
            response = meraki.request(meraki.construct_path('create'),
                                      method='POST',
                                      payload=json.dumps(payload))
            if meraki.status == 201:
                meraki.result['data'] = response
                meraki.result['changed'] = True
        elif meraki.params['org_id'] and meraki.params[
                'org_name']:  # Update an existing organization
            payload = {
                'name': meraki.params['org_name'],
                'id': meraki.params['org_id'],
            }
            original = get_org(meraki, meraki.params['org_id'], orgs)
            if meraki.is_update_required(original,
                                         payload,
                                         optional_ignore=['url']):
                response = meraki.request(meraki.construct_path(
                    'update', org_id=meraki.params['org_id']),
                                          method='PUT',
                                          payload=json.dumps(payload))
                if meraki.status != 200:
                    meraki.fail_json(msg='Organization update failed')
                meraki.result['data'] = response
                meraki.result['changed'] = True
            else:
                meraki.result['data'] = original
    elif meraki.params['state'] == 'absent':
        if meraki.params['org_name'] is not None:
            org_id = meraki.get_org_id(meraki.params['org_name'])
        elif meraki.params['org_id'] is not None:
            org_id = meraki.params['org_id']
        if meraki.params['delete_confirm'] != org_id:
            meraki.fail_json(
                msg=
                "delete_confirm must match the network ID of the network to be deleted."
            )
        if meraki.check_mode is True:
            meraki.result['data'] = {}
            meraki.result['changed'] = True
            meraki.exit_json(**meraki.result)
        path = meraki.construct_path('delete', org_id=org_id)
        response = meraki.request(path, method='DELETE')
        if meraki.status == 204:
            meraki.result['data'] = {}
            meraki.result['changed'] = True

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)
def main():
    # define the available arguments/parameters that a user can pass to
    # the module

    fw_rules = dict(
        policy=dict(type='str', choices=['allow', 'deny']),
        protocol=dict(type='str', choices=['tcp', 'udp', 'icmp', 'any']),
        dest_port=dict(type='str'),
        dest_cidr=dict(type='str'),
        comment=dict(type='str'),
    )

    argument_spec = meraki_argument_spec()
    argument_spec.update(
        state=dict(type='str', choices=['present', 'query'],
                   default='present'),
        net_name=dict(type='str'),
        net_id=dict(type='str'),
        number=dict(type='str', aliases=['ssid_number']),
        ssid_name=dict(type='str', aliases=['ssid']),
        rules=dict(type='list',
                   default=None,
                   elements='dict',
                   options=fw_rules),
        allow_lan_access=dict(type='bool', default=True),
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )
    meraki = MerakiModule(module, function='mr_l3_firewall')

    meraki.params['follow_redirects'] = 'all'

    query_urls = {
        'mr_l3_firewall': '/networks/{net_id}/ssids/{number}/l3FirewallRules'
    }
    update_urls = {
        'mr_l3_firewall': '/networks/{net_id}/ssids/{number}/l3FirewallRules'
    }

    meraki.url_catalog['get_all'].update(query_urls)
    meraki.url_catalog['update'] = update_urls

    payload = None

    # execute checks for argument completeness

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    org_id = meraki.params['org_id']
    orgs = None
    if org_id is None:
        orgs = meraki.get_orgs()
        for org in orgs:
            if org['name'] == meraki.params['org_name']:
                org_id = org['id']
    net_id = meraki.params['net_id']
    if net_id is None:
        if orgs is None:
            orgs = meraki.get_orgs()
        net_id = meraki.get_net_id(net_name=meraki.params['net_name'],
                                   data=meraki.get_nets(org_id=org_id))
    number = meraki.params['number']
    if meraki.params['ssid_name']:
        number = get_ssid_number(meraki.params['ssid_name'],
                                 get_ssids(meraki, net_id))

    if meraki.params['state'] == 'query':
        meraki.result['data'] = get_rules(meraki, net_id, number)
    elif meraki.params['state'] == 'present':
        rules = get_rules(meraki, net_id, number)
        path = meraki.construct_path('get_all',
                                     net_id=net_id,
                                     custom={'number': number})
        if meraki.params['rules']:
            payload = assemble_payload(meraki)
        else:
            payload = dict()
        update = False
        try:
            if len(rules) != len(
                    payload['rules']
            ):  # Quick and simple check to avoid more processing
                update = True
            if update is False:
                for r in range(len(rules) - 2):
                    if meraki.is_update_required(rules[r], payload[r]) is True:
                        update = True
        except KeyError:
            pass
        if rules[len(rules) - 2] != meraki.params['allow_lan_access']:
            update = True
        if update is True:
            payload['allowLanAccess'] = meraki.params['allow_lan_access']
            if meraki.check_mode is True:
                # This code is disgusting, rework it at some point
                if 'rules' in payload:
                    cleansed_payload = payload['rules']
                    cleansed_payload.append(rules[len(rules) - 1])
                    cleansed_payload.append(rules[len(rules) - 2])
                    if meraki.params['allow_lan_access'] is None:
                        cleansed_payload[len(cleansed_payload) -
                                         2]['policy'] = rules[len(rules) -
                                                              2]['policy']
                    else:
                        if meraki.params['allow_lan_access'] is True:
                            cleansed_payload[len(cleansed_payload) -
                                             2]['policy'] = 'allow'
                        else:
                            cleansed_payload[len(cleansed_payload) -
                                             2]['policy'] = 'deny'
                else:
                    if meraki.params['allow_lan_access'] is True:
                        rules[len(rules) - 2]['policy'] = 'allow'
                    else:
                        rules[len(rules) - 2]['policy'] = 'deny'
                    cleansed_payload = rules
                meraki.result['data'] = cleansed_payload
                meraki.result['changed'] = True
                meraki.exit_json(**meraki.result)
            response = meraki.request(path,
                                      method='PUT',
                                      payload=json.dumps(payload))
            if meraki.status == 200:
                meraki.result['data'] = response
                meraki.result['changed'] = True
        else:
            meraki.result['data'] = rules

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)
def main():
    # define the available arguments/parameters that a user can pass to
    # the module

    hubs_args = dict(hub_id=dict(type='str'),
                     use_default_route=dict(type='bool'),
                     )
    subnets_args = dict(local_subnet=dict(type='str'),
                        use_vpn=dict(type='bool'),
                        )

    argument_spec = meraki_argument_spec()
    argument_spec.update(state=dict(type='str', choices=['present', 'query'], default='present'),
                         net_name=dict(type='str'),
                         net_id=dict(type='str'),
                         hubs=dict(type='list', default=None, elements='dict', options=hubs_args),
                         subnets=dict(type='list', default=None, elements='dict', options=subnets_args),
                         mode=dict(type='str', choices=['none', 'hub', 'spoke']),
                         )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True,
                           )
    meraki = MerakiModule(module, function='site_to_site_vpn')

    meraki.params['follow_redirects'] = 'all'

    query_urls = {'site_to_site_vpn': '/networks/{net_id}/appliance/vpn/siteToSiteVpn/'}
    update_urls = {'site_to_site_vpn': '/networks/{net_id}/appliance/vpn/siteToSiteVpn/'}

    meraki.url_catalog['get_all'].update(query_urls)
    meraki.url_catalog['update'] = update_urls

    payload = None

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    org_id = meraki.params['org_id']
    if org_id is None:
        orgs = meraki.get_orgs()
        for org in orgs:
            if org['name'] == meraki.params['org_name']:
                org_id = org['id']
    net_id = meraki.params['net_id']
    if net_id is None:
        net_id = meraki.get_net_id(net_name=meraki.params['net_name'],
                                   data=meraki.get_nets(org_id=org_id))

    if meraki.params['state'] == 'query':
        path = meraki.construct_path('get_all', net_id=net_id)
        response = meraki.request(path, method='GET')
        meraki.result['data'] = response
    elif meraki.params['state'] == 'present':
        path = meraki.construct_path('get_all', net_id=net_id)
        original = meraki.request(path, method='GET')
        payload = assemble_payload(meraki)
        comparable = deepcopy(original)
        comparable.update(payload)
        if meraki.is_update_required(original, payload):
            path = meraki.construct_path('update', net_id=net_id)
            response = meraki.request(path, method='PUT', payload=json.dumps(payload))
            meraki.result['changed'] = True
            meraki.result['data'] = response
        else:
            meraki.result['data'] = original

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)
示例#6
0
def main():
    # define the available arguments/parameters that a user can pass to
    # the module

    argument_spec = meraki_argument_spec()
    argument_spec.update(
        state=dict(type='str',
                   choices=['present', 'query', 'absent'],
                   default='present'),
        net_name=dict(type='str'),
        net_id=dict(type='str'),
        stack_id=dict(type='str'),
        serials=dict(type='list', elements='str', default=None),
        name=dict(type='str'),
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )
    meraki = MerakiModule(module, function='switch_stack')

    meraki.params['follow_redirects'] = 'all'

    query_urls = {'switch_stack': '/networks/{net_id}/switch/stacks'}
    query_url = {'switch_stack': '/networks/{net_id}/switch/stacks/{stack_id}'}
    add_urls = {
        'switch_stack': '/networks/{net_id}/switch/stacks/{stack_id}/add'
    }
    remove_urls = {
        'switch_stack': '/networks/{net_id}/switch/stacks/{stack_id}/remove'
    }
    create_urls = {'switch_stack': '/networks/{net_id}/switch/stacks'}
    delete_urls = {
        'switch_stack': '/networks/{net_id}/switch/stacks/{stack_id}'
    }

    meraki.url_catalog['get_all'].update(query_urls)
    meraki.url_catalog['get_one'].update(query_url)
    meraki.url_catalog['add'] = add_urls
    meraki.url_catalog['remove'] = remove_urls
    meraki.url_catalog['create'] = create_urls
    meraki.url_catalog['delete'] = delete_urls

    payload = None

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    org_id = meraki.params['org_id']
    if org_id is None:
        orgs = meraki.get_orgs()
        for org in orgs:
            if org['name'] == meraki.params['org_name']:
                org_id = org['id']
    net_id = meraki.params['net_id']
    if net_id is None:
        net_id = meraki.get_net_id(net_name=meraki.params['net_name'],
                                   data=meraki.get_nets(org_id=org_id))

    # assign and lookup stack_id
    stack_id = meraki.params['stack_id']
    if stack_id is None and meraki.params['name'] is not None:
        stack_id = get_stack_id(meraki, net_id)
    path = meraki.construct_path('get_all', net_id=net_id)
    stacks = meraki.request(path, method='GET')

    if meraki.params['state'] == 'query':
        if stack_id is None:
            meraki.result['data'] = stacks
        else:
            meraki.result['data'] = get_stack(stack_id, stacks)
    elif meraki.params['state'] == 'present':
        if meraki.params['stack_id'] is None:
            payload = {
                'serials': meraki.params['serials'],
                'name': meraki.params['name'],
            }
            path = meraki.construct_path('create', net_id=net_id)
            response = meraki.request(path,
                                      method='POST',
                                      payload=json.dumps(payload))
            if meraki.status == 201:
                meraki.result['data'] = response
                meraki.result['changed'] = True
        else:
            payload = {'serial': meraki.params['serials'][0]}
            original = get_stack(stack_id, stacks)
            comparable = deepcopy(original)
            comparable.update(payload)
            if meraki.params['serials'][0] not in comparable['serials']:
                comparable['serials'].append(meraki.params['serials'][0])
            # meraki.fail_json(msg=comparable)
            if meraki.is_update_required(original,
                                         comparable,
                                         optional_ignore=['serial']):
                path = meraki.construct_path('add',
                                             net_id=net_id,
                                             custom={'stack_id': stack_id})
                response = meraki.request(path,
                                          method='POST',
                                          payload=json.dumps(payload))
                if meraki.status == 200:
                    meraki.result['data'] = response
                    meraki.result['changed'] = True
            else:
                meraki.result['data'] = original
    elif meraki.params['state'] == 'absent':
        if meraki.params['serials'] is None:
            path = meraki.construct_path('delete',
                                         net_id=net_id,
                                         custom={'stack_id': stack_id})
            response = meraki.request(path, method='DELETE')
            meraki.result['data'] = {}
            meraki.result['changed'] = True
        else:
            payload = {'serial': meraki.params['serials'][0]}
            original = get_stack(stack_id, stacks)
            comparable = deepcopy(original)
            comparable.update(payload)
            if meraki.params['serials'][0] in comparable['serials']:
                comparable['serials'].remove(meraki.params['serials'][0])
            if meraki.is_update_required(original,
                                         comparable,
                                         optional_ignore=['serial']):
                path = meraki.construct_path('remove',
                                             net_id=net_id,
                                             custom={'stack_id': stack_id})
                response = meraki.request(path,
                                          method='POST',
                                          payload=json.dumps(payload))
                if meraki.status == 200:
                    meraki.result['data'] = response
                    meraki.result['changed'] = True
            else:
                meraki.result['data'] = original

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)
def main():
    # define the available arguments/parameters that a user can pass to
    # the module

    ospf_arg_spec = dict(
        area=dict(type='str'),
        cost=dict(type='int'),
        is_passive_enabled=dict(type='bool'),
    )

    argument_spec = meraki_argument_spec()
    argument_spec.update(
        state=dict(type='str',
                   choices=['present', 'query', 'absent'],
                   default='present'),
        net_id=dict(type='str'),
        net_name=dict(type='str', aliases=['network']),
        stack_id=dict(type='str'),
        name=dict(type='str'),
        subnet=dict(type='str'),
        interface_id=dict(type='str'),
        interface_ip=dict(type='str'),
        multicast_routing=dict(
            type='str',
            choices=['disabled', 'enabled', 'IGMP snooping querier']),
        vlan_id=dict(type='int'),
        default_gateway=dict(type='str'),
        ospf_settings=dict(type='dict', default=None, options=ospf_arg_spec),
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )
    meraki = MerakiModule(module, function='ms_stack_l3_interfaces')

    meraki.params['follow_redirects'] = 'all'

    query_urls = {
        'ms_stack_l3_interfaces':
        '/networks/{net_id}/switch/stacks/{stack_id}/routing/interfaces'
    }
    query_one_urls = {
        'ms_stack_l3_interfaces':
        '/networks/{net_id}/switch/stacks/{stack_id}/routing/interfaces'
    }
    create_urls = {
        'ms_stack_l3_interfaces':
        '/networks/{net_id}/switch/stacks/{stack_id}/routing/interfaces'
    }
    update_urls = {
        'ms_stack_l3_interfaces':
        '/networks/{net_id}/switch/stacks/{stack_id}/routing/interfaces/{interface_id}'
    }
    delete_urls = {
        'ms_stack_l3_interfaces':
        '/networks/{net_id}/switch/stacks/{stack_id}/routing/interfaces/{interface_id}'
    }

    meraki.url_catalog['get_all'].update(query_urls)
    meraki.url_catalog['get_one'].update(query_one_urls)
    meraki.url_catalog['create'] = create_urls
    meraki.url_catalog['update'] = update_urls
    meraki.url_catalog['delete'] = delete_urls

    payload = None

    if meraki.params['vlan_id'] is not None:
        if meraki.params['vlan_id'] < 1 or meraki.params['vlan_id'] > 4094:
            meraki.fail_json(msg='vlan_id must be between 1 and 4094')

    org_id = meraki.params['org_id']
    if org_id is None:
        orgs = meraki.get_orgs()
        for org in orgs:
            if org['name'] == meraki.params['org_name']:
                org_id = org['id']
    net_id = meraki.params['net_id']
    if net_id is None:
        net_id = meraki.get_net_id(net_name=meraki.params['net_name'],
                                   data=meraki.get_nets(org_id=org_id))

    interface_id = meraki.params['interface_id']
    interfaces = None
    if interface_id is None:
        if meraki.params['name'] is not None:
            path = meraki.construct_path(
                'get_all',
                net_id=net_id,
                custom={'stack_id': meraki.params['stack_id']})
            interfaces = meraki.request(path, method='GET')
            interface_id = get_interface_id(meraki, interfaces,
                                            meraki.params['name'])

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)

    if meraki.params['state'] == 'query':
        if interface_id is not None:  # Query one interface
            path = meraki.construct_path('get_one',
                                         net_id=net_id,
                                         custom={
                                             'stack_id':
                                             meraki.params['stack_id'],
                                             'interface_id': interface_id
                                         })
            response = meraki.request(path, method='GET')
            meraki.result['data'] = response
            meraki.exit_json(**meraki.result)
        else:  # Query all interfaces
            path = meraki.construct_path(
                'get_all',
                net_id=net_id,
                custom={'stack_id': meraki.params['stack_id']})
            response = meraki.request(path, method='GET')
            meraki.result['data'] = response
            meraki.exit_json(**meraki.result)
    elif meraki.params['state'] == 'present':
        if interface_id is None:  # Create a new interface
            payload = construct_payload(meraki)
            if meraki.check_mode is True:
                meraki.result['data'] = payload
                meraki.result['changed'] = True
                meraki.exit_json(**meraki.result)
            path = meraki.construct_path(
                'create',
                net_id=net_id,
                custom={'stack_id': meraki.params['stack_id']})
            response = meraki.request(path,
                                      method='POST',
                                      payload=json.dumps(payload))
            meraki.result['data'] = response
            meraki.result['changed'] = True
            meraki.exit_json(**meraki.result)
        else:
            if interfaces is None:
                path = meraki.construct_path(
                    'get_all',
                    net_id=net_id,
                    custom={'stack_id': meraki.params['stack_id']})
                interfaces = meraki.request(path, method='GET')
            payload = construct_payload(meraki)
            interface = get_interface(interfaces, interface_id)
            if meraki.is_update_required(interface, payload):
                if meraki.check_mode is True:
                    interface.update(payload)
                    meraki.result['data'] = interface
                    meraki.result['changed'] = True
                    meraki.exit_json(**meraki.result)
                path = meraki.construct_path('update',
                                             net_id=net_id,
                                             custom={
                                                 'stack_id':
                                                 meraki.params['stack_id'],
                                                 'interface_id':
                                                 interface_id
                                             })
                response = meraki.request(path,
                                          method='PUT',
                                          payload=json.dumps(payload))
                meraki.result['data'] = response
                meraki.result['changed'] = True
                meraki.exit_json(**meraki.result)
            else:
                meraki.result['data'] = interface
                meraki.exit_json(**meraki.result)
    elif meraki.params['state'] == 'absent':
        if meraki.check_mode is True:
            meraki.result['data'] = {}
            meraki.result['changed'] = True
            meraki.exit_json(**meraki.result)
        path = meraki.construct_path('delete',
                                     net_id=net_id,
                                     custom={
                                         'stack_id':
                                         meraki.params['stack_id'],
                                         'interface_id':
                                         meraki.params['interface_id']
                                     })
        response = meraki.request(path, method='DELETE')
        meraki.result['data'] = response
        meraki.result['changed'] = True

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    meraki.exit_json(**meraki.result)