1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3
4# Copyright: (c) 2019, Dag Wieers (@dagwieers) <dag@wieers.com>
5# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import absolute_import, division, print_function
8__metaclass__ = type
9
10ANSIBLE_METADATA = {'metadata_version': '1.1',
11                    'status': ['preview'],
12                    'supported_by': 'community'}
13
14DOCUMENTATION = r'''
15---
16module: mso_schema_site_vrf
17short_description: Manage site-local VRFs in schema template
18description:
19- Manage site-local VRFs in schema template on Cisco ACI Multi-Site.
20author:
21- Dag Wieers (@dagwieers)
22options:
23  schema:
24    description:
25    - The name of the schema.
26    type: str
27    required: yes
28  site:
29    description:
30    - The name of the site.
31    type: str
32    required: yes
33  template:
34    description:
35    - The name of the template.
36    type: str
37    required: yes
38  vrf:
39    description:
40    - The name of the VRF to manage.
41    type: str
42    aliases: [ name ]
43  state:
44    description:
45    - Use C(present) or C(absent) for adding or removing.
46    - Use C(query) for listing an object or multiple objects.
47    type: str
48    choices: [ absent, present, query ]
49    default: present
50seealso:
51- module: cisco.mso.mso_schema_site
52- module: cisco.mso.mso_schema_template_vrf
53extends_documentation_fragment: cisco.mso.modules
54'''
55
56EXAMPLES = r'''
57- name: Add a new site VRF
58  cisco.mso.mso_schema_site_vrf:
59    host: mso_host
60    username: admin
61    password: SomeSecretPassword
62    schema: Schema1
63    site: Site1
64    template: Template1
65    vrf: VRF1
66    state: present
67  delegate_to: localhost
68
69- name: Remove a site VRF
70  cisco.mso.mso_schema_site_vrf:
71    host: mso_host
72    username: admin
73    password: SomeSecretPassword
74    schema: Schema1
75    site: Site1
76    template: Template1
77    vrf: VRF1
78    state: absent
79  delegate_to: localhost
80
81- name: Query a specific site VRF
82  cisco.mso.mso_schema_site_vrf:
83    host: mso_host
84    username: admin
85    password: SomeSecretPassword
86    schema: Schema1
87    site: Site1
88    template: Template1
89    vrf: VRF1
90    state: query
91  delegate_to: localhost
92  register: query_result
93
94- name: Query all site VRFs
95  cisco.mso.mso_schema_site_vrf:
96    host: mso_host
97    username: admin
98    password: SomeSecretPassword
99    schema: Schema1
100    site: Site1
101    template: Template1
102    state: query
103  delegate_to: localhost
104  register: query_result
105'''
106
107RETURN = r'''
108'''
109
110from ansible.module_utils.basic import AnsibleModule
111from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec
112
113
114def main():
115    argument_spec = mso_argument_spec()
116    argument_spec.update(
117        schema=dict(type='str', required=True),
118        site=dict(type='str', required=True),
119        template=dict(type='str', required=True),
120        vrf=dict(type='str', aliases=['name']),  # This parameter is not required for querying all objects
121        state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
122    )
123
124    module = AnsibleModule(
125        argument_spec=argument_spec,
126        supports_check_mode=True,
127        required_if=[
128            ['state', 'absent', ['vrf']],
129            ['state', 'present', ['vrf']],
130        ],
131    )
132
133    schema = module.params.get('schema')
134    site = module.params.get('site')
135    template = module.params.get('template').replace(' ', '')
136    vrf = module.params.get('vrf')
137    state = module.params.get('state')
138
139    mso = MSOModule(module)
140
141    # Get schema objects
142    schema_id, schema_path, schema_obj = mso.query_schema(schema)
143
144    # Get site
145    site_id = mso.lookup_site(site)
146
147    # Get site_idx
148    if 'sites' not in schema_obj:
149        mso.fail_json(msg="No site associated with template '{0}'. Associate the site with the template using mso_schema_site.".format(template))
150    sites = [(s.get('siteId'), s.get('templateName')) for s in schema_obj.get('sites')]
151    if (site_id, template) not in sites:
152        mso.fail_json(msg="Provided site/template '{0}-{1}' does not exist. Existing sites/templates: {2}".format(site, template, ', '.join(sites)))
153
154    # Schema-access uses indexes
155    site_idx = sites.index((site_id, template))
156    # Path-based access uses site_id-template
157    site_template = '{0}-{1}'.format(site_id, template)
158
159    # Get VRF
160    vrf_ref = mso.vrf_ref(schema_id=schema_id, template=template, vrf=vrf)
161    vrfs = [v.get('vrfRef') for v in schema_obj.get('sites')[site_idx]['vrfs']]
162    if vrf is not None and vrf_ref in vrfs:
163        vrf_idx = vrfs.index(vrf_ref)
164        vrf_path = '/sites/{0}/vrfs/{1}'.format(site_template, vrf)
165        mso.existing = schema_obj.get('sites')[site_idx]['vrfs'][vrf_idx]
166
167    if state == 'query':
168        if vrf is None:
169            mso.existing = schema_obj.get('sites')[site_idx]['vrfs']
170        elif not mso.existing:
171            mso.fail_json(msg="VRF '{vrf}' not found".format(vrf=vrf))
172        mso.exit_json()
173
174    vrfs_path = '/sites/{0}/vrfs'.format(site_template)
175    ops = []
176
177    mso.previous = mso.existing
178    if state == 'absent':
179        if mso.existing:
180            mso.sent = mso.existing = {}
181            ops.append(dict(op='remove', path=vrf_path))
182
183    elif state == 'present':
184        payload = dict(
185            vrfRef=dict(
186                schemaId=schema_id,
187                templateName=template,
188                vrfName=vrf,
189            ),
190        )
191
192        mso.sanitize(payload, collate=True)
193
194        if mso.existing:
195            ops.append(dict(op='replace', path=vrf_path, value=mso.sent))
196        else:
197            ops.append(dict(op='add', path=vrfs_path + '/-', value=mso.sent))
198
199        mso.existing = mso.proposed
200
201    if not module.check_mode:
202        mso.request(schema_path, method='PATCH', data=ops)
203
204    mso.exit_json()
205
206
207if __name__ == "__main__":
208    main()
209