def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', aliases=[
            'name'
        ]),  # This parameter is not required for querying all objects
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'absent', ['vrf']],
            ['state', 'present', ['vrf']],
        ],
    )

    schema = module.params.get('schema')
    site = module.params.get('site')
    template = module.params.get('template')
    vrf = module.params.get('vrf')
    state = module.params.get('state')

    mso = MSOModule(module)

    # Get schema_id
    schema_obj = mso.get_obj('schemas', displayName=schema)
    if not schema_obj:
        mso.fail_json(
            msg="Provided schema '{0}' does not exist".format(schema))

    schema_path = 'schemas/{id}'.format(**schema_obj)
    schema_id = schema_obj.get('id')

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    if 'sites' not in schema_obj:
        mso.fail_json(
            msg=
            "No site associated with template '{0}'. Associate the site with the template using mso_schema_site."
            .format(template))
    sites = [(s.get('siteId'), s.get('templateName'))
             for s in schema_obj.get('sites')]
    if (site_id, template) not in sites:
        mso.fail_json(
            msg=
            "Provided site/template '{0}-{1}' does not exist. Existing sites/templates: {2}"
            .format(site, template, ', '.join(sites)))

    # Schema-access uses indexes
    site_idx = sites.index((site_id, template))
    # Path-based access uses site_id-template
    site_template = '{0}-{1}'.format(site_id, template)

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    vrfs = [v.get('vrfRef') for v in schema_obj.get('sites')[site_idx]['vrfs']]
    if vrf is not None and vrf_ref in vrfs:
        vrf_idx = vrfs.index(vrf_ref)
        vrf_path = '/sites/{0}/vrfs/{1}'.format(site_template, vrf)
        mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]

    if state == 'query':
        if vrf is None:
            mso.existing = schema_obj.get('sites')[site_idx]['vrfs']
        elif not mso.existing:
            mso.fail_json(msg="VRF '{vrf}' not found".format(vrf=vrf))
        mso.exit_json()

    vrfs_path = '/sites/{0}/vrfs'.format(site_template)
    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(dict(op='remove', path=vrf_path))

    elif state == 'present':
        payload = dict(vrfRef=dict(
            schemaId=schema_id,
            templateName=template,
            vrfName=vrf,
        ), )

        mso.sanitize(payload, collate=True)

        if mso.existing:
            ops.append(dict(op='replace', path=vrf_path, value=mso.sent))
        else:
            ops.append(dict(op='add', path=vrfs_path + '/-', value=mso.sent))

        mso.existing = mso.proposed

    if not module.check_mode:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()
def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', required=True),
        region=dict(type='str', required=True),
        cidr=dict(type='str', aliases=[
            'ip'
        ]),  # This parameter is not required for querying all objects
        primary=dict(type='bool', default=True),
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'absent', ['cidr']],
            ['state', 'present', ['cidr']],
        ],
    )

    schema = module.params.get('schema')
    site = module.params.get('site')
    template = module.params.get('template')
    vrf = module.params.get('vrf')
    region = module.params.get('region')
    cidr = module.params.get('cidr')
    primary = module.params.get('primary')
    state = module.params.get('state')

    mso = MSOModule(module)

    # Get schema_id
    schema_obj = mso.get_obj('schemas', displayName=schema)
    if not schema_obj:
        mso.fail_json(
            msg="Provided schema '{0}' does not exist".format(schema))

    schema_path = 'schemas/{id}'.format(**schema_obj)
    schema_id = schema_obj.get('id')

    # Get template
    templates = [t.get('name') for t in schema_obj.get('templates')]
    if template not in templates:
        mso.fail_json(
            msg="Provided template '{0}' does not exist. Existing templates: {1}"
            .format(template, ', '.join(templates)))
    template_idx = templates.index(template)

    payload = dict()
    op_path = ''
    new_cidr = dict(
        ip=cidr,
        primary=primary,
    )

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    all_sites = schema_obj.get('sites')
    sites = []
    if all_sites is not None:
        sites = [(s.get('siteId'), s.get('templateName')) for s in all_sites]

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    template_vrfs = [
        a.get('name') for a in schema_obj['templates'][template_idx]['vrfs']
    ]
    if vrf not in template_vrfs:
        mso.fail_json(
            msg="Provided vrf '{0}' does not exist. Existing vrfs: {1}".format(
                vrf, ', '.join(template_vrfs)))

    # if site-template does not exist, create it
    if (site_id, template) not in sites:
        op_path = '/sites/-'
        payload.update(siteId=site_id,
                       templateName=template,
                       vrfs=[
                           dict(vrfRef=dict(
                               schemaId=schema_id,
                               templateName=template,
                               vrfName=vrf,
                           ),
                                regions=[dict(name=region, cidrs=[new_cidr])])
                       ])

    else:
        # Schema-access uses indexes
        site_idx = sites.index((site_id, template))
        # Path-based access uses site_id-template
        site_template = '{0}-{1}'.format(site_id, template)

        # If vrf not at site level but exists at template level
        vrfs = [
            v.get('vrfRef') for v in schema_obj.get('sites')[site_idx]['vrfs']
        ]
        if vrf_ref not in vrfs:
            op_path = '/sites/{0}/vrfs/-'.format(site_template)
            payload.update(vrfRef=dict(
                schemaId=schema_id,
                templateName=template,
                vrfName=vrf,
            ),
                           regions=[dict(name=region, cidrs=[new_cidr])])
        else:
            # Update vrf index at site level
            vrf_idx = vrfs.index(vrf_ref)

            # Get Region
            regions = [
                r.get('name') for r in schema_obj.get('sites')[site_idx]
                ['vrfs'][vrf_idx]['regions']
            ]
            if region not in regions:
                op_path = '/sites/{0}/vrfs/{1}/regions/-'.format(
                    site_template, vrf)
                payload.update(name=region, cidrs=[new_cidr])
            else:
                region_idx = regions.index(region)

                # Get CIDR
                cidrs = [
                    c.get('ip') for c in schema_obj.get('sites')[site_idx]
                    ['vrfs'][vrf_idx]['regions'][region_idx]['cidrs']
                ]
                if cidr is not None:
                    if cidr in cidrs:
                        cidr_idx = cidrs.index(cidr)
                        # FIXME: Changes based on index are DANGEROUS
                        cidr_path = '/sites/{0}/vrfs/{1}/regions/{2}/cidrs/{3}'.format(
                            site_template, vrf, region, cidr_idx)
                        mso.existing = schema_obj.get(
                            'sites')[site_idx]['vrfs'][vrf_idx]['regions'][
                                region_idx]['cidrs'][cidr_idx]
                    op_path = '/sites/{0}/vrfs/{1}/regions/{2}/cidrs/-'.format(
                        site_template, vrf, region)
                    payload = new_cidr

    if state == 'query':
        if (site_id, template) not in sites:
            mso.fail_json(
                msg=
                "Provided site-template association '{0}-{1}' does not exist.".
                format(site, template))
        elif vrf_ref not in vrfs:
            mso.fail_json(
                msg="Provided vrf '{0}' does not exist at site level.".format(
                    vrf))
        elif not regions or region not in regions:
            mso.fail_json(
                msg="Provided region '{0}' does not exist. Existing regions: {1}"
                .format(region, ', '.join(regions)))
        elif cidr is None and not payload:
            mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx][
                'regions'][region_idx]['cidrs']
        elif not mso.existing:
            mso.fail_json(msg="CIDR IP '{cidr}' not found".format(cidr=cidr))
        mso.exit_json()

    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(dict(op='remove', path=cidr_path))

    elif state == 'present':
        mso.sanitize(payload, collate=True)

        if mso.existing:
            ops.append(dict(op='replace', path=cidr_path, value=mso.sent))
        else:
            ops.append(dict(op='add', path=op_path, value=mso.sent))

        mso.existing = new_cidr

    if not module.check_mode and mso.previous != mso.existing:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()
Exemplo n.º 3
0
def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', required=True),
        region=dict(type='str', required=True),
        hub_network=dict(type='dict', options=mso_hub_network_spec()),
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'present', ['hub_network']],
        ],
    )

    schema = module.params.get('schema')
    site = module.params.get('site')
    template = module.params.get('template').replace(' ', '')
    vrf = module.params.get('vrf')
    region = module.params.get('region')
    hub_network = module.params.get('hub_network')
    state = module.params.get('state')

    mso = MSOModule(module)

    # Get schema objects
    schema_id, schema_path, schema_obj = mso.query_schema(schema)

    # Get template
    templates = [t.get('name') for t in schema_obj.get('templates')]
    if template not in templates:
        mso.fail_json(
            msg="Provided template '{0}' does not exist. Existing templates: {1}"
            .format(template, ', '.join(templates)))

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    if 'sites' not in schema_obj:
        mso.fail_json(
            msg=
            "No site associated with template '{0}'. Associate the site with the template using mso_schema_site."
            .format(template))
    sites = [(s.get('siteId'), s.get('templateName'))
             for s in schema_obj.get('sites')]
    if (site_id, template) not in sites:
        mso.fail_json(
            msg="Provided site-template association '{0}-{1}' does not exist.".
            format(site, template))

    # Schema-access uses indexes
    site_idx = sites.index((site_id, template))
    # Path-based access uses site_id-template
    site_template = '{0}-{1}'.format(site_id, template)

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    vrfs = [v.get('vrfRef') for v in schema_obj.get('sites')[site_idx]['vrfs']]
    vrfs_name = [mso.dict_from_ref(v).get('vrfName') for v in vrfs]
    if vrf_ref not in vrfs:
        mso.fail_json(
            msg="Provided vrf '{0}' does not exist. Existing vrfs: {1}".format(
                vrf, ', '.join(vrfs_name)))
    vrf_idx = vrfs.index(vrf_ref)

    # Get Region
    regions = [
        r.get('name')
        for r in schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]['regions']
    ]
    if region not in regions:
        mso.fail_json(
            msg="Provided region '{0}' does not exist. Existing regions: {1}".
            format(region, ', '.join(regions)))
    region_idx = regions.index(region)
    # Get Region object
    region_obj = schema_obj.get(
        'sites')[site_idx]['vrfs'][vrf_idx]['regions'][region_idx]
    region_path = '/sites/{0}/vrfs/{1}/regions/{2}'.format(
        site_template, vrf, region)

    # Get hub network
    existing_hub_network = region_obj.get('cloudRsCtxProfileToGatewayRouterP')
    if existing_hub_network is not None:
        mso.existing = existing_hub_network

    if state == 'query':
        if not mso.existing:
            mso.fail_json(msg="Hub network not found")
        mso.exit_json()

    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(
                dict(op='remove',
                     path=region_path + '/cloudRsCtxProfileToGatewayRouterP'))
            ops.append(
                dict(op='replace',
                     path=region_path + '/isTGWAttachment',
                     value=False))

    elif state == 'present':
        new_hub_network = dict(
            name=hub_network.get('name'),
            tenantName=hub_network.get('tenant'),
        )
        payload = region_obj
        payload.update(
            cloudRsCtxProfileToGatewayRouterP=new_hub_network,
            isTGWAttachment=True,
        )

        mso.sanitize(payload, collate=True)

        ops.append(dict(op='replace', path=region_path, value=mso.sent))

        mso.existing = new_hub_network

    if not module.check_mode and mso.previous != mso.existing:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()
def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', required=True),
        region=dict(type='str', required=True),
        cidr=dict(type='str', required=True),
        subnet=dict(type='str', aliases=[
            'ip'
        ]),  # This parameter is not required for querying all objects
        zone=dict(type='str', aliases=['name']),
        vgw=dict(type='bool'),
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'absent', ['subnet']],
            ['state', 'present', ['subnet']],
        ],
    )

    schema = module.params.get('schema')
    site = module.params.get('site')
    template = module.params.get('template')
    vrf = module.params.get('vrf')
    region = module.params.get('region')
    cidr = module.params.get('cidr')
    subnet = module.params.get('subnet')
    zone = module.params.get('zone')
    vgw = module.params.get('vgw')
    state = module.params.get('state')

    mso = MSOModule(module)

    # Get schema_id
    schema_obj = mso.get_obj('schemas', displayName=schema)
    if not schema_obj:
        mso.fail_json(
            msg="Provided schema '{0}' does not exist".format(schema))

    schema_path = 'schemas/{id}'.format(**schema_obj)
    schema_id = schema_obj.get('id')

    # Get template
    templates = [t.get('name') for t in schema_obj.get('templates')]
    if template not in templates:
        mso.fail_json(
            msg="Provided template '{0}' does not exist. Existing templates: {1}"
            .format(template, ', '.join(templates)))

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    if 'sites' not in schema_obj:
        mso.fail_json(
            msg=
            "No site associated with template '{0}'. Associate the site with the template using mso_schema_site."
            .format(template))
    sites = [(s.get('siteId'), s.get('templateName'))
             for s in schema_obj.get('sites')]
    sites_list = [
        s.get('siteId') + '/' + s.get('templateName')
        for s in schema_obj.get('sites')
    ]
    if (site_id, template) not in sites:
        mso.fail_json(
            msg="Provided site/siteId/template '{0}/{1}/{2}' does not exist. "
            "Existing siteIds/templates: {3}".format(site, site_id, template,
                                                     ', '.join(sites_list)))

    # Schema-access uses indexes
    site_idx = sites.index((site_id, template))
    # Path-based access uses site_id-template
    site_template = '{0}-{1}'.format(site_id, template)

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    vrfs = [v.get('vrfRef') for v in schema_obj.get('sites')[site_idx]['vrfs']]

    # If vrf not at site level but exists at template level
    if vrf_ref not in vrfs:
        mso.fail_json(
            msg="Provided vrf '{0}' does not exist at site level."
            " Use mso_schema_site_vrf_region_cidr to create it.".format(vrf))
    vrf_idx = vrfs.index(vrf_ref)

    # Get Region
    regions = [
        r.get('name')
        for r in schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]['regions']
    ]
    if region not in regions:
        mso.fail_json(
            msg="Provided region '{0}' does not exist. Existing regions: {1}."
            " Use mso_schema_site_vrf_region_cidr to create it.".format(
                region, ', '.join(regions)))
    region_idx = regions.index(region)

    # Get CIDR
    cidrs = [
        c.get('ip') for c in schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]
        ['regions'][region_idx]['cidrs']
    ]
    if cidr not in cidrs:
        mso.fail_json(
            msg="Provided CIDR IP '{0}' does not exist. Existing CIDR IPs: {1}."
            " Use mso_schema_site_vrf_region_cidr to create it.".format(
                cidr, ', '.join(cidrs)))
    cidr_idx = cidrs.index(cidr)

    # Get Subnet
    subnets = [
        s.get('ip') for s in schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]
        ['regions'][region_idx]['cidrs'][cidr_idx]['subnets']
    ]
    if subnet is not None and subnet in subnets:
        subnet_idx = subnets.index(subnet)
        # FIXME: Changes based on index are DANGEROUS
        subnet_path = '/sites/{0}/vrfs/{1}/regions/{2}/cidrs/{3}/subnets/{4}'.format(
            site_template, vrf, region, cidr_idx, subnet_idx)
        mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx][
            'regions'][region_idx]['cidrs'][cidr_idx]['subnets'][subnet_idx]

    if state == 'query':
        if subnet is None:
            mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx][
                'regions'][region_idx]['cidrs'][cidr_idx]['subnets']
        elif not mso.existing:
            mso.fail_json(msg="Subnet IP '{subnet}' not found".format(
                subnet=subnet))
        mso.exit_json()

    subnets_path = '/sites/{0}/vrfs/{1}/regions/{2}/cidrs/{3}/subnets'.format(
        site_template, vrf, region, cidr_idx)
    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(dict(op='remove', path=subnet_path))

    elif state == 'present':
        payload = dict(ip=subnet, zone="")

        if zone is not None:
            payload['zone'] = zone
        elif vgw is True:
            payload['usage'] = 'gateway'

        mso.sanitize(payload, collate=True)

        if mso.existing:
            ops.append(dict(op='replace', path=subnet_path, value=mso.sent))
        else:
            ops.append(dict(op='add', path=subnets_path + '/-',
                            value=mso.sent))

        mso.existing = mso.proposed

    if not module.check_mode:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()
Exemplo n.º 5
0
def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', required=True),
        region=dict(type='str', aliases=['name']),  # This parameter is not required for querying all objects
        vpn_gateway_router=dict(type='bool'),
        container_overlay=dict(type='bool'),
        underlay_context_profile=dict(type='dict', options=dict(
            vrf=dict(type='str', required=True),
            region=dict(type='str', required=True),
        )),
        state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'absent', ['region']],
            ['state', 'present', ['region']],
        ],
    )

    schema = module.params.get('schema')
    site = module.params.get('site')
    template = module.params.get('template').replace(' ', '')
    vrf = module.params.get('vrf')
    region = module.params.get('region')
    vpn_gateway_router = module.params.get('vpn_gateway_router')
    container_overlay = module.params.get('container_overlay')
    underlay_context_profile = module.params.get('underlay_context_profile')
    state = module.params.get('state')

    mso = MSOModule(module)

    # Get schema objects
    schema_id, schema_path, schema_obj = mso.query_schema(schema)

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    if 'sites' not in schema_obj:
        mso.fail_json(msg="No site associated with template '{0}'. Associate the site with the template using mso_schema_site.".format(template))
    sites = [(s.get('siteId'), s.get('templateName')) for s in schema_obj.get('sites')]
    if (site_id, template) not in sites:
        mso.fail_json(msg="Provided site-template association '{0}-{1}' does not exist.".format(site, template))

    # Schema-access uses indexes
    site_idx = sites.index((site_id, template))
    # Path-based access uses site_id-template
    site_template = '{0}-{1}'.format(site_id, template)

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    vrfs = [v.get('vrfRef') for v in schema_obj.get('sites')[site_idx]['vrfs']]
    vrfs_name = [mso.dict_from_ref(v).get('vrfName') for v in vrfs]
    if vrf_ref not in vrfs:
        mso.fail_json(msg="Provided vrf '{0}' does not exist. Existing vrfs: {1}".format(vrf, ', '.join(vrfs_name)))
    vrf_idx = vrfs.index(vrf_ref)

    # Get Region
    regions = [r.get('name') for r in schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]['regions']]
    if region is not None and region in regions:
        region_idx = regions.index(region)
        region_path = '/sites/{0}/vrfs/{1}/regions/{2}'.format(site_template, vrf, region)
        mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]['regions'][region_idx]

    if state == 'query':
        if region is None:
            mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]['regions']
        elif not mso.existing:
            mso.fail_json(msg="Region '{region}' not found".format(region=region))
        mso.exit_json()

    regions_path = '/sites/{0}/vrfs/{1}/regions'.format(site_template, vrf)
    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(dict(op='remove', path=region_path))

    elif state == 'present':

        payload = dict(
            name=region,
            isVpnGatewayRouter=vpn_gateway_router,
        )

        if container_overlay:
            payload['contextProfileType'] = 'container-overlay'
            if mso.existing:
                underlay_dict = dict(
                    vrfRef=dict(
                        schemaId=schema_id,
                        templateName=template,
                        vrfName=underlay_context_profile['vrf']
                    ),
                    regionName=underlay_context_profile['region']
                )
                payload['underlayCtxProfile'] = underlay_dict

        mso.sanitize(payload, collate=True)
        if mso.existing:
            ops.append(dict(op='replace', path=region_path, value=mso.sent))
        else:
            ops.append(dict(op='add', path=regions_path + '/-', value=mso.sent))

        mso.existing = mso.proposed

    if not module.check_mode:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()
def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', required=True),
        region=dict(type='str', required=True),
        cidr=dict(type='str', required=True),
        subnet=dict(type='str', aliases=[
            'ip'
        ]),  # This parameter is not required for querying all objects
        zone=dict(type='str', aliases=['name']),
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'absent', ['subnet']],
            ['state', 'present', ['subnet', 'zone']],
        ],
    )

    schema = module.params['schema']
    site = module.params['site']
    template = module.params['template']
    vrf = module.params['vrf']
    region = module.params['region']
    cidr = module.params['cidr']
    subnet = module.params['subnet']
    zone = module.params['zone']
    state = module.params['state']

    mso = MSOModule(module)

    # Get schema_id
    schema_obj = mso.get_obj('schemas', displayName=schema)
    if not schema_obj:
        mso.fail_json(
            msg="Provided schema '{0}' does not exist".format(schema))

    schema_path = 'schemas/{id}'.format(**schema_obj)
    schema_id = schema_obj['id']

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    sites = [(s['siteId'], s['templateName']) for s in schema_obj['sites']]
    if (site_id, template) not in sites:
        mso.fail_json(
            msg=
            "Provided site/template '{0}-{1}' does not exist. Existing sites/templates: {2}"
            .format(site, template, ', '.join(sites)))

    # Schema-access uses indexes
    site_idx = sites.index((site_id, template))
    # Path-based access uses site_id-template
    site_template = '{0}-{1}'.format(site_id, template)

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    vrfs = [v['vrfRef'] for v in schema_obj['sites'][site_idx]['vrfs']]
    if vrf_ref not in vrfs:
        mso.fail_json(
            msg="Provided vrf '{0}' does not exist. Existing vrfs: {1}".format(
                vrf, ', '.join(vrfs)))
    vrf_idx = vrfs.index(vrf_ref)

    # Get Region
    regions = [
        r['name']
        for r in schema_obj['sites'][site_idx]['vrfs'][vrf_idx]['regions']
    ]
    if region not in regions:
        mso.fail_json(
            msg="Provided region '{0}' does not exist. Existing regions: {1}".
            format(region, ', '.join(regions)))
    region_idx = regions.index(region)

    # Get CIDR
    cidrs = [
        c['ip'] for c in schema_obj['sites'][site_idx]['vrfs'][vrf_idx]
        ['regions'][region_idx]['cidrs']
    ]
    if cidr not in cidrs:
        mso.fail_json(
            msg="Provided CIDR IP '{0}' does not exist. Existing CIDR IPs: {1}"
            .format(cidr, ', '.join(cidrs)))
    cidr_idx = cidrs.index(cidr)

    # Get Subnet
    subnets = [
        s['ip'] for s in schema_obj['sites'][site_idx]['vrfs'][vrf_idx]
        ['regions'][region_idx]['cidrs'][cidr_idx]['subnets']
    ]
    if subnet is not None and subnet in subnets:
        subnet_idx = subnets.index(subnet)
        # FIXME: Changes based on index are DANGEROUS
        subnet_path = '/sites/{0}/vrfs/{1}/regions/{2}/cidrs/{3}/subnets/{4}'.format(
            site_template, vrf, region, cidr_idx, subnet_idx)
        mso.existing = schema_obj['sites'][site_idx]['vrfs'][vrf_idx][
            'regions'][region_idx]['cidrs'][cidr_idx]['subnets'][subnet_idx]

    if state == 'query':
        if subnet is None:
            mso.existing = schema_obj['sites'][site_idx]['vrfs'][vrf_idx][
                'regions'][region_idx]['cidrs'][cidr_idx]['subnets']
        elif not mso.existing:
            mso.fail_json(msg="Subnet IP '{subnet}' not found".format(
                subnet=subnet))
        mso.exit_json()

    subnets_path = '/sites/{0}/vrfs/{1}/regions/{2}/cidrs/{3}/subnets'.format(
        site_template, vrf, region, cidr_idx)
    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(dict(op='remove', path=subnet_path))

    elif state == 'present':

        payload = dict(
            ip=subnet,
            zone=zone,
        )

        mso.sanitize(payload, collate=True)

        if mso.existing:
            ops.append(dict(op='replace', path=subnet_path, value=mso.sent))
        else:
            ops.append(dict(op='add', path=subnets_path + '/-',
                            value=mso.sent))

        mso.existing = mso.proposed

    if not module.check_mode:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()
def main():
    argument_spec = mso_argument_spec()
    argument_spec.update(
        schema=dict(type='str', required=True),
        site=dict(type='str', required=True),
        template=dict(type='str', required=True),
        vrf=dict(type='str', required=True),
        region=dict(type='str', aliases=[
            'name'
        ]),  # This parameter is not required for querying all objects
        state=dict(type='str',
                   default='present',
                   choices=['absent', 'present', 'query']),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[
            ['state', 'absent', ['region']],
            ['state', 'present', ['region']],
        ],
    )

    schema = module.params['schema']
    site = module.params['site']
    template = module.params['template']
    vrf = module.params['vrf']
    region = module.params['region']
    state = module.params['state']

    mso = MSOModule(module)

    # Get schema_id
    schema_obj = mso.get_obj('schemas', displayName=schema)
    if not schema_obj:
        mso.fail_json(
            msg="Provided schema '{0}' does not exist".format(schema))

    schema_path = 'schemas/{id}'.format(**schema_obj)
    schema_id = schema_obj['id']

    # Get site
    site_id = mso.lookup_site(site)

    # Get site_idx
    sites = [(s['siteId'], s['templateName']) for s in schema_obj['sites']]
    if (site_id, template) not in sites:
        mso.fail_json(
            msg=
            "Provided site/template '{0}-{1}' does not exist. Existing sites/templates: {2}"
            .format(site, template, ', '.join(sites)))

    # Schema-access uses indexes
    site_idx = sites.index((site_id, template))
    # Path-based access uses site_id-template
    site_template = '{0}-{1}'.format(site_id, template)

    # Get VRF
    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
    vrfs = [v['vrfRef'] for v in schema_obj['sites'][site_idx]['vrfs']]
    if vrf_ref not in vrfs:
        mso.fail_json(
            msg="Provided vrf '{0}' does not exist. Existing vrfs: {1}".format(
                vrf, ', '.join(vrfs)))
    vrf_idx = vrfs.index(vrf_ref)

    # Get Region
    regions = [
        r['name']
        for r in schema_obj['sites'][site_idx]['vrfs'][vrf_idx]['regions']
    ]
    if region is not None and region in regions:
        region_idx = regions.index(region)
        region_path = '/sites/{0}/vrfs/{1}/regions/{2}'.format(
            site_template, vrf, region)
        mso.existing = schema_obj['sites'][site_idx]['vrfs'][vrf_idx][
            'regions'][region_idx]

    if state == 'query':
        if region is None:
            mso.existing = schema_obj['sites'][site_idx]['vrfs'][vrf_idx][
                'regions']
        elif not mso.existing:
            mso.fail_json(msg="Region '{region}' not found".format(
                region=region))
        mso.exit_json()

    regions_path = '/sites/{0}/vrfs/{1}/regions'.format(site_template, vrf)
    ops = []

    mso.previous = mso.existing
    if state == 'absent':
        if mso.existing:
            mso.sent = mso.existing = {}
            ops.append(dict(op='remove', path=region_path))

    elif state == 'present':

        payload = dict(name=region, )

        mso.sanitize(payload, collate=True)

        if mso.existing:
            ops.append(dict(op='replace', path=region_path, value=mso.sent))
        else:
            ops.append(dict(op='add', path=regions_path + '/-',
                            value=mso.sent))

        mso.existing = mso.proposed

    if not module.check_mode:
        mso.request(schema_path, method='PATCH', data=ops)

    mso.exit_json()