mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
MSO: Refactor modules to common structure (#51354)
This PR includes: - Various fixes to jsonpatch interface - Added seealso: and notes: to docs - Various improvements to docs - A set of bugfixes found during integration tests Full integration tests follow.
This commit is contained in:
parent
2c2a79f712
commit
73636175da
13 changed files with 207 additions and 265 deletions
|
@ -48,7 +48,7 @@ options:
|
|||
choices: [ absent, present, query ]
|
||||
default: present
|
||||
notes:
|
||||
- This module cannot create empty schemas (i.e. schemas without templates).
|
||||
- Due to restrictions of the MSO REST API this module cannot create empty schemas (i.e. schemas without templates).
|
||||
Use the M(mso_schema_template) to automatically create schemas with templates.
|
||||
seealso:
|
||||
- module: mso_schema_site
|
||||
|
|
|
@ -135,7 +135,6 @@ def main():
|
|||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
# Schema exists
|
||||
schema_id = schema_obj['id']
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get site
|
||||
|
@ -159,16 +158,16 @@ def main():
|
|||
mso.existing = []
|
||||
mso.exit_json()
|
||||
|
||||
sites_path = '/sites'
|
||||
site_path = '/sites/{0}'.format(site)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
mso.proposed = mso.sent = {}
|
||||
|
||||
if mso.existing:
|
||||
# Remove existing site
|
||||
mso.existing = {}
|
||||
ops.append(dict(op='remove', path='/sites/{0}'.format(site_idx)))
|
||||
mso.sent = mso.existing = {}
|
||||
ops.append(dict(op='remove', path=site_path))
|
||||
|
||||
elif state == 'present':
|
||||
if not mso.existing:
|
||||
|
@ -187,8 +186,9 @@ def main():
|
|||
|
||||
mso.sanitize(payload, collate=True)
|
||||
|
||||
mso.existing = mso.proposed = mso.sent
|
||||
ops.append(dict(op='add', path='/sites/-', value=mso.sent))
|
||||
ops.append(dict(op='add', path=sites_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
|
|
@ -21,6 +21,11 @@ author:
|
|||
- Dag Wieers (@dagwieers)
|
||||
version_added: '2.8'
|
||||
options:
|
||||
tenant:
|
||||
description:
|
||||
- The tenant used for this template.
|
||||
type: str
|
||||
required: yes
|
||||
schema:
|
||||
description:
|
||||
- The name of the schema.
|
||||
|
@ -31,10 +36,6 @@ options:
|
|||
- The name of the template.
|
||||
type: str
|
||||
aliases: [ name ]
|
||||
tenant:
|
||||
description:
|
||||
- The tenant used for this template.
|
||||
type: str
|
||||
display_name:
|
||||
description:
|
||||
- The name as displayed on the MSO web interface.
|
||||
|
@ -47,7 +48,7 @@ options:
|
|||
choices: [ absent, present, query ]
|
||||
default: present
|
||||
notes:
|
||||
- This module creates schemas when needed, and removes them when the last template has been removed.
|
||||
- Due to restrictions of the MSO REST API this module creates schemas when needed, and removes them when the last template has been removed.
|
||||
seealso:
|
||||
- module: mso_schema
|
||||
- module: mso_schema_site
|
||||
|
@ -137,30 +138,34 @@ def main():
|
|||
|
||||
# Get schema
|
||||
schema_obj = mso.get_obj('schemas', displayName=schema)
|
||||
|
||||
mso.existing = {}
|
||||
if schema_obj:
|
||||
# Schema exists
|
||||
path = 'schemas/{id}'.format(**schema_obj)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
if template is None:
|
||||
if template:
|
||||
if template in templates:
|
||||
template_idx = templates.index(template)
|
||||
mso.existing = schema_obj['templates'][template_idx]
|
||||
else:
|
||||
mso.existing = schema_obj['templates']
|
||||
elif template in templates:
|
||||
template_idx = templates.index(template)
|
||||
mso.existing = schema_obj['templates'][template_idx]
|
||||
else:
|
||||
mso.existing = {}
|
||||
else:
|
||||
path = 'schemas'
|
||||
|
||||
if template is None:
|
||||
mso.existing = []
|
||||
else:
|
||||
mso.existing = {}
|
||||
schema_path = 'schemas'
|
||||
|
||||
if state == 'query':
|
||||
if not mso.existing:
|
||||
if template:
|
||||
mso.fail_json(msg="Template '{0}' not found".format(template))
|
||||
else:
|
||||
mso.existing = []
|
||||
mso.exit_json()
|
||||
|
||||
template_path = '/templates/{0}'.format(template)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
mso.proposed = mso.sent = {}
|
||||
|
@ -172,15 +177,11 @@ def main():
|
|||
# There is only one tenant, remove schema
|
||||
mso.existing = {}
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='DELETE')
|
||||
mso.request(schema_path, method='DELETE')
|
||||
elif mso.existing:
|
||||
# Remove existing template
|
||||
mso.existing = {}
|
||||
operation = [
|
||||
dict(op='remove', path='/templates/{template}'.format(template=template)),
|
||||
]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=template_path))
|
||||
else:
|
||||
# There was no template to begin with
|
||||
pass
|
||||
|
@ -206,7 +207,7 @@ def main():
|
|||
mso.existing = payload['templates'][0]
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='POST', data=payload)
|
||||
mso.request(schema_path, method='POST', data=payload)
|
||||
|
||||
elif mso.existing:
|
||||
# Template exists, so we have to update it
|
||||
|
@ -218,14 +219,10 @@ def main():
|
|||
|
||||
mso.sanitize(payload, collate=True)
|
||||
|
||||
mso.existing = payload
|
||||
operations = [
|
||||
dict(op='replace', path='/templates/{template}/displayName'.format(template=template), value=display_name),
|
||||
dict(op='replace', path='/templates/{template}/tenantId'.format(template=template), value=tenant_id),
|
||||
]
|
||||
ops.append(dict(op='replace', path=template_path + '/displayName', value=display_name))
|
||||
ops.append(dict(op='replace', path=template_path + '/tenantId', value=tenant_id))
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operations)
|
||||
mso.existing = mso.proposed
|
||||
else:
|
||||
# Template does not exist, so we have to add it
|
||||
payload = dict(
|
||||
|
@ -234,13 +231,14 @@ def main():
|
|||
tenantId=tenant_id,
|
||||
)
|
||||
|
||||
mso.existing = payload
|
||||
operations = [
|
||||
dict(op='add', path='/templates/-', value=payload),
|
||||
]
|
||||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operations)
|
||||
ops.append(dict(op='add', path='/templates/-', value=payload))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
anp:
|
||||
description:
|
||||
- The name of the ANP to manage.
|
||||
|
@ -134,12 +135,10 @@ def main():
|
|||
|
||||
# Get schema_id
|
||||
schema_obj = mso.get_obj('schemas', displayName=schema)
|
||||
if schema_obj:
|
||||
schema_id = schema_obj['id']
|
||||
else:
|
||||
if not schema_obj:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -197,7 +196,7 @@ def main():
|
|||
mso.existing = mso.proposed
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=ops)
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,10 +30,12 @@ options:
|
|||
description:
|
||||
- The name of the template to change.
|
||||
type: list
|
||||
required: yes
|
||||
anp:
|
||||
description:
|
||||
- The name of the ANP.
|
||||
type: str
|
||||
required: yes
|
||||
epg:
|
||||
description:
|
||||
- The name of the EPG to manage.
|
||||
|
@ -231,7 +233,7 @@ def main():
|
|||
else:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -258,16 +260,15 @@ def main():
|
|||
mso.fail_json(msg="EPG '{epg}' not found".format(epg=epg))
|
||||
mso.exit_json()
|
||||
|
||||
epgs_path = '/templates/{0}/anps/{1}/epgs'.format(template, anp)
|
||||
epg_path = '/templates/{0}/anps/{1}/epgs/{2}'.format(template, anp, epg)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
path='/templates/{template}/anps/{anp}/epgs/{epg}'.format(template=template, anp=anp, epg=epg),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=epg_path))
|
||||
|
||||
elif state == 'present':
|
||||
bd_ref = mso.make_reference(bd, 'bd', schema_id, template)
|
||||
|
@ -292,21 +293,14 @@ def main():
|
|||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
path='/templates/{template}/anps/{anp}/epgs/{epg}'.format(template=template, anp=anp, epg=epg),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='replace', path=epg_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/anps/{anp}/epgs/-'.format(template=template, anp=anp),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=epgs_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,14 +30,17 @@ options:
|
|||
description:
|
||||
- The name of the template to change.
|
||||
type: list
|
||||
required: yes
|
||||
anp:
|
||||
description:
|
||||
- The name of the ANP.
|
||||
type: str
|
||||
required: yes
|
||||
epg:
|
||||
description:
|
||||
- The name of the EPG to manage.
|
||||
type: str
|
||||
required: yes
|
||||
ip:
|
||||
description:
|
||||
- The IP range in CIDR notation.
|
||||
|
@ -67,6 +70,8 @@ options:
|
|||
type: str
|
||||
choices: [ absent, present, query ]
|
||||
default: present
|
||||
notes:
|
||||
- Due to restrictions of the MSO REST API concurrent modifications to EPG subnets can be dangerous and corrupt data.
|
||||
extends_documentation_fragment: mso
|
||||
'''
|
||||
|
||||
|
@ -164,14 +169,12 @@ def main():
|
|||
|
||||
mso = MSOModule(module)
|
||||
|
||||
# Get schema_id
|
||||
# Get schema
|
||||
schema_obj = mso.get_obj('schemas', displayName=schema)
|
||||
if schema_obj:
|
||||
schema_id = schema_obj['id']
|
||||
else:
|
||||
if not schema_obj:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -196,7 +199,8 @@ def main():
|
|||
subnets = [s['ip'] for s in schema_obj['templates'][template_idx]['anps'][anp_idx]['epgs'][epg_idx]['subnets']]
|
||||
if ip in subnets:
|
||||
ip_idx = subnets.index(ip)
|
||||
# FIXME: Forced to use index here
|
||||
# FIXME: Changes based on index are DANGEROUS
|
||||
subnet_path = '/templates/{0}/anps/{1}/epgs/{2}/subnets/{3}'.format(template, anp, epg, ip_idx)
|
||||
mso.existing = schema_obj['templates'][template_idx]['anps'][anp_idx]['epgs'][epg_idx]['subnets'][ip_idx]
|
||||
|
||||
if state == 'query':
|
||||
|
@ -206,17 +210,14 @@ def main():
|
|||
mso.fail_json(msg="Subnet '{ip}' not found".format(ip=ip))
|
||||
mso.exit_json()
|
||||
|
||||
subnets_path = '/templates/{0}/anps/{1}/epgs/{2}/subnets'.format(template, anp, epg)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
# FIXME: Forced to use index here
|
||||
path='/templates/{template}/anps/{anp}/epgs/{epg}/subnets/{ip}'.format(template=template, anp=anp, epg=epg, ip=ip_idx),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
mso.existing = {}
|
||||
ops.append(dict(op='remove', path=subnet_path))
|
||||
|
||||
elif state == 'present':
|
||||
if description is None and not mso.existing:
|
||||
|
@ -239,22 +240,14 @@ def main():
|
|||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
# FIXME: Forced to use index here
|
||||
path='/templates/{template}/anps/{anp}/epgs/{epg}/subnets/{ip}'.format(template=template, anp=anp, epg=epg, ip=ip_idx),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='replace', path=subnet_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/anps/{anp}/epgs/{epg}/subnets/-'.format(template=template, anp=anp, epg=epg),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=subnets_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
bd:
|
||||
description:
|
||||
- The name of the BD to manage.
|
||||
|
@ -41,11 +42,11 @@ options:
|
|||
type: str
|
||||
vrf:
|
||||
description:
|
||||
- The VRF associated to this ANP.
|
||||
- The VRF associated to this BD.
|
||||
type: str
|
||||
subnets:
|
||||
description:
|
||||
- The subnets associated to this ANP.
|
||||
- The subnets associated to this BD.
|
||||
type: list
|
||||
suboptions:
|
||||
ip:
|
||||
|
@ -203,7 +204,7 @@ def main():
|
|||
else:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -225,16 +226,15 @@ def main():
|
|||
mso.fail_json(msg="BD '{bd}' not found".format(bd=bd))
|
||||
mso.exit_json()
|
||||
|
||||
bds_path = '/templates/{0}/bds'.format(template)
|
||||
bd_path = '/templates/{0}/bds/{1}'.format(template, bd)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
path='/templates/{template}/bds/{bd}'.format(template=template, bd=bd),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=bd_path))
|
||||
|
||||
elif state == 'present':
|
||||
vrf_ref = mso.make_reference(vrf, 'vrf', schema_id, template)
|
||||
|
@ -242,6 +242,8 @@ def main():
|
|||
|
||||
if display_name is None and not mso.existing:
|
||||
display_name = bd
|
||||
if subnets is None and not mso.existing:
|
||||
subnets = []
|
||||
|
||||
payload = dict(
|
||||
name=bd,
|
||||
|
@ -255,25 +257,17 @@ def main():
|
|||
vrfRef=vrf_ref,
|
||||
)
|
||||
|
||||
mso.sanitize(payload, collate=True, unwanted=['bdRef', 'vrfRef'])
|
||||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
path='/templates/{template}/bds/{bd}'.format(template=template, bd=bd),
|
||||
value=mso.sent,
|
||||
)]
|
||||
|
||||
ops.append(dict(op='replace', path=bd_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/bds/-'.format(template=template),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=bds_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,10 +30,12 @@ options:
|
|||
description:
|
||||
- The name of the template to change.
|
||||
type: list
|
||||
required: yes
|
||||
bd:
|
||||
description:
|
||||
- The name of the BD to manage.
|
||||
type: str
|
||||
required: yes
|
||||
ip:
|
||||
description:
|
||||
- The IP range in CIDR notation.
|
||||
|
@ -63,6 +65,8 @@ options:
|
|||
type: str
|
||||
choices: [ absent, present, query ]
|
||||
default: present
|
||||
notes:
|
||||
- Due to restrictions of the MSO REST API concurrent modifications to BD subnets can be dangerous and corrupt data.
|
||||
extends_documentation_fragment: mso
|
||||
'''
|
||||
|
||||
|
@ -155,14 +159,12 @@ def main():
|
|||
|
||||
mso = MSOModule(module)
|
||||
|
||||
# Get schema_id
|
||||
# Get schema
|
||||
schema_obj = mso.get_obj('schemas', displayName=schema)
|
||||
if schema_obj:
|
||||
schema_id = schema_obj['id']
|
||||
else:
|
||||
if not schema_obj:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -180,7 +182,8 @@ def main():
|
|||
subnets = [s['ip'] for s in schema_obj['templates'][template_idx]['bds'][bd_idx]['subnets']]
|
||||
if ip in subnets:
|
||||
ip_idx = subnets.index(ip)
|
||||
# FIXME: Forced to use index here
|
||||
# FIXME: Changes based on index are DANGEROUS
|
||||
subnet_path = '/templates/{0}/bds/{1}/subnets/{2}'.format(template, bd, ip_idx)
|
||||
mso.existing = schema_obj['templates'][template_idx]['bds'][bd_idx]['subnets'][ip_idx]
|
||||
|
||||
if state == 'query':
|
||||
|
@ -190,17 +193,14 @@ def main():
|
|||
mso.fail_json(msg="Subnet '{ip}' not found".format(ip=ip))
|
||||
mso.exit_json()
|
||||
|
||||
subnets_path = '/templates/{0}/bds/{1}/subnets'.format(template, bd)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
# FIXME: Forced to use index here
|
||||
path='/templates/{template}/bds/{bd}/subnets/{ip}'.format(template=template, bd=bd, ip=ip_idx),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=subnet_path))
|
||||
|
||||
elif state == 'present':
|
||||
if description is None and not mso.existing:
|
||||
|
@ -223,22 +223,14 @@ def main():
|
|||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
# FIXME: Forced to use index here
|
||||
path='/templates/{template}/bds/{bd}/subnets/{ip}'.format(template=template, bd=bd, ip=ip_idx),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='replace', path=subnet_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/bds/{bd}/subnets/-'.format(template=template, bd=bd),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=subnets_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,10 +30,12 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
contract:
|
||||
description:
|
||||
- The name of the contract to manage.
|
||||
type: str
|
||||
required: yes
|
||||
contract_display_name:
|
||||
description:
|
||||
- The name as displayed on the MSO web interface.
|
||||
|
@ -78,6 +80,11 @@ options:
|
|||
type: str
|
||||
choices: [ absent, present, query ]
|
||||
default: present
|
||||
seealso:
|
||||
- module: mso_schema_template_filter_entry
|
||||
notes:
|
||||
- Due to restrictions of the MSO REST API this module creates contracts when needed, and removes them when the last filter has been removed.
|
||||
- Due to restrictions of the MSO REST API concurrent modifications to contract filters can be dangerous and corrupt data.
|
||||
extends_documentation_fragment: mso
|
||||
'''
|
||||
|
||||
|
@ -209,7 +216,7 @@ def main():
|
|||
else:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -230,6 +237,8 @@ def main():
|
|||
filter_ref = mso.filter_ref(filter_schema_id, filter_template, filter_name)
|
||||
if filter_ref in filters:
|
||||
filter_idx = filters.index(filter_ref)
|
||||
# FIXME: Changes based on index are DANGEROUS
|
||||
filter_path = '/templates/{0}/contracts/{1}/{2}/{3}'.format(template, contract, filter_key, filter_idx)
|
||||
mso.existing = schema_obj['templates'][template_idx]['contracts'][contract_idx][filter_key][filter_idx]
|
||||
|
||||
if state == 'query':
|
||||
|
@ -244,8 +253,7 @@ def main():
|
|||
|
||||
ops = []
|
||||
contract_path = '/templates/{0}/contracts/{1}'.format(template, contract)
|
||||
# FIXME: Removing based on index is DANGEROUS
|
||||
filter_path = '/templates/{0}/contracts/{1}/{2}/{3}'.format(template, contract, filter_key, filter_idx)
|
||||
filters_path = '/templates/{0}/contracts/{1}/{2}'.format(template, contract, filter_key)
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
|
@ -266,9 +274,6 @@ def main():
|
|||
mso.existing = {}
|
||||
ops.append(dict(op='remove', path=filter_path))
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=ops)
|
||||
|
||||
elif state == 'present':
|
||||
|
||||
payload = dict(
|
||||
|
@ -282,11 +287,6 @@ def main():
|
|||
|
||||
mso.sanitize(payload, collate=True)
|
||||
mso.existing = mso.sent
|
||||
ops = []
|
||||
contract_path = '/templates/{0}/contracts/{1}'.format(template, contract)
|
||||
filters_path = '/templates/{0}/contracts/{1}/{2}'.format(template, contract, filter_key)
|
||||
# FIXME: Updating based on index is DANGEROUS
|
||||
filter_path = '/templates/{0}/contracts/{1}/{2}/{3}'.format(template, contract, filter_key, filter_idx)
|
||||
|
||||
if contract_idx is None:
|
||||
# COntract does not exist, so we have to create it
|
||||
|
@ -322,8 +322,8 @@ def main():
|
|||
# Filter exists, we have to update it
|
||||
ops.append(dict(op='replace', path=filter_path, value=mso.sent))
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=ops)
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
externalepg:
|
||||
description:
|
||||
- The name of the external EPG to manage.
|
||||
|
@ -143,7 +144,7 @@ def main():
|
|||
else:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -165,16 +166,15 @@ def main():
|
|||
mso.fail_json(msg="External EPG '{externalepg}' not found".format(externalepg=externalepg))
|
||||
mso.exit_json()
|
||||
|
||||
eepgs_path = '/templates/{0}/externalEpgs'.format(template)
|
||||
eepg_path = '/templates/{0}/externalEpgs/{1}'.format(template, externalepg)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
path='/templates/{template}/externalEpgs/{externalepg}'.format(template=template, externalepg=externalepg),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=eepg_path))
|
||||
|
||||
elif state == 'present':
|
||||
vrf_ref = mso.make_reference(vrf, 'vrf', schema_id, template)
|
||||
|
@ -194,22 +194,14 @@ def main():
|
|||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
path='/templates/{template}/externalEpgs/{externalepg}'.format(template=template, externalepg=externalepg),
|
||||
value=mso.sent,
|
||||
)]
|
||||
|
||||
ops.append(dict(op='replace', path=eepg_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/externalEpgs/-'.format(template=template),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=eepgs_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,10 +30,12 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
filter:
|
||||
description:
|
||||
- The name of the filter to manage.
|
||||
type: str
|
||||
required: yes
|
||||
filter_display_name:
|
||||
description:
|
||||
- The name as displayed on the MSO web interface.
|
||||
|
@ -106,6 +108,10 @@ options:
|
|||
type: str
|
||||
choices: [ absent, present, query ]
|
||||
default: present
|
||||
seealso:
|
||||
- module: mso_schema_template_contract_filter
|
||||
notes:
|
||||
- Due to restrictions of the MSO REST API this module creates filters when needed, and removes them when the last entry has been removed.
|
||||
extends_documentation_fragment: mso
|
||||
'''
|
||||
|
||||
|
@ -168,9 +174,9 @@ def main():
|
|||
argument_spec.update(
|
||||
schema=dict(type='str', required=True),
|
||||
template=dict(type='str', required=True),
|
||||
filter=dict(type='str', required=True), # This parameter is not required for querying all objects
|
||||
filter=dict(type='str', required=True),
|
||||
filter_display_name=dict(type='str', aliases=['filter_display_name']),
|
||||
entry=dict(type='str', required=True, aliases=['name']),
|
||||
entry=dict(type='str', required=False, aliases=['name']), # This parameter is not required for querying all objects
|
||||
description=dict(type='str', aliases=['entry_description']),
|
||||
display_name=dict(type='str', aliases=['entry_display_name']),
|
||||
ethertype=dict(type='str', choices=['arp', 'fcoe', 'ip', 'ipv4', 'ipv6', 'mac-security', 'mpls-unicast', 'trill', 'unspecified']),
|
||||
|
@ -216,14 +222,12 @@ def main():
|
|||
|
||||
mso = MSOModule(module)
|
||||
|
||||
# Get schema_id
|
||||
# Get schema
|
||||
schema_obj = mso.get_obj('schemas', displayName=schema)
|
||||
if schema_obj:
|
||||
schema_id = schema_obj['id']
|
||||
else:
|
||||
if not schema_obj:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -247,11 +251,19 @@ def main():
|
|||
|
||||
if state == 'query':
|
||||
if entry is None:
|
||||
if filter_idx is None:
|
||||
mso.fail_json(msg="Filter '{filter}' not found".format(filter=filter_name))
|
||||
mso.existing = schema_obj['templates'][template_idx]['filters'][filter_idx]['entries']
|
||||
elif not mso.existing:
|
||||
mso.fail_json(msg="Entry '{entry}' not found".format(entry=entry))
|
||||
mso.exit_json()
|
||||
|
||||
filters_path = '/templates/{0}/filters'.format(template)
|
||||
filter_path = '/templates/{0}/filters/{1}'.format(template, filter_name)
|
||||
entries_path = '/templates/{0}/filters/{1}/entries'.format(template, filter_name)
|
||||
entry_path = '/templates/{0}/filters/{1}/entries/{2}'.format(template, filter_name, entry)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
mso.proposed = mso.sent = {}
|
||||
|
@ -265,18 +277,11 @@ def main():
|
|||
elif len(entries) == 1:
|
||||
# There is only one entry, remove filter
|
||||
mso.existing = {}
|
||||
operations = [
|
||||
dict(op='remove', path='/templates/{template}/filters/{filter}'.format(template=template, filter=filter_name)),
|
||||
]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operations)
|
||||
ops.append(dict(op='remove', path=filter_path))
|
||||
|
||||
else:
|
||||
mso.existing = {}
|
||||
operations = [
|
||||
dict(op='remove', path='/templates/{template}/filters/{filter}/entries/{entry}'.format(template=template, filter=filter_name, entry=entry)),
|
||||
]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operations)
|
||||
ops.append(dict(op='remove', path=entry_path))
|
||||
|
||||
elif state == 'present':
|
||||
|
||||
|
@ -322,7 +327,6 @@ def main():
|
|||
)
|
||||
|
||||
mso.sanitize(payload, collate=True)
|
||||
mso.existing = mso.sent
|
||||
|
||||
if filter_idx is None:
|
||||
# Filter does not exist, so we have to create it
|
||||
|
@ -335,37 +339,31 @@ def main():
|
|||
entries=[mso.sent],
|
||||
)
|
||||
|
||||
operations = [
|
||||
dict(op='add', path='/templates/{template}/filters/-'.format(template=template), value=payload),
|
||||
]
|
||||
ops.append(dict(op='add', path=filters_path + '/-', value=payload))
|
||||
|
||||
elif entry_idx is None:
|
||||
# Entry does not exist, so we have to add it
|
||||
operations = [
|
||||
dict(op='add', path='/templates/{template}/filters/{filter}/entries/-'.format(template=template, filter=filter_name), value=mso.sent)
|
||||
]
|
||||
ops.append(dict(op='add', path=entries_path + '/-', value=mso.sent))
|
||||
|
||||
else:
|
||||
# Entry exists, we have to update it
|
||||
alias = '/templates/{template}/filters/{filter}/entries/{entry}'.format(template=template, filter=filter_name, entry=entry)
|
||||
operations = [
|
||||
dict(op='replace', path='{alias}/name'.format(alias=alias), value=entry),
|
||||
dict(op='replace', path='{alias}/displayName'.format(alias=alias), value=display_name),
|
||||
dict(op='replace', path='{alias}/description'.format(alias=alias), value=description),
|
||||
dict(op='replace', path='{alias}/etherType'.format(alias=alias), value=ethertype),
|
||||
dict(op='replace', path='{alias}/ipProtocol'.format(alias=alias), value=ip_protocol),
|
||||
dict(op='replace', path='{alias}/tcpSessionRules'.format(alias=alias), value=tcp_session_rules),
|
||||
dict(op='replace', path='{alias}/sourceFrom'.format(alias=alias), value=source_from),
|
||||
dict(op='replace', path='{alias}/sourceTo'.format(alias=alias), value=source_to),
|
||||
dict(op='replace', path='{alias}/destinationFrom'.format(alias=alias), value=destination_from),
|
||||
dict(op='replace', path='{alias}/destinationTo'.format(alias=alias), value=destination_to),
|
||||
dict(op='replace', path='{alias}/arpFlag'.format(alias=alias), value=arp_flag),
|
||||
dict(op='replace', path='{alias}/stateful'.format(alias=alias), value=stateful),
|
||||
dict(op='replace', path='{alias}/matchOnlyFragments'.format(alias=alias), value=fragments_only),
|
||||
]
|
||||
ops.append(dict(op='replace', path=entry_path + '/displayName', value=display_name))
|
||||
ops.append(dict(op='replace', path=entry_path + '/description', value=description))
|
||||
ops.append(dict(op='replace', path=entry_path + '/etherType', value=ethertype))
|
||||
ops.append(dict(op='replace', path=entry_path + '/ipProtocol', value=ip_protocol))
|
||||
ops.append(dict(op='replace', path=entry_path + '/tcpSessionRules', value=tcp_session_rules))
|
||||
ops.append(dict(op='replace', path=entry_path + '/sourceFrom', value=source_from))
|
||||
ops.append(dict(op='replace', path=entry_path + '/sourceTo', value=source_to))
|
||||
ops.append(dict(op='replace', path=entry_path + '/destinationFrom', value=destination_from))
|
||||
ops.append(dict(op='replace', path=entry_path + '/destinationTo', value=destination_to))
|
||||
ops.append(dict(op='replace', path=entry_path + '/arpFlag', value=arp_flag))
|
||||
ops.append(dict(op='replace', path=entry_path + '/stateful', value=stateful))
|
||||
ops.append(dict(op='replace', path=entry_path + '/matchOnlyFragments', value=fragments_only))
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operations)
|
||||
mso.existing = mso.proposed
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
l3out:
|
||||
description:
|
||||
- The name of the l3out to manage.
|
||||
|
@ -41,7 +42,7 @@ options:
|
|||
type: str
|
||||
vrf:
|
||||
description:
|
||||
- The VRF associated to this ANP.
|
||||
- The VRF associated to this L3out.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
|
@ -143,7 +144,7 @@ def main():
|
|||
else:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -165,16 +166,15 @@ def main():
|
|||
mso.fail_json(msg="L3out '{l3out}' not found".format(l3out=l3out))
|
||||
mso.exit_json()
|
||||
|
||||
l3outs_path = '/templates/{0}/intersiteL3outs'.format(template)
|
||||
l3out_path = '/templates/{0}/intersiteL3outs/{1}'.format(template, l3out)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
path='/templates/{template}/intersiteL3outs/{l3out}'.format(template=template, l3out=l3out),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=l3out_path))
|
||||
|
||||
elif state == 'present':
|
||||
vrf_ref = mso.make_reference(vrf, 'vrf', schema_id, template)
|
||||
|
@ -191,22 +191,14 @@ def main():
|
|||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
path='/templates/{template}/intersiteL3outs/{l3out}'.format(template=template, l3out=l3out),
|
||||
value=mso.sent,
|
||||
)]
|
||||
|
||||
ops.append(dict(op='replace', path=l3out_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/intersiteL3outs/-'.format(template=template),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=l3outs_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ options:
|
|||
description:
|
||||
- The name of the template.
|
||||
type: list
|
||||
required: yes
|
||||
vrf:
|
||||
description:
|
||||
- The name of the VRF to manage.
|
||||
|
@ -138,12 +139,10 @@ def main():
|
|||
|
||||
# Get schema_id
|
||||
schema_obj = mso.get_obj('schemas', displayName=schema)
|
||||
if schema_obj:
|
||||
schema_id = schema_obj['id']
|
||||
else:
|
||||
if not schema_obj:
|
||||
mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
|
||||
|
||||
path = 'schemas/{id}'.format(id=schema_id)
|
||||
schema_path = 'schemas/{id}'.format(**schema_obj)
|
||||
|
||||
# Get template
|
||||
templates = [t['name'] for t in schema_obj['templates']]
|
||||
|
@ -165,16 +164,15 @@ def main():
|
|||
mso.fail_json(msg="VRF '{vrf}' not found".format(vrf=vrf))
|
||||
mso.exit_json()
|
||||
|
||||
vrfs_path = '/templates/{0}/vrfs'.format(template)
|
||||
vrf_path = '/templates/{0}/vrfs/{1}'.format(template, vrf)
|
||||
ops = []
|
||||
|
||||
mso.previous = mso.existing
|
||||
if state == 'absent':
|
||||
if mso.existing:
|
||||
mso.sent = mso.existing = {}
|
||||
operation = [dict(
|
||||
op='remove',
|
||||
path='/templates/{template}/vrfs/{vrf}'.format(template=template, vrf=vrf),
|
||||
)]
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
ops.append(dict(op='remove', path=vrf_path))
|
||||
|
||||
elif state == 'present':
|
||||
if display_name is None and not mso.existing:
|
||||
|
@ -191,22 +189,14 @@ def main():
|
|||
mso.sanitize(payload, collate=True)
|
||||
|
||||
if mso.existing:
|
||||
operation = [dict(
|
||||
op='replace',
|
||||
path='/templates/{template}/vrfs/{vrf}'.format(template=template, vrf=vrf),
|
||||
value=mso.sent,
|
||||
)]
|
||||
|
||||
ops.append(dict(op='replace', path=vrf_path, value=mso.sent))
|
||||
else:
|
||||
operation = [dict(
|
||||
op='add',
|
||||
path='/templates/{template}/vrfs/-'.format(template=template),
|
||||
value=mso.sent,
|
||||
)]
|
||||
ops.append(dict(op='add', path=vrfs_path + '/-', value=mso.sent))
|
||||
|
||||
mso.existing = mso.proposed
|
||||
if not module.check_mode:
|
||||
mso.request(path, method='PATCH', data=operation)
|
||||
|
||||
if not module.check_mode:
|
||||
mso.request(schema_path, method='PATCH', data=ops)
|
||||
|
||||
mso.exit_json()
|
||||
|
||||
|
|
Loading…
Reference in a new issue