text: #!/usr/bin/python
  # -*- coding: utf-8 -*-
  
  # Copyright: (c) 2018, Kevin Breit (@kbreit) <kevin.breit@kevinbreit.net>
  # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
  
  from __future__ import absolute_import, division, print_function
  __metaclass__ = type
  
  ANSIBLE_METADATA = {
      'metadata_version': '1.1',
      'status': ['preview'],
      'supported_by': 'community'
  }
  
  DOCUMENTATION = r'''
  ---
  module: meraki_mx_site_to_site_vpn
  short_description: Manage AutoVPN connections in Meraki
  version_added: "1.1.0"
  description:
  - Allows for creation, management, and visibility into AutoVPNs implemented on Meraki MX firewalls.
  options:
      state:
          description:
          - Create or modify an organization.
          choices: ['present', 'query']
          default: present
          type: str
      net_name:
          description:
          - Name of network which MX firewall is in.
          type: str
      net_id:
          description:
          - ID of network which MX firewall is in.
          type: str
      mode:
          description:
          - Set VPN mode for network
          choices: ['none', 'hub', 'spoke']
          type: str
      hubs:
          description:
          - List of hubs to assign to a spoke.
          type: list
          elements: dict
          suboptions:
              hub_id:
                  description:
                  - Network ID of hub
                  type: str
              use_default_route:
                  description:
                  - Indicates whether deafult troute traffic should be sent to this hub.
                  - Only valid in spoke mode.
                  type: bool
      subnets:
          description:
          - List of subnets to advertise over VPN.
          type: list
          elements: dict
          suboptions:
              local_subnet:
                  description:
                  - CIDR formatted subnet.
                  type: str
              use_vpn:
                  description:
                  - Whether to advertise over VPN.
                  type: bool
  author:
  - Kevin Breit (@kbreit)
  extends_documentation_fragment: cisco.meraki.meraki
  '''
  
  EXAMPLES = r'''
  - name: Set hub mode
    meraki_site_to_site_vpn:
      auth_key: abc123
      state: present
      org_name: YourOrg
      net_name: hub_network
      mode: hub
    delegate_to: localhost
    register: set_hub
  
  - name: Set spoke mode
    meraki_site_to_site_vpn:
      auth_key: abc123
      state: present
      org_name: YourOrg
      net_name: spoke_network
      mode: spoke
      hubs:
        - hub_id: N_1234
          use_default_route: false
    delegate_to: localhost
    register: set_spoke
  
  - name: Query rules for hub
    meraki_site_to_site_vpn:
      auth_key: abc123
      state: query
      org_name: YourOrg
      net_name: hub_network
    delegate_to: localhost
    register: query_all_hub
  '''
  
  RETURN = r'''
  data:
      description: VPN settings.
      returned: success
      type: complex
      contains:
          mode:
              description: Mode assigned to network.
              returned: always
              type: str
              sample: spoke
          hubs:
              description: Hub networks to associate to.
              returned: always
              type: complex
              contains:
                  hub_id:
                      description: ID of hub network.
                      returned: always
                      type: complex
                      sample: N_12345
                  use_default_route:
                      description: Whether to send all default route traffic over VPN.
                      returned: always
                      type: bool
                      sample: true
          subnets:
              description: List of subnets to advertise over VPN.
              returned: always
              type: complex
              contains:
                  local_subnet:
                      description: CIDR formatted subnet.
                      returned: always
                      type: str
                      sample: 192.168.1.0/24
                  use_vpn:
                      description: Whether subnet should use the VPN.
                      returned: always
                      type: bool
                      sample: true
  '''
  
  from ansible.module_utils.basic import AnsibleModule, json
  from ansible_collections.cisco.meraki.plugins.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec
  from copy import deepcopy
  
  
  def assemble_payload(meraki):
      payload = {'mode': meraki.params['mode']}
      if meraki.params['hubs'] is not None:
          payload['hubs'] = meraki.params['hubs']
          for hub in payload['hubs']:
              hub['hubId'] = hub.pop('hub_id')
              hub['useDefaultRoute'] = hub.pop('use_default_route')
      if meraki.params['subnets'] is not None:
          payload['subnets'] = meraki.params['subnets']
          for subnet in payload['subnets']:
              subnet['localSubnet'] = subnet.pop('local_subnet')
              subnet['useVpn'] = subnet.pop('use_vpn')
      return payload
  
  
  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)
  
  
  if __name__ == '__main__':
      main()
  