From 8a3f3e41f8cf1dfa3bb5b922d5ee8202ef6e07f6 Mon Sep 17 00:00:00 2001 From: Ansible Core Team Date: Mon, 9 Mar 2020 09:40:34 +0000 Subject: [PATCH] Migrated to cisco.meraki --- .../module_utils/network/meraki/__init__.py | 0 .../module_utils/network/meraki/meraki.py | 461 ------------ .../modules/network/meraki/__init__.py | 0 .../modules/network/meraki/meraki_admin.py | 498 ------------- .../network/meraki/meraki_config_template.py | 331 --------- .../meraki/meraki_content_filtering.py | 248 ------- .../modules/network/meraki/meraki_device.py | 430 ----------- .../meraki/meraki_firewalled_services.py | 238 ------- .../modules/network/meraki/meraki_malware.py | 276 ------- .../network/meraki/meraki_mr_l3_firewall.py | 283 -------- .../network/meraki/meraki_mx_l3_firewall.py | 328 --------- .../network/meraki/meraki_mx_l7_firewall.py | 506 ------------- .../modules/network/meraki/meraki_nat.py | 673 ------------------ .../modules/network/meraki/meraki_network.py | 390 ---------- .../network/meraki/meraki_organization.py | 244 ------- .../modules/network/meraki/meraki_snmp.py | 401 ----------- .../modules/network/meraki/meraki_ssid.py | 606 ---------------- .../network/meraki/meraki_static_route.py | 375 ---------- .../network/meraki/meraki_switchport.py | 397 ----------- .../modules/network/meraki/meraki_syslog.py | 257 ------- .../modules/network/meraki/meraki_vlan.py | 446 ------------ .../modules/network/meraki/meraki_webhook.py | 342 --------- lib/ansible/plugins/doc_fragments/meraki.py | 78 -- .../targets/meraki_admin/tasks/main.yml | 384 ---------- .../targets/meraki_config_template/aliases | 1 - .../meraki_config_template/tasks/main.yml | 196 ----- .../targets/meraki_content_filtering/aliases | 1 - .../meraki_config_template/aliases | 1 - .../meraki_config_template/tasks/main.yml | 117 --- .../meraki_content_filtering/tasks/main.yml | 247 ------- .../integration/targets/meraki_device/aliases | 1 - .../targets/meraki_device/tasks/main.yml | 215 ------ .../meraki_firewalled_services/aliases | 1 - .../meraki_firewalled_services/tasks/main.yml | 7 - .../tasks/tests.yml | 196 ----- .../targets/meraki_malware/aliases | 1 - .../targets/meraki_malware/tasks/main.yml | 247 ------- .../targets/meraki_mr_l3_firewall/aliases | 1 - .../meraki_mr_l3_firewall/tasks/main.yml | 100 --- .../targets/meraki_mx_l3_firewall/aliases | 1 - .../meraki_mx_l3_firewall/tasks/main.yml | 203 ------ .../targets/meraki_mx_l7_firewall/aliases | 2 - .../meraki_mx_l7_firewall/tasks/main.yml | 7 - .../meraki_mx_l7_firewall/tasks/tests.yml | 494 ------------- .../targets/meraki_nat/tasks/main.yml | 7 - .../targets/meraki_nat/tasks/tests.yml | 363 ---------- .../targets/meraki_network/aliases | 1 - .../targets/meraki_network/tasks/main.yml | 402 ----------- .../targets/meraki_organization/aliases | 1 - .../meraki_organization/tasks/main.yml | 8 - .../meraki_organization/tasks/tests.yml | 127 ---- test/integration/targets/meraki_snmp/aliases | 1 - .../targets/meraki_snmp/tasks/main.yml | 306 -------- test/integration/targets/meraki_ssid/aliases | 1 - .../targets/meraki_ssid/tasks/main.yml | 408 ----------- .../targets/meraki_static_route/aliases | 1 - .../meraki_static_route/tasks/main.yml | 170 ----- .../targets/meraki_switchport/aliases | 1 - .../targets/meraki_switchport/tasks/main.yml | 297 -------- .../targets/meraki_syslog/tasks/main.yml | 169 ----- test/integration/targets/meraki_vlan/aliases | 1 - .../targets/meraki_vlan/tasks/main.yml | 412 ----------- .../targets/meraki_webhook/aliases | 1 - .../targets/meraki_webhook/tasks/main.yml | 7 - .../targets/meraki_webhook/tasks/tests.yml | 273 ------- test/sanity/ignore.txt | 40 -- .../network/meraki/fixtures/orgs.json | 6 - .../network/meraki/test_meraki.py | 160 ----- 68 files changed, 13394 deletions(-) delete mode 100644 lib/ansible/module_utils/network/meraki/__init__.py delete mode 100644 lib/ansible/module_utils/network/meraki/meraki.py delete mode 100644 lib/ansible/modules/network/meraki/__init__.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_admin.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_config_template.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_content_filtering.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_device.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_firewalled_services.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_malware.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_mr_l3_firewall.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_mx_l3_firewall.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_nat.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_network.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_organization.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_snmp.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_ssid.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_static_route.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_switchport.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_syslog.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_vlan.py delete mode 100644 lib/ansible/modules/network/meraki/meraki_webhook.py delete mode 100644 lib/ansible/plugins/doc_fragments/meraki.py delete mode 100644 test/integration/targets/meraki_admin/tasks/main.yml delete mode 100644 test/integration/targets/meraki_config_template/aliases delete mode 100644 test/integration/targets/meraki_config_template/tasks/main.yml delete mode 100644 test/integration/targets/meraki_content_filtering/aliases delete mode 100644 test/integration/targets/meraki_content_filtering/meraki_config_template/aliases delete mode 100644 test/integration/targets/meraki_content_filtering/meraki_config_template/tasks/main.yml delete mode 100644 test/integration/targets/meraki_content_filtering/tasks/main.yml delete mode 100644 test/integration/targets/meraki_device/aliases delete mode 100644 test/integration/targets/meraki_device/tasks/main.yml delete mode 100644 test/integration/targets/meraki_firewalled_services/aliases delete mode 100644 test/integration/targets/meraki_firewalled_services/tasks/main.yml delete mode 100644 test/integration/targets/meraki_firewalled_services/tasks/tests.yml delete mode 100644 test/integration/targets/meraki_malware/aliases delete mode 100644 test/integration/targets/meraki_malware/tasks/main.yml delete mode 100644 test/integration/targets/meraki_mr_l3_firewall/aliases delete mode 100644 test/integration/targets/meraki_mr_l3_firewall/tasks/main.yml delete mode 100644 test/integration/targets/meraki_mx_l3_firewall/aliases delete mode 100644 test/integration/targets/meraki_mx_l3_firewall/tasks/main.yml delete mode 100644 test/integration/targets/meraki_mx_l7_firewall/aliases delete mode 100644 test/integration/targets/meraki_mx_l7_firewall/tasks/main.yml delete mode 100644 test/integration/targets/meraki_mx_l7_firewall/tasks/tests.yml delete mode 100644 test/integration/targets/meraki_nat/tasks/main.yml delete mode 100644 test/integration/targets/meraki_nat/tasks/tests.yml delete mode 100644 test/integration/targets/meraki_network/aliases delete mode 100644 test/integration/targets/meraki_network/tasks/main.yml delete mode 100644 test/integration/targets/meraki_organization/aliases delete mode 100644 test/integration/targets/meraki_organization/tasks/main.yml delete mode 100644 test/integration/targets/meraki_organization/tasks/tests.yml delete mode 100644 test/integration/targets/meraki_snmp/aliases delete mode 100644 test/integration/targets/meraki_snmp/tasks/main.yml delete mode 100644 test/integration/targets/meraki_ssid/aliases delete mode 100644 test/integration/targets/meraki_ssid/tasks/main.yml delete mode 100644 test/integration/targets/meraki_static_route/aliases delete mode 100644 test/integration/targets/meraki_static_route/tasks/main.yml delete mode 100644 test/integration/targets/meraki_switchport/aliases delete mode 100644 test/integration/targets/meraki_switchport/tasks/main.yml delete mode 100644 test/integration/targets/meraki_syslog/tasks/main.yml delete mode 100644 test/integration/targets/meraki_vlan/aliases delete mode 100644 test/integration/targets/meraki_vlan/tasks/main.yml delete mode 100644 test/integration/targets/meraki_webhook/aliases delete mode 100644 test/integration/targets/meraki_webhook/tasks/main.yml delete mode 100644 test/integration/targets/meraki_webhook/tasks/tests.yml delete mode 100644 test/units/module_utils/network/meraki/fixtures/orgs.json delete mode 100644 test/units/module_utils/network/meraki/test_meraki.py diff --git a/lib/ansible/module_utils/network/meraki/__init__.py b/lib/ansible/module_utils/network/meraki/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ansible/module_utils/network/meraki/meraki.py b/lib/ansible/module_utils/network/meraki/meraki.py deleted file mode 100644 index 50567562c15..00000000000 --- a/lib/ansible/module_utils/network/meraki/meraki.py +++ /dev/null @@ -1,461 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Ansible, but is an independent component - -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. - -# Copyright: (c) 2018, Kevin Breit -# All rights reserved. - -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import time -import os -import re -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict -from ansible.module_utils.urls import fetch_url -from ansible.module_utils.six.moves.urllib.parse import urlencode -from ansible.module_utils._text import to_native, to_bytes, to_text - - -RATE_LIMIT_RETRY_MULTIPLIER = 3 -INTERNAL_ERROR_RETRY_MULTIPLIER = 3 - - -def meraki_argument_spec(): - return dict(auth_key=dict(type='str', no_log=True, fallback=(env_fallback, ['MERAKI_KEY']), required=True), - host=dict(type='str', default='api.meraki.com'), - use_proxy=dict(type='bool', default=False), - use_https=dict(type='bool', default=True), - validate_certs=dict(type='bool', default=True), - output_format=dict(type='str', choices=['camelcase', 'snakecase'], default='snakecase', fallback=(env_fallback, ['ANSIBLE_MERAKI_FORMAT'])), - output_level=dict(type='str', default='normal', choices=['normal', 'debug']), - timeout=dict(type='int', default=30), - org_name=dict(type='str', aliases=['organization']), - org_id=dict(type='str'), - rate_limit_retry_time=dict(type='int', default=165), - internal_error_retry_time=dict(type='int', default=60) - ) - - -class RateLimitException(Exception): - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - - -class InternalErrorException(Exception): - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - - -class HTTPError(Exception): - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - - -def _error_report(function): - def inner(self, *args, **kwargs): - while True: - try: - response = function(self, *args, **kwargs) - if self.status == 429: - raise RateLimitException( - "Rate limiter hit, retry {0}".format(self.retry)) - elif self.status == 500: - raise InternalErrorException( - "Internal server error 500, retry {0}".format(self.retry)) - elif self.status == 502: - raise InternalErrorException( - "Internal server error 502, retry {0}".format(self.retry)) - elif self.status >= 400: - raise HTTPError("HTTP error {0} - {1}".format(self.status, response)) - self.retry = 0 # Needs to reset in case of future retries - return response - except RateLimitException as e: - self.retry += 1 - if self.retry <= 10: - self.retry_time += self.retry * RATE_LIMIT_RETRY_MULTIPLIER - time.sleep(self.retry * RATE_LIMIT_RETRY_MULTIPLIER) - else: - self.retry_time += 30 - time.sleep(30) - if self.retry_time > self.params['rate_limit_retry_time']: - raise RateLimitException(e) - except InternalErrorException as e: - self.retry += 1 - if self.retry <= 10: - self.retry_time += self.retry * INTERNAL_ERROR_RETRY_MULTIPLIER - time.sleep(self.retry * INTERNAL_ERROR_RETRY_MULTIPLIER) - else: - self.retry_time += 9 - time.sleep(9) - if self.retry_time > self.params['internal_error_retry_time']: - raise InternalErrorException(e) - except HTTPError as e: - raise HTTPError(e) - return inner - - -class MerakiModule(object): - - def __init__(self, module, function=None): - self.module = module - self.params = module.params - self.result = dict(changed=False) - self.headers = dict() - self.function = function - self.orgs = None - self.nets = None - self.org_id = None - self.net_id = None - self.check_mode = module.check_mode - self.key_map = {} - self.request_attempts = 0 - - # normal output - self.existing = None - - # info output - self.config = dict() - self.original = None - self.proposed = dict() - self.merged = None - self.ignored_keys = ['id', 'organizationId'] - - # debug output - self.filter_string = '' - self.method = None - self.path = None - self.response = None - self.status = None - self.url = None - - # rate limiting statistics - self.retry = 0 - self.retry_time = 0 - - # If URLs need to be modified or added for specific purposes, use .update() on the url_catalog dictionary - self.get_urls = {'organizations': '/organizations', - 'network': '/organizations/{org_id}/networks', - 'admins': '/organizations/{org_id}/admins', - 'configTemplates': '/organizations/{org_id}/configTemplates', - 'samlymbols': '/organizations/{org_id}/samlRoles', - 'ssids': '/networks/{net_id}/ssids', - 'groupPolicies': '/networks/{net_id}/groupPolicies', - 'staticRoutes': '/networks/{net_id}/staticRoutes', - 'vlans': '/networks/{net_id}/vlans', - 'devices': '/networks/{net_id}/devices', - } - - # Used to retrieve only one item - self.get_one_urls = {'organizations': '/organizations/{org_id}', - 'network': '/networks/{net_id}', - } - - # Module should add URLs which are required by the module - self.url_catalog = {'get_all': self.get_urls, - 'get_one': self.get_one_urls, - 'create': None, - 'update': None, - 'delete': None, - 'misc': None, - } - - if self.module._debug or self.params['output_level'] == 'debug': - self.module.warn('Enable debug output because ANSIBLE_DEBUG was set or output_level is set to debug.') - - # TODO: This should be removed as org_name isn't always required - self.module.required_if = [('state', 'present', ['org_name']), - ('state', 'absent', ['org_name']), - ] - # self.module.mutually_exclusive = [('org_id', 'org_name'), - # ] - self.modifiable_methods = ['POST', 'PUT', 'DELETE'] - - self.headers = {'Content-Type': 'application/json', - 'X-Cisco-Meraki-API-Key': module.params['auth_key'], - } - - def define_protocol(self): - """Set protocol based on use_https parameters.""" - if self.params['use_https'] is True: - self.params['protocol'] = 'https' - else: - self.params['protocol'] = 'http' - - def sanitize_keys(self, data): - if isinstance(data, dict): - items = {} - for k, v in data.items(): - try: - new = {self.key_map[k]: data[k]} - items[self.key_map[k]] = self.sanitize_keys(data[k]) - except KeyError: - snake_k = re.sub('([a-z0-9])([A-Z])', r'\1_\2', k).lower() - new = {snake_k: data[k]} - items[snake_k] = self.sanitize_keys(data[k]) - return items - elif isinstance(data, list): - items = [] - for i in data: - items.append(self.sanitize_keys(i)) - return items - elif isinstance(data, int) or isinstance(data, str) or isinstance(data, float): - return data - - def is_update_required(self, original, proposed, optional_ignore=None): - ''' Compare two data-structures ''' - self.ignored_keys.append('net_id') - if optional_ignore is not None: - self.ignored_keys = self.ignored_keys + optional_ignore - - if isinstance(original, list): - if len(original) != len(proposed): - # self.fail_json(msg="Length of lists don't match") - return True - for a, b in zip(original, proposed): - if self.is_update_required(a, b): - # self.fail_json(msg="List doesn't match", a=a, b=b) - return True - elif isinstance(original, dict): - for k, v in proposed.items(): - if k not in self.ignored_keys: - if k in original: - if self.is_update_required(original[k], proposed[k]): - return True - else: - # self.fail_json(msg="Key not in original", k=k) - return True - else: - if original != proposed: - # self.fail_json(msg="Fallback", original=original, proposed=proposed) - return True - return False - - def get_orgs(self): - """Downloads all organizations for a user.""" - response = self.request('/organizations', method='GET') - if self.status != 200: - self.fail_json(msg='Organization lookup failed') - self.orgs = response - return self.orgs - - def is_org_valid(self, data, org_name=None, org_id=None): - """Checks whether a specific org exists and is duplicated. - - If 0, doesn't exist. 1, exists and not duplicated. >1 duplicated. - """ - org_count = 0 - if org_name is not None: - for o in data: - if o['name'] == org_name: - org_count += 1 - if org_id is not None: - for o in data: - if o['id'] == org_id: - org_count += 1 - return org_count - - def get_org_id(self, org_name): - """Returns an organization id based on organization name, only if unique. - - If org_id is specified as parameter, return that instead of a lookup. - """ - orgs = self.get_orgs() - # self.fail_json(msg='ogs', orgs=orgs) - if self.params['org_id'] is not None: - if self.is_org_valid(orgs, org_id=self.params['org_id']) is True: - return self.params['org_id'] - org_count = self.is_org_valid(orgs, org_name=org_name) - if org_count == 0: - self.fail_json(msg='There are no organizations with the name {org_name}'.format(org_name=org_name)) - if org_count > 1: - self.fail_json(msg='There are multiple organizations with the name {org_name}'.format(org_name=org_name)) - elif org_count == 1: - for i in orgs: - if org_name == i['name']: - # self.fail_json(msg=i['id']) - return str(i['id']) - - def get_nets(self, org_name=None, org_id=None): - """Downloads all networks in an organization.""" - if org_name: - org_id = self.get_org_id(org_name) - path = self.construct_path('get_all', org_id=org_id, function='network') - r = self.request(path, method='GET') - if self.status != 200: - self.fail_json(msg='Network lookup failed') - self.nets = r - templates = self.get_config_templates(org_id) - for t in templates: - self.nets.append(t) - return self.nets - - def get_net(self, org_name, net_name=None, org_id=None, data=None, net_id=None): - ''' Return network information ''' - if not data: - if not org_id: - org_id = self.get_org_id(org_name) - data = self.get_nets(org_id=org_id) - for n in data: - if net_id: - if n['id'] == net_id: - return n - elif net_name: - if n['name'] == net_name: - return n - return False - - def get_net_id(self, org_name=None, net_name=None, data=None): - """Return network id from lookup or existing data.""" - if data is None: - self.fail_json(msg='Must implement lookup') - for n in data: - if n['name'] == net_name: - return n['id'] - self.fail_json(msg='No network found with the name {0}'.format(net_name)) - - def get_config_templates(self, org_id): - path = self.construct_path('get_all', function='configTemplates', org_id=org_id) - response = self.request(path, 'GET') - if self.status != 200: - self.fail_json(msg='Unable to get configuration templates') - return response - - def get_template_id(self, name, data): - for template in data: - if name == template['name']: - return template['id'] - self.fail_json(msg='No configuration template named {0} found'.format(name)) - - def convert_camel_to_snake(self, data): - """ - Converts a dictionary or list to snake case from camel case - :type data: dict or list - :return: Converted data structure, if list or dict - """ - - if isinstance(data, dict): - return camel_dict_to_snake_dict(data, ignore_list=('tags', 'tag')) - elif isinstance(data, list): - return [camel_dict_to_snake_dict(item, ignore_list=('tags', 'tag')) for item in data] - else: - return data - - def construct_params_list(self, keys, aliases=None): - qs = {} - for key in keys: - if key in aliases: - qs[aliases[key]] = self.module.params[key] - else: - qs[key] = self.module.params[key] - return qs - - def encode_url_params(self, params): - """Encodes key value pairs for URL""" - return "?{0}".format(urlencode(params)) - - def construct_path(self, - action, - function=None, - org_id=None, - net_id=None, - org_name=None, - custom=None, - params=None): - """Build a path from the URL catalog. - Uses function property from class for catalog lookup. - """ - built_path = None - if function is None: - built_path = self.url_catalog[action][self.function] - else: - built_path = self.url_catalog[action][function] - if org_name: - org_id = self.get_org_id(org_name) - if custom: - built_path = built_path.format(org_id=org_id, net_id=net_id, **custom) - else: - built_path = built_path.format(org_id=org_id, net_id=net_id) - if params: - built_path += self.encode_url_params(params) - return built_path - - @_error_report - def request(self, path, method=None, payload=None): - """Generic HTTP method for Meraki requests.""" - self.path = path - self.define_protocol() - - if method is not None: - self.method = method - self.url = '{protocol}://{host}/api/v0/{path}'.format(path=self.path.lstrip('/'), **self.params) - resp, info = fetch_url(self.module, self.url, - headers=self.headers, - data=payload, - method=self.method, - timeout=self.params['timeout'], - use_proxy=self.params['use_proxy'], - ) - self.response = info['msg'] - self.status = info['status'] - - try: - return json.loads(to_native(resp.read())) - except Exception: - pass - - def exit_json(self, **kwargs): - """Custom written method to exit from module.""" - self.result['response'] = self.response - self.result['status'] = self.status - if self.retry > 0: - self.module.warn("Rate limiter triggered - retry count {0}".format(self.retry)) - # Return the gory details when we need it - if self.params['output_level'] == 'debug': - self.result['method'] = self.method - self.result['url'] = self.url - self.result.update(**kwargs) - if self.params['output_format'] == 'camelcase': - self.module.deprecate("Update your playbooks to support snake_case format instead of camelCase format.", version=2.13) - else: - if 'data' in self.result: - try: - self.result['data'] = self.convert_camel_to_snake(self.result['data']) - except (KeyError, AttributeError): - pass - self.module.exit_json(**self.result) - - def fail_json(self, msg, **kwargs): - """Custom written method to return info on failure.""" - self.result['response'] = self.response - self.result['status'] = self.status - - if self.params['output_level'] == 'debug': - if self.url is not None: - self.result['method'] = self.method - self.result['url'] = self.url - - self.result.update(**kwargs) - self.module.fail_json(msg=msg, **self.result) diff --git a/lib/ansible/modules/network/meraki/__init__.py b/lib/ansible/modules/network/meraki/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ansible/modules/network/meraki/meraki_admin.py b/lib/ansible/modules/network/meraki/meraki_admin.py deleted file mode 100644 index 342d071f0ed..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_admin.py +++ /dev/null @@ -1,498 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_admin -short_description: Manage administrators in the Meraki cloud -version_added: '2.6' -description: -- Allows for creation, management, and visibility into administrators within Meraki. -options: - name: - description: - - Name of the dashboard administrator. - - Required when creating a new administrator. - type: str - email: - description: - - Email address for the dashboard administrator. - - Email cannot be updated. - - Required when creating or editing an administrator. - type: str - org_access: - description: - - Privileges assigned to the administrator in the organization. - aliases: [ orgAccess ] - choices: [ full, none, read-only ] - type: str - tags: - description: - - Tags the administrator has privileges on. - - When creating a new administrator, C(org_name), C(network), or C(tags) must be specified. - - If C(none) is specified, C(network) or C(tags) must be specified. - suboptions: - tag: - description: - - Object tag which privileges should be assigned. - type: str - access: - description: - - The privilege of the dashboard administrator for the tag. - type: str - networks: - description: - - List of networks the administrator has privileges on. - - When creating a new administrator, C(org_name), C(network), or C(tags) must be specified. - suboptions: - id: - description: - - Network ID for which administrator should have privileges assigned. - type: str - access: - description: - - The privilege of the dashboard administrator on the network. - - Valid options are C(full), C(read-only), or C(none). - type: str - state: - description: - - Create or modify, or delete an organization - - If C(state) is C(absent), name takes priority over email if both are specified. - choices: [ absent, present, query ] - required: true - type: str - org_name: - description: - - Name of organization. - - Used when C(name) should refer to another object. - - When creating a new administrator, C(org_name), C(network), or C(tags) must be specified. - aliases: ['organization'] - type: str -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query information about all administrators associated to the organization - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: query - delegate_to: localhost - -- name: Query information about a single administrator by name - meraki_admin: - auth_key: abc12345 - org_id: 12345 - state: query - name: Jane Doe - -- name: Query information about a single administrator by email - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: query - email: jane@doe.com - -- name: Create new administrator with organization access - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: present - name: Jane Doe - org_access: read-only - email: jane@doe.com - -- name: Create new administrator with organization access - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: present - name: Jane Doe - org_access: read-only - email: jane@doe.com - -- name: Create a new administrator with organization access - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: present - name: Jane Doe - org_access: read-only - email: jane@doe.com - -- name: Revoke access to an organization for an administrator - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: absent - email: jane@doe.com - -- name: Create a new administrator with full access to two tags - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: present - name: Jane Doe - orgAccess: read-only - email: jane@doe.com - tags: - - tag: tenant - access: full - - tag: corporate - access: read-only - -- name: Create a new administrator with full access to a network - meraki_admin: - auth_key: abc12345 - org_name: YourOrg - state: present - name: Jane Doe - orgAccess: read-only - email: jane@doe.com - networks: - - id: N_12345 - access: full -''' - -RETURN = r''' -data: - description: List of administrators. - returned: success - type: complex - contains: - email: - description: Email address of administrator. - returned: success - type: str - sample: your@email.com - id: - description: Unique identification number of administrator. - returned: success - type: str - sample: 1234567890 - name: - description: Given name of administrator. - returned: success - type: str - sample: John Doe - account_status: - description: Status of account. - returned: success - type: str - sample: ok - two_factor_auth_enabled: - description: Enabled state of two-factor authentication for administrator. - returned: success - type: bool - sample: false - has_api_key: - description: Defines whether administrator has an API assigned to their account. - returned: success - type: bool - sample: false - last_active: - description: Date and time of time the administrator was active within Dashboard. - returned: success - type: str - sample: 2019-01-28 14:58:56 -0800 - networks: - description: List of networks administrator has access on. - returned: success - type: complex - contains: - id: - description: The network ID. - returned: when network permissions are set - type: str - sample: N_0123456789 - access: - description: Access level of administrator. Options are 'full', 'read-only', or 'none'. - returned: when network permissions are set - type: str - sample: read-only - tags: - description: Tags the administrator has access on. - returned: success - type: complex - contains: - tag: - description: Tag name. - returned: when tag permissions are set - type: str - sample: production - access: - description: Access level of administrator. Options are 'full', 'read-only', or 'none'. - returned: when tag permissions are set - type: str - sample: full - org_access: - description: The privilege of the dashboard administrator on the organization. Options are 'full', 'read-only', or 'none'. - returned: success - type: str - sample: full - -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_admins(meraki, org_id): - admins = meraki.request( - meraki.construct_path( - 'query', - function='admin', - org_id=org_id - ), - method='GET' - ) - if meraki.status == 200: - return admins - - -def get_admin_id(meraki, data, name=None, email=None): - admin_id = None - for a in data: - if meraki.params['name'] is not None: - if meraki.params['name'] == a['name']: - if admin_id is not None: - meraki.fail_json(msg='There are multiple administrators with the same name') - else: - admin_id = a['id'] - elif meraki.params['email']: - if meraki.params['email'] == a['email']: - return a['id'] - if admin_id is None: - meraki.fail_json(msg='No admin_id found') - return admin_id - - -def get_admin(meraki, data, id): - for a in data: - if a['id'] == id: - return a - meraki.fail_json(msg='No admin found by specified name or email') - - -def find_admin(meraki, data, email): - for a in data: - if a['email'] == email: - return a - return None - - -def delete_admin(meraki, org_id, admin_id): - path = meraki.construct_path('revoke', 'admin', org_id=org_id) + admin_id - r = meraki.request(path, - method='DELETE' - ) - if meraki.status == 204: - return r - - -def network_factory(meraki, networks, nets): - networks = json.loads(networks) - networks_new = [] - for n in networks: - networks_new.append({'id': meraki.get_net_id(org_name=meraki.params['org_name'], - net_name=n['network'], - data=nets), - 'access': n['access'] - }) - return networks_new - - -def create_admin(meraki, org_id, name, email): - payload = dict() - payload['name'] = name - payload['email'] = email - - is_admin_existing = find_admin(meraki, get_admins(meraki, org_id), email) - - if meraki.params['org_access'] is not None: - payload['orgAccess'] = meraki.params['org_access'] - if meraki.params['tags'] is not None: - payload['tags'] = json.loads(meraki.params['tags']) - if meraki.params['networks'] is not None: - nets = meraki.get_nets(org_id=org_id) - networks = network_factory(meraki, meraki.params['networks'], nets) - payload['networks'] = networks - if is_admin_existing is None: # Create new admin - if meraki.module.check_mode is True: - meraki.result['data'] = payload - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - path = meraki.construct_path('create', function='admin', org_id=org_id) - r = meraki.request(path, - method='POST', - payload=json.dumps(payload) - ) - if meraki.status == 201: - meraki.result['changed'] = True - return r - elif is_admin_existing is not None: # Update existing admin - if not meraki.params['tags']: - payload['tags'] = [] - if not meraki.params['networks']: - payload['networks'] = [] - if meraki.is_update_required(is_admin_existing, payload) is True: - if meraki.module.check_mode is True: - diff = recursive_diff(is_admin_existing, payload) - is_admin_existing.update(payload) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1], - } - meraki.result['changed'] = True - meraki.result['data'] = payload - meraki.exit_json(**meraki.result) - path = meraki.construct_path('update', function='admin', org_id=org_id) + is_admin_existing['id'] - r = meraki.request(path, - method='PUT', - payload=json.dumps(payload) - ) - if meraki.status == 200: - meraki.result['changed'] = True - return r - else: - meraki.result['data'] = is_admin_existing - if meraki.module.check_mode is True: - meraki.result['data'] = payload - meraki.exit_json(**meraki.result) - return -1 - - -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'], required=True), - name=dict(type='str'), - email=dict(type='str'), - org_access=dict(type='str', aliases=['orgAccess'], choices=['full', 'read-only', 'none']), - tags=dict(type='json'), - networks=dict(type='json'), - org_name=dict(type='str', aliases=['organization']), - org_id=dict(type='str'), - ) - - # 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='admin') - - meraki.function = 'admin' - meraki.params['follow_redirects'] = 'all' - - query_urls = {'admin': '/organizations/{org_id}/admins', - } - create_urls = {'admin': '/organizations/{org_id}/admins', - } - update_urls = {'admin': '/organizations/{org_id}/admins/', - } - revoke_urls = {'admin': '/organizations/{org_id}/admins/', - } - - meraki.url_catalog['query'] = query_urls - meraki.url_catalog['create'] = create_urls - meraki.url_catalog['update'] = update_urls - meraki.url_catalog['revoke'] = revoke_urls - - try: - meraki.params['auth_key'] = os.environ['MERAKI_KEY'] - except KeyError: - pass - - payload = None - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - - # execute checks for argument completeness - if meraki.params['state'] == 'query': - meraki.mututally_exclusive = ['name', 'email'] - if not meraki.params['org_name'] and not meraki.params['org_id']: - meraki.fail_json(msg='org_name or org_id required') - meraki.required_if = [(['state'], ['absent'], ['email']), - ] - - # 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 not meraki.params['org_id']: - org_id = meraki.get_org_id(meraki.params['org_name']) - if meraki.params['state'] == 'query': - admins = get_admins(meraki, org_id) - if not meraki.params['name'] and not meraki.params['email']: # Return all admins for org - meraki.result['data'] = admins - if meraki.params['name'] is not None: # Return a single admin for org - admin_id = get_admin_id(meraki, admins, name=meraki.params['name']) - meraki.result['data'] = admin_id - admin = get_admin(meraki, admins, admin_id) - meraki.result['data'] = admin - elif meraki.params['email'] is not None: - admin_id = get_admin_id(meraki, admins, email=meraki.params['email']) - meraki.result['data'] = admin_id - admin = get_admin(meraki, admins, admin_id) - meraki.result['data'] = admin - elif meraki.params['state'] == 'present': - r = create_admin(meraki, - org_id, - meraki.params['name'], - meraki.params['email'], - ) - if r != -1: - meraki.result['data'] = r - elif meraki.params['state'] == 'absent': - if meraki.module.check_mode is True: - meraki.result['data'] = {} - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - admin_id = get_admin_id(meraki, - get_admins(meraki, org_id), - email=meraki.params['email'] - ) - r = delete_admin(meraki, org_id, admin_id) - - if r != -1: - meraki.result['data'] = r - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_config_template.py b/lib/ansible/modules/network/meraki/meraki_config_template.py deleted file mode 100644 index ad6258db73f..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_config_template.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_config_template -short_description: Manage configuration templates in the Meraki cloud -version_added: "2.7" -description: -- Allows for querying, deleting, binding, and unbinding of configuration templates. -notes: -- Module is not idempotent as the Meraki API is limited in what information it provides about configuration templates. -- Meraki's API does not support creating new configuration templates. -- To use the configuration template, simply pass its ID via C(net_id) parameters in Meraki modules. -options: - state: - description: - - Specifies whether configuration template information should be queried, modified, or deleted. - choices: ['absent', 'query', 'present'] - default: query - org_name: - description: - - Name of organization containing the configuration template. - type: str - org_id: - description: - - ID of organization associated to a configuration template. - type: str - config_template: - description: - - Name of the configuration template within an organization to manipulate. - aliases: ['name'] - net_name: - description: - - Name of the network to bind or unbind configuration template to. - type: str - net_id: - description: - - ID of the network to bind or unbind configuration template to. - type: str - auto_bind: - description: - - Optional boolean indicating whether the network's switches should automatically bind to profiles of the same model. - - This option only affects switch networks and switch templates. - - Auto-bind is not valid unless the switch template has at least one profile and has at most one profile per switch model. - type: bool - -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query configuration templates - meraki_config_template: - auth_key: abc12345 - org_name: YourOrg - state: query - delegate_to: localhost - -- name: Bind a template from a network - meraki_config_template: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - config_template: DevConfigTemplate - delegate_to: localhost - -- name: Unbind a template from a network - meraki_config_template: - auth_key: abc123 - state: absent - org_name: YourOrg - net_name: YourNet - config_template: DevConfigTemplate - delegate_to: localhost - -- name: Delete a configuration template - meraki_config_template: - auth_key: abc123 - state: absent - org_name: YourOrg - config_template: DevConfigTemplate - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information about queried object. - returned: success - type: complex - contains: - id: - description: Unique identification number of organization - returned: success - type: int - sample: L_2930418 - name: - description: Name of configuration template - returned: success - type: str - sample: YourTemplate -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_config_templates(meraki, org_id): - path = meraki.construct_path('get_all', org_id=org_id) - response = meraki.request(path, 'GET') - if meraki.status != 200: - meraki.fail_json(msg='Unable to get configuration templates') - return response - - -def get_template_id(meraki, name, data): - for template in data: - if name == template['name']: - return template['id'] - meraki.fail_json(msg='No configuration template named {0} found'.format(name)) - - -def is_template_valid(meraki, nets, template_id): - for net in nets: - if net['id'] == template_id: - return True - return False - - -def is_network_bound(meraki, nets, net_id, template_id): - for net in nets: - if net['id'] == net_id: - try: - if net['configTemplateId'] == template_id: - return True - except KeyError: - pass - return False - - -def delete_template(meraki, org_id, name, data): - template_id = get_template_id(meraki, name, data) - path = meraki.construct_path('delete', org_id=org_id) - path = path + '/' + template_id - response = meraki.request(path, 'DELETE') - if meraki.status != 204: - meraki.fail_json(msg='Unable to remove configuration template') - return response - - -def bind(meraki, net_id, template_id): - path = meraki.construct_path('bind', net_id=net_id) - payload = {'configTemplateId': template_id} - if meraki.params['auto_bind']: - payload['autoBind'] = meraki.params['auto_bind'] - r = meraki.request(path, method='POST', payload=json.dumps(payload)) - return r - - -def unbind(meraki, net_id): - path = meraki.construct_path('unbind', net_id=net_id) - meraki.result['changed'] = True - return meraki.request(path, method='POST') - - -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=['absent', 'query', 'present'], default='query'), - config_template=dict(type='str', aliases=['name']), - net_name=dict(type='str'), - net_id=dict(type='str'), - # config_template_id=dict(type='str', aliases=['id']), - auto_bind=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='config_template') - meraki.params['follow_redirects'] = 'all' - - query_urls = {'config_template': '/organizations/{org_id}/configTemplates'} - delete_urls = {'config_template': '/organizations/{org_id}/configTemplates'} - bind_urls = {'config_template': '/networks/{net_id}/bind'} - unbind_urls = {'config_template': '/networks/{net_id}/unbind'} - - meraki.url_catalog['get_all'].update(query_urls) - meraki.url_catalog['delete'] = delete_urls - meraki.url_catalog['bind'] = bind_urls - meraki.url_catalog['unbind'] = unbind_urls - - payload = None - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - - # 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 meraki.params['org_name']: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - nets = None - if net_id is None: - if meraki.params['net_name'] is not None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - else: - nets = meraki.get_nets(org_id=org_id) - - if meraki.params['state'] == 'query': - meraki.result['data'] = get_config_templates(meraki, org_id) - elif meraki.params['state'] == 'present': - template_id = get_template_id(meraki, - meraki.params['config_template'], - get_config_templates(meraki, org_id)) - if nets is None: - nets = meraki.get_nets(org_id=org_id) - if is_network_bound(meraki, nets, net_id, template_id) is False: # Bind template - if meraki.check_mode is True: - meraki.result['data'] = {} - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - template_bind = bind(meraki, - net_id, - template_id) - if meraki.status != 200: - meraki.fail_json(msg='Unable to bind configuration template to network') - meraki.result['changed'] = True - meraki.result['data'] = template_bind - else: # Network is already bound, being explicit - if meraki.check_mode is True: # Include to be explicit - meraki.result['data'] = {} - meraki.result['changed'] = False - meraki.exit_json(**meraki.result) - meraki.result['data'] = {} - meraki.result['changed'] = False - meraki.exit_json(**meraki.result) - elif meraki.params['state'] == 'absent': - template_id = get_template_id(meraki, - meraki.params['config_template'], - get_config_templates(meraki, org_id)) - if not meraki.params['net_name'] and not meraki.params['net_id']: # Delete template - if is_template_valid(meraki, nets, template_id) is True: - if meraki.check_mode is True: - meraki.result['data'] = {} - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - meraki.result['data'] = delete_template(meraki, - org_id, - meraki.params['config_template'], - get_config_templates(meraki, org_id)) - if meraki.status == 204: - meraki.result['data'] = {} - meraki.result['changed'] = True - else: - meraki.fail_json(msg="No template named {0} found.".format(meraki.params['config_template'])) - else: # Unbind template - if meraki.check_mode is True: - meraki.result['data'] = {} - if is_template_valid(meraki, nets, template_id) is True: - meraki.result['changed'] = True - else: - meraki.result['changed'] = False - meraki.exit_json(**meraki.result) - template_id = get_template_id(meraki, - meraki.params['config_template'], - get_config_templates(meraki, org_id)) - if nets is None: - nets = meraki.get_nets(org_id=org_id) - if is_network_bound(meraki, nets, net_id, template_id) is True: - if meraki.check_mode is True: - meraki.result['data'] = {} - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - config_unbind = unbind(meraki, - net_id) - if meraki.status != 200: - meraki.fail_json(msg='Unable to unbind configuration template from network') - meraki.result['changed'] = True - meraki.result['data'] = config_unbind - else: # No network is bound, nothing to do - if meraki.check_mode is True: # Include to be explicit - meraki.result['data'] = {} - meraki.result['changed'] = False - meraki.exit_json(**meraki.result) - meraki.result['data'] = {} - meraki.result['changed'] = False - - # 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() diff --git a/lib/ansible/modules/network/meraki/meraki_content_filtering.py b/lib/ansible/modules/network/meraki/meraki_content_filtering.py deleted file mode 100644 index 498bf43ab06..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_content_filtering.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Kevin Breit (@kbreit) -# 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_content_filtering -short_description: Edit Meraki MX content filtering policies -version_added: "2.8" -description: -- Allows for setting policy on content filtering. - -options: - auth_key: - description: - - Authentication key provided by the dashboard. Required if environmental variable MERAKI_KEY is not set. - type: str - net_name: - description: - - Name of a network. - aliases: [ network ] - type: str - net_id: - description: - - ID number of a network. - type: str - state: - description: - - States that a policy should be created or modified. - choices: [present, query] - default: present - type: str - allowed_urls: - description: - - List of URL patterns which should be allowed. - type: list - blocked_urls: - description: - - List of URL patterns which should be blocked. - type: list - blocked_categories: - description: - - List of content categories which should be blocked. - - Use the C(meraki_content_filtering_facts) module for a full list of categories. - type: list - category_list_size: - description: - - Determines whether a network filters fo rall URLs in a category or only the list of top blocked sites. - choices: [ top sites, full list ] - type: str - subset: - description: - - Display only certain facts. - choices: [categories, policy] - type: str - version_added: '2.9' -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' - - name: Set single allowed URL pattern - meraki_content_filtering: - auth_key: abc123 - org_name: YourOrg - net_name: YourMXNet - allowed_urls: - - "http://www.ansible.com/*" - - - name: Set blocked URL category - meraki_content_filtering: - auth_key: abc123 - org_name: YourOrg - net_name: YourMXNet - state: present - category_list_size: full list - blocked_categories: - - "Adult and Pornography" - - - name: Remove match patterns and categories - meraki_content_filtering: - auth_key: abc123 - org_name: YourOrg - net_name: YourMXNet - state: present - category_list_size: full list - allowed_urls: [] - blocked_urls: [] -''' - -RETURN = r''' -data: - description: Information about the created or manipulated object. - returned: info - type: complex - contains: - id: - description: Identification string of network. - returned: success - type: str - sample: N_12345 -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_category_dict(meraki, full_list, category): - for i in full_list['categories']: - if i['name'] == category: - return i['id'] - meraki.fail_json(msg="{0} is not a valid content filtering category".format(category)) - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - - argument_spec = meraki_argument_spec() - argument_spec.update( - net_id=dict(type='str'), - net_name=dict(type='str', aliases=['network']), - state=dict(type='str', default='present', choices=['present', 'query']), - allowed_urls=dict(type='list'), - blocked_urls=dict(type='list'), - blocked_categories=dict(type='list'), - category_list_size=dict(type='str', choices=['top sites', 'full list']), - subset=dict(type='str', choices=['categories', 'policy']), - ) - - # 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='content_filtering') - module.params['follow_redirects'] = 'all' - - category_urls = {'content_filtering': '/networks/{net_id}/contentFiltering/categories'} - policy_urls = {'content_filtering': '/networks/{net_id}/contentFiltering'} - - meraki.url_catalog['categories'] = category_urls - meraki.url_catalog['policy'] = policy_urls - - if meraki.params['net_name'] and meraki.params['net_id']: - meraki.fail_json(msg='net_name and net_id are mutually exclusive') - - # 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 not org_id: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(org_id, meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - if meraki.params['subset']: - if meraki.params['subset'] == 'categories': - path = meraki.construct_path('categories', net_id=net_id) - elif meraki.params['subset'] == 'policy': - path = meraki.construct_path('policy', net_id=net_id) - meraki.result['data'] = meraki.request(path, method='GET') - else: - response_data = {'categories': None, - 'policy': None, - } - path = meraki.construct_path('categories', net_id=net_id) - response_data['categories'] = meraki.request(path, method='GET') - path = meraki.construct_path('policy', net_id=net_id) - response_data['policy'] = meraki.request(path, method='GET') - meraki.result['data'] = response_data - if module.params['state'] == 'present': - payload = dict() - if meraki.params['allowed_urls']: - payload['allowedUrlPatterns'] = meraki.params['allowed_urls'] - if meraki.params['blocked_urls']: - payload['blockedUrlPatterns'] = meraki.params['blocked_urls'] - if meraki.params['blocked_categories']: - if len(meraki.params['blocked_categories']) == 0: # Corner case for resetting - payload['blockedUrlCategories'] = [] - else: - category_path = meraki.construct_path('categories', net_id=net_id) - categories = meraki.request(category_path, method='GET') - payload['blockedUrlCategories'] = [] - for category in meraki.params['blocked_categories']: - payload['blockedUrlCategories'].append(get_category_dict(meraki, - categories, - category)) - if meraki.params['category_list_size']: - if meraki.params['category_list_size'].lower() == 'top sites': - payload['urlCategoryListSize'] = "topSites" - elif meraki.params['category_list_size'].lower() == 'full list': - payload['urlCategoryListSize'] = "fullList" - path = meraki.construct_path('policy', net_id=net_id) - current = meraki.request(path, method='GET') - proposed = current.copy() - proposed.update(payload) - if meraki.is_update_required(current, payload) is True: - meraki.result['diff'] = dict() - diff = recursive_diff(current, payload) - meraki.result['diff']['before'] = diff[0] - meraki.result['diff']['after'] = diff[1] - if module.check_mode: - current.update(payload) - meraki.result['changed'] = True - meraki.result['data'] = current - meraki.exit_json(**meraki.result) - response = meraki.request(path, method='PUT', payload=json.dumps(payload)) - meraki.result['data'] = response - meraki.result['changed'] = True - else: - meraki.result['data'] = current - if module.check_mode: - meraki.result['data'] = current - meraki.exit_json(**meraki.result) - meraki.result['data'] = current - meraki.exit_json(**meraki.result) - - # 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() diff --git a/lib/ansible/modules/network/meraki/meraki_device.py b/lib/ansible/modules/network/meraki/meraki_device.py deleted file mode 100644 index 72662959f5e..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_device.py +++ /dev/null @@ -1,430 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_device -short_description: Manage devices in the Meraki cloud -version_added: "2.7" -description: -- Visibility into devices associated to a Meraki environment. -notes: -- This module does not support claiming of devices or licenses into a Meraki organization. -- More information about the Meraki API can be found at U(https://dashboard.meraki.com/api_docs). -- Some of the options are likely only used for developers within Meraki. -options: - state: - description: - - Query an organization. - choices: [absent, present, query] - default: query - type: str - net_name: - description: - - Name of a network. - aliases: [network] - type: str - net_id: - description: - - ID of a network. - type: str - serial: - description: - - Serial number of a device to query. - type: str - hostname: - description: - - Hostname of network device to search for. - aliases: [name] - type: str - model: - description: - - Model of network device to search for. - type: str - tags: - description: - - Space delimited list of tags to assign to device. - type: str - lat: - description: - - Latitude of device's geographic location. - - Use negative number for southern hemisphere. - aliases: [latitude] - type: float - lng: - description: - - Longitude of device's geographic location. - - Use negative number for western hemisphere. - aliases: [longitude] - type: float - address: - description: - - Postal address of device's location. - type: str - move_map_marker: - description: - - Whether or not to set the latitude and longitude of a device based on the new address. - - Only applies when C(lat) and C(lng) are not specified. - type: bool - serial_lldp_cdp: - description: - - Serial number of device to query LLDP/CDP information from. - type: str - lldp_cdp_timespan: - description: - - Timespan, in seconds, used to query LLDP and CDP information. - - Must be less than 1 month. - type: int - serial_uplink: - description: - - Serial number of device to query uplink information from. - type: str - note: - description: - - Informational notes about a device. - - Limited to 255 characters. - version_added: '2.8' - type: str - - -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query all devices in an organization. - meraki_device: - auth_key: abc12345 - org_name: YourOrg - state: query - delegate_to: localhost - -- name: Query all devices in a network. - meraki_device: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - state: query - delegate_to: localhost - -- name: Query a device by serial number. - meraki_device: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - serial: ABC-123 - state: query - delegate_to: localhost - -- name: Lookup uplink information about a device. - meraki_device: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - serial_uplink: ABC-123 - state: query - delegate_to: localhost - -- name: Lookup LLDP and CDP information about devices connected to specified device. - meraki_device: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - serial_lldp_cdp: ABC-123 - state: query - delegate_to: localhost - -- name: Lookup a device by hostname. - meraki_device: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - hostname: main-switch - state: query - delegate_to: localhost - -- name: Query all devices of a specific model. - meraki_device: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - model: MR26 - state: query - delegate_to: localhost - -- name: Update information about a device. - meraki_device: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - serial: '{{serial}}' - name: mr26 - address: 1060 W. Addison St., Chicago, IL - lat: 41.948038 - lng: -87.65568 - tags: recently-added - delegate_to: localhost - -- name: Claim a device into a network. - meraki_device: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - serial: ABC-123 - state: present - delegate_to: localhost - -- name: Remove a device from a network. - meraki_device: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - serial: ABC-123 - state: absent - delegate_to: localhost -''' - -RETURN = r''' -response: - description: Data returned from Meraki dashboard. - type: dict - returned: info -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def format_tags(tags): - return " {tags} ".format(tags=tags) - - -def is_device_valid(meraki, serial, data): - for device in data: - if device['serial'] == serial: - return True - return False - - -def get_org_devices(meraki, org_id): - path = meraki.construct_path('get_all_org', org_id=org_id) - response = meraki.request(path, method='GET') - if meraki.status != 200: - meraki.fail_json(msg='Failed to query all devices belonging to the organization') - return response - - -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=['absent', 'present', 'query'], default='query'), - net_name=dict(type='str', aliases=['network']), - net_id=dict(type='str'), - serial=dict(type='str'), - serial_uplink=dict(type='str'), - serial_lldp_cdp=dict(type='str'), - lldp_cdp_timespan=dict(type='int'), - hostname=dict(type='str', aliases=['name']), - model=dict(type='str'), - tags=dict(type='str'), - lat=dict(type='float', aliases=['latitude']), - lng=dict(type='float', aliases=['longitude']), - address=dict(type='str'), - move_map_marker=dict(type='bool'), - note=dict(type='str'), - ) - - # 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='device') - - if meraki.params['serial_lldp_cdp'] and not meraki.params['lldp_cdp_timespan']: - meraki.fail_json(msg='lldp_cdp_timespan is required when querying LLDP and CDP information') - if meraki.params['net_name'] and meraki.params['net_id']: - meraki.fail_json(msg='net_name and net_id are mutually exclusive') - - meraki.params['follow_redirects'] = 'all' - - query_urls = {'device': '/networks/{net_id}/devices'} - query_org_urls = {'device': '/organizations/{org_id}/inventory'} - query_device_urls = {'device': '/networks/{net_id}/devices/'} - claim_device_urls = {'device': '/networks/{net_id}/devices/claim'} - bind_org_urls = {'device': '/organizations/{org_id}/claim'} - update_device_urls = {'device': '/networks/{net_id}/devices/'} - delete_device_urls = {'device': '/networks/{net_id}/devices/'} - - meraki.url_catalog['get_all'].update(query_urls) - meraki.url_catalog['get_all_org'] = query_org_urls - meraki.url_catalog['get_device'] = query_device_urls - meraki.url_catalog['create'] = claim_device_urls - meraki.url_catalog['bind_org'] = bind_org_urls - meraki.url_catalog['update'] = update_device_urls - meraki.url_catalog['delete'] = delete_device_urls - - payload = None - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - # FIXME: Work with Meraki so they can implement a check mode - if module.check_mode: - meraki.exit_json(**meraki.result) - - # 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: - org_id = meraki.get_org_id(meraki.params['org_name']) - nets = meraki.get_nets(org_id=org_id) - net_id = None - if meraki.params['net_id'] or meraki.params['net_name']: - net_id = meraki.params['net_id'] - if net_id is None: - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - if meraki.params['net_name'] or meraki.params['net_id']: - device = [] - if meraki.params['serial']: - path = meraki.construct_path('get_device', net_id=net_id) + meraki.params['serial'] - request = meraki.request(path, method='GET') - device.append(request) - meraki.result['data'] = device - elif meraki.params['serial_uplink']: - path = meraki.construct_path('get_device', net_id=net_id) + meraki.params['serial_uplink'] + '/uplink' - meraki.result['data'] = (meraki.request(path, method='GET')) - elif meraki.params['serial_lldp_cdp']: - if meraki.params['lldp_cdp_timespan'] > 2592000: - meraki.fail_json(msg='LLDP/CDP timespan must be less than a month (2592000 seconds)') - path = meraki.construct_path('get_device', net_id=net_id) + meraki.params['serial_lldp_cdp'] + '/lldp_cdp' - path = path + '?timespan=' + str(meraki.params['lldp_cdp_timespan']) - device.append(meraki.request(path, method='GET')) - meraki.result['data'] = device - elif meraki.params['hostname']: - path = meraki.construct_path('get_all', net_id=net_id) - devices = meraki.request(path, method='GET') - for unit in devices: - try: - if unit['name'] == meraki.params['hostname']: - device.append(unit) - meraki.result['data'] = device - except KeyError: - pass - elif meraki.params['model']: - path = meraki.construct_path('get_all', net_id=net_id) - devices = meraki.request(path, method='GET') - device_match = [] - for device in devices: - if device['model'] == meraki.params['model']: - device_match.append(device) - meraki.result['data'] = device_match - else: - path = meraki.construct_path('get_all', net_id=net_id) - request = meraki.request(path, method='GET') - meraki.result['data'] = request - else: - path = meraki.construct_path('get_all_org', org_id=org_id) - devices = meraki.request(path, method='GET') - if meraki.params['serial']: - for device in devices: - if device['serial'] == meraki.params['serial']: - meraki.result['data'] = device - else: - meraki.result['data'] = devices - elif meraki.params['state'] == 'present': - device = [] - if meraki.params['hostname']: - query_path = meraki.construct_path('get_all', net_id=net_id) - device_list = meraki.request(query_path, method='GET') - if is_device_valid(meraki, meraki.params['serial'], device_list): - payload = {'name': meraki.params['hostname'], - 'tags': format_tags(meraki.params['tags']), - 'lat': meraki.params['lat'], - 'lng': meraki.params['lng'], - 'address': meraki.params['address'], - 'moveMapMarker': meraki.params['move_map_marker'], - 'notes': meraki.params['note'], - } - query_path = meraki.construct_path('get_device', net_id=net_id) + meraki.params['serial'] - device_data = meraki.request(query_path, method='GET') - ignore_keys = ['lanIp', 'serial', 'mac', 'model', 'networkId', 'moveMapMarker', 'wan1Ip', 'wan2Ip'] - # meraki.fail_json(msg="Compare", original=device_data, payload=payload, ignore=ignore_keys) - if meraki.is_update_required(device_data, payload, optional_ignore=ignore_keys): - path = meraki.construct_path('update', net_id=net_id) + meraki.params['serial'] - updated_device = [] - updated_device.append(meraki.request(path, method='PUT', payload=json.dumps(payload))) - meraki.result['data'] = updated_device - meraki.result['changed'] = True - else: - meraki.result['data'] = device_data - else: - if net_id is None: - device_list = get_org_devices(meraki, org_id) - if is_device_valid(meraki, meraki.params['serial'], device_list) is False: - payload = {'serial': meraki.params['serial']} - path = meraki.construct_path('bind_org', org_id=org_id) - created_device = [] - created_device.append(meraki.request(path, method='POST', payload=json.dumps(payload))) - meraki.result['data'] = created_device - meraki.result['changed'] = True - else: - query_path = meraki.construct_path('get_all', net_id=net_id) - device_list = meraki.request(query_path, method='GET') - if is_device_valid(meraki, meraki.params['serial'], device_list) is False: - if net_id: - payload = {'serial': meraki.params['serial']} - path = meraki.construct_path('create', net_id=net_id) - created_device = [] - created_device.append(meraki.request(path, method='POST', payload=json.dumps(payload))) - meraki.result['data'] = created_device - meraki.result['changed'] = True - elif meraki.params['state'] == 'absent': - device = [] - query_path = meraki.construct_path('get_all', net_id=net_id) - device_list = meraki.request(query_path, method='GET') - if is_device_valid(meraki, meraki.params['serial'], device_list) is True: - path = meraki.construct_path('delete', net_id=net_id) - path = path + meraki.params['serial'] + '/remove' - request = meraki.request(path, method='POST') - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_firewalled_services.py b/lib/ansible/modules/network/meraki/meraki_firewalled_services.py deleted file mode 100644 index 43842c343f4..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_firewalled_services.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Kevin Breit (@kbreit) -# 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_firewalled_services -short_description: Edit firewall policies for administrative network services -version_added: "2.9" -description: -- Allows for setting policy firewalled services for Meraki network devices. - -options: - auth_key: - description: - - Authentication key provided by the dashboard. Required if environmental variable MERAKI_KEY is not set. - type: str - net_name: - description: - - Name of a network. - aliases: [ network ] - type: str - net_id: - description: - - ID number of a network. - type: str - org_name: - description: - - Name of organization associated to a network. - type: str - org_id: - description: - - ID of organization associated to a network. - type: str - state: - description: - - States that a policy should be created or modified. - choices: [present, query] - default: present - type: str - service: - description: - - Network service to query or modify. - choices: [ICMP, SNMP, web] - type: str - access: - description: - - Network service to query or modify. - choices: [blocked, restricted, unrestricted] - type: str - allowed_ips: - description: - - List of IP addresses allowed to access a service. - - Only used when C(access) is set to restricted. - type: list - -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Set icmp service to blocked - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: ICMP - access: blocked - delegate_to: localhost - -- name: Set icmp service to restricted - meraki_firewalled_services: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - service: web - access: restricted - allowed_ips: - - 192.0.1.1 - - 192.0.1.2 - delegate_to: localhost - -- name: Query appliance services - meraki_firewalled_services: - auth_key: abc123 - state: query - org_name: YourOrg - net_name: YourNet - delegate_to: localhost - -- name: Query services - meraki_firewalled_services: - auth_key: abc123 - state: query - org_name: YourOrg - net_name: YourNet - service: ICMP - delegate_to: localhost -''' - -RETURN = r''' -data: - description: List of network services. - returned: info - type: complex - contains: - access: - description: Access assigned to a service type. - returned: success - type: str - sample: unrestricted - service: - description: Service to apply policy to. - returned: success - type: str - sample: ICMP - allowed_ips: - description: List of IP addresses to have access to service. - returned: success - type: str - sample: 192.0.1.0 -''' - -from ansible.module_utils.basic import AnsibleModule, json -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - - argument_spec = meraki_argument_spec() - argument_spec.update( - net_id=dict(type='str'), - net_name=dict(type='str', aliases=['network']), - state=dict(type='str', default='present', choices=['query', 'present']), - service=dict(type='str', default=None, choices=['ICMP', 'SNMP', 'web']), - access=dict(type='str', choices=['blocked', 'restricted', 'unrestricted']), - allowed_ips=dict(type='list', elements='str'), - ) - - mutually_exclusive = [('net_name', 'net_id')] - - # 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, - mutually_exclusive=mutually_exclusive - ) - - meraki = MerakiModule(module, function='firewalled_services') - module.params['follow_redirects'] = 'all' - - net_services_urls = {'firewalled_services': '/networks/{net_id}/firewalledServices'} - services_urls = {'firewalled_services': '/networks/{net_id}/firewalledServices/{service}'} - - meraki.url_catalog['network_services'] = net_services_urls - meraki.url_catalog['service'] = services_urls - - # 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 not org_id: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(org_id, meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'present': - if meraki.params['access'] != 'restricted' and meraki.params['allowed_ips'] is not None: - meraki.fail_json(msg="allowed_ips is only allowed when access is restricted.") - payload = {'access': meraki.params['access']} - if meraki.params['access'] == 'restricted': - payload['allowedIps'] = meraki.params['allowed_ips'] - - if meraki.params['state'] == 'query': - if meraki.params['service'] is None: - path = meraki.construct_path('network_services', net_id=net_id) - response = meraki.request(path, method='GET') - meraki.result['data'] = response - meraki.exit_json(**meraki.result) - else: - path = meraki.construct_path('service', net_id=net_id, custom={'service': meraki.params['service']}) - response = meraki.request(path, method='GET') - meraki.result['data'] = response - meraki.exit_json(**meraki.result) - elif meraki.params['state'] == 'present': - path = meraki.construct_path('service', net_id=net_id, custom={'service': meraki.params['service']}) - original = meraki.request(path, method='GET') - if meraki.is_update_required(original, payload, optional_ignore=['service']): - if meraki.check_mode is True: - diff_payload = {'service': meraki.params['service']} # Need to add service as it's not in payload - diff_payload.update(payload) - diff = recursive_diff(original, diff_payload) - original.update(payload) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1]} - meraki.result['data'] = original - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - path = meraki.construct_path('service', net_id=net_id, custom={'service': meraki.params['service']}) - response = meraki.request(path, method='PUT', payload=json.dumps(payload)) - if meraki.status == 200: - diff = recursive_diff(original, response) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1]} - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_malware.py b/lib/ansible/modules/network/meraki/meraki_malware.py deleted file mode 100644 index 93de3202852..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_malware.py +++ /dev/null @@ -1,276 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Kevin Breit (@kbreit) -# 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_malware -short_description: Manage Malware Protection in the Meraki cloud -version_added: "2.9" -description: -- Fully configure malware protection in a Meraki environment. -notes: -- Some of the options are likely only used for developers within Meraki. -options: - state: - description: - - Specifies whether object should be queried, created/modified, or removed. - choices: [absent, present, query] - default: query - type: str - net_name: - description: - - Name of network which configuration is applied to. - aliases: [network] - type: str - net_id: - description: - - ID of network which configuration is applied to. - type: str - allowed_urls: - description: - - List of URLs to whitelist. - suboptions: - url: - description: - - URL string to allow. - type: str - comment: - description: - - Human readable information about URL. - type: str - allowed_files: - description: - - List of files to whitelist. - suboptions: - sha256: - description: - - 256-bit hash of file. - type: str - aliases: [ hash ] - comment: - description: - - Human readable information about file. - type: str - mode: - description: - - Enabled or disabled state of malware protection. - choices: [disabled, enabled] - - -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' - - name: Enable malware protection - meraki_malware: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - mode: enabled - delegate_to: localhost - - - name: Set whitelisted url - meraki_malware: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - mode: enabled - allowed_urls: - - url: www.google.com - comment: Google - delegate_to: localhost - - - name: Set whitelisted file - meraki_malware: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - mode: enabled - allowed_files: - - sha256: e82c5f7d75004727e1f3b94426b9a11c8bc4c312a9170ac9a73abace40aef503 - comment: random zip - delegate_to: localhost - - - name: Get malware settings - meraki_malware: - auth_key: abc123 - state: query - org_name: YourNet - net_name: YourOrg - delegate_to: localhost -''' - -RETURN = r''' -data: - description: List of administrators. - returned: success - type: complex - contains: - mode: - description: Mode to enable or disable malware scanning. - returned: success - type: str - sample: enabled - allowed_files: - description: List of files which are whitelisted. - returned: success - type: complex - contains: - sha256: - description: sha256 hash of whitelisted file. - returned: success - type: str - sample: e82c5f7d75004727e1f3b94426b9a11c8bc4c312a9170ac9a73abace40aef503 - comment: - description: Comment about the whitelisted entity - returned: success - type: str - sample: TPS report - allowed_urls: - description: List of URLs which are whitelisted. - returned: success - type: complex - contains: - url: - description: URL of whitelisted site. - returned: success - type: str - sample: site.com - comment: - description: Comment about the whitelisted entity - returned: success - type: str - sample: Corporate HQ -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils._text import to_native -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def main(): - # define the available arguments/parameters that a user can pass to - # the module - - urls_arg_spec = dict(url=dict(type='str'), - comment=dict(type='str'), - ) - - files_arg_spec = dict(sha256=dict(type='str', aliases=['hash']), - comment=dict(type='str'), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update(state=dict(type='str', choices=['absent', 'present', 'query'], default='query'), - net_name=dict(type='str', aliases=['network']), - net_id=dict(type='str'), - mode=dict(type='str', choices=['enabled', 'disabled']), - allowed_urls=dict(type='list', default=None, elements='dict', options=urls_arg_spec), - allowed_files=dict(type='list', default=None, elements='dict', options=files_arg_spec), - ) - - # 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='malware') - - meraki.params['follow_redirects'] = 'all' - - query_url = {'malware': '/networks/{net_id}/security/malwareSettings'} - update_url = {'malware': '/networks/{net_id}/security/malwareSettings'} - - meraki.url_catalog['get_one'].update(query_url) - meraki.url_catalog['update'] = update_url - - org_id = meraki.params['org_id'] - if org_id is None: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - - # Check for argument completeness - if meraki.params['state'] == 'present': - if meraki.params['allowed_files'] is not None or meraki.params['allowed_urls'] is not None: - if meraki.params['mode'] is None: - meraki.fail_json(msg="mode must be set when allowed_files or allowed_urls is set.") - - # Assemble payload - if meraki.params['state'] == 'present': - payload = dict() - if meraki.params['mode'] is not None: - payload['mode'] = meraki.params['mode'] - if meraki.params['allowed_urls'] is not None: - payload['allowedUrls'] = meraki.params['allowed_urls'] - if meraki.params['allowed_files'] is not None: - payload['allowedFiles'] = meraki.params['allowed_files'] - - if meraki.params['state'] == 'query': - path = meraki.construct_path('get_one', net_id=net_id) - data = meraki.request(path, method='GET') - if meraki.status == 200: - meraki.result['data'] = data - elif meraki.params['state'] == 'present': - path = meraki.construct_path('get_one', net_id=net_id) - original = meraki.request(path, method='GET') - if meraki.is_update_required(original, payload): - if meraki.module.check_mode is True: - diff = recursive_diff(original, payload) - original.update(payload) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1], - } - meraki.result['data'] = original - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - path = meraki.construct_path('update', net_id=net_id) - data = meraki.request(path, method='PUT', payload=json.dumps(payload)) - if meraki.status == 200: - diff = recursive_diff(original, payload) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1], - } - meraki.result['data'] = data - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_mr_l3_firewall.py b/lib/ansible/modules/network/meraki/meraki_mr_l3_firewall.py deleted file mode 100644 index 2b07373d959..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_mr_l3_firewall.py +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_mr_l3_firewall -short_description: Manage MR access point layer 3 firewalls in the Meraki cloud -version_added: "2.7" -description: -- Allows for creation, management, and visibility into layer 3 firewalls implemented on Meraki MR access points. -- Module is not idempotent as of current release. -options: - state: - description: - - Create or modify an organization. - type: str - choices: [ present, query ] - default: present - net_name: - description: - - Name of network containing access points. - type: str - net_id: - description: - - ID of network containing access points. - type: str - number: - description: - - Number of SSID to apply firewall rule to. - type: int - aliases: [ ssid_number ] - ssid_name: - description: - - Name of SSID to apply firewall rule to. - type: str - aliases: [ ssid ] - allow_lan_access: - description: - - Sets whether devices can talk to other devices on the same LAN. - type: bool - default: yes - rules: - description: - - List of firewall rules. - type: list - suboptions: - policy: - description: - - Specifies the action that should be taken when rule is hit. - type: str - choices: [ allow, deny ] - protocol: - description: - - Specifies protocol to match against. - type: str - choices: [ any, icmp, tcp, udp ] - dest_port: - description: - - Comma-seperated list of destination ports to match. - type: str - dest_cidr: - description: - - Comma-separated list of CIDR notation networks to match. - type: str - comment: - description: - - Optional comment describing the firewall rule. - type: str -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Create single firewall rule - meraki_mr_l3_firewall: - auth_key: abc123 - state: present - org_name: YourOrg - net_id: 12345 - number: 1 - rules: - - comment: Integration test rule - policy: allow - protocol: tcp - dest_port: 80 - dest_cidr: 192.0.2.0/24 - allow_lan_access: no - delegate_to: localhost - -- name: Enable local LAN access - meraki_mr_l3_firewall: - auth_key: abc123 - state: present - org_name: YourOrg - net_id: 123 - number: 1 - rules: - allow_lan_access: yes - delegate_to: localhost - -- name: Query firewall rules - meraki_mr_l3_firewall: - auth_key: abc123 - state: query - org_name: YourOrg - net_name: YourNet - number: 1 - delegate_to: localhost -''' - -RETURN = r''' - -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def assemble_payload(meraki): - params_map = {'policy': 'policy', - 'protocol': 'protocol', - 'dest_port': 'destPort', - 'dest_cidr': 'destCidr', - 'comment': 'comment', - } - rules = [] - for rule in meraki.params['rules']: - proposed_rule = dict() - for k, v in rule.items(): - proposed_rule[params_map[k]] = v - rules.append(proposed_rule) - payload = {'rules': rules} - return payload - - -def get_rules(meraki, net_id, number): - path = meraki.construct_path('get_all', net_id=net_id, custom={'number': number}) - response = meraki.request(path, method='GET') - if meraki.status == 200: - return response - - -def get_ssid_number(name, data): - for ssid in data: - if name == ssid['name']: - return ssid['number'] - return False - - -def get_ssids(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - return meraki.request(path, method='GET') - - -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), - ) - - # 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='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 - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - # FIXME: Work with Meraki so they can implement a check mode - if module.check_mode: - meraki.exit_json(**meraki.result) - - # 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'] - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_mx_l3_firewall.py b/lib/ansible/modules/network/meraki/meraki_mx_l3_firewall.py deleted file mode 100644 index db83164742a..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_mx_l3_firewall.py +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_l3_firewall -short_description: Manage MX appliance layer 3 firewalls in the Meraki cloud -version_added: "2.7" -description: -- Allows for creation, management, and visibility into layer 3 firewalls implemented on Meraki MX firewalls. -notes: -- Module assumes a complete list of firewall rules are passed as a parameter. -- If there is interest in this module allowing manipulation of a single firewall rule, please submit an issue against this module. -options: - state: - description: - - Create or modify an organization. - choices: ['present', 'query'] - default: present - net_name: - description: - - Name of network which MX firewall is in. - net_id: - description: - - ID of network which MX firewall is in. - rules: - description: - - List of firewall rules. - suboptions: - policy: - description: - - Policy to apply if rule is hit. - choices: [allow, deny] - protocol: - description: - - Protocol to match against. - choices: [any, icmp, tcp, udp] - dest_port: - description: - - Comma separated list of destination port numbers to match against. - dest_cidr: - description: - - Comma separated list of CIDR notation destination networks. - src_port: - description: - - Comma separated list of source port numbers to match against. - src_cidr: - description: - - Comma separated list of CIDR notation source networks. - comment: - description: - - Optional comment to describe the firewall rule. - syslog_enabled: - description: - - Whether to log hints against the firewall rule. - - Only applicable if a syslog server is specified against the network. - - syslog_default_rule: - description: - - Whether to log hits against the default firewall rule. - - Only applicable if a syslog server is specified against the network. - - This is not shown in response from Meraki. Instead, refer to the C(syslog_enabled) value in the default rule. - type: bool - default: no -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query firewall rules - meraki_mx_l3_firewall: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: query - delegate_to: localhost - -- name: Set two firewall rules - meraki_mx_l3_firewall: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - rules: - - comment: Block traffic to server - src_cidr: 192.0.1.0/24 - src_port: any - dest_cidr: 192.0.2.2/32 - dest_port: any - protocol: any - policy: deny - - comment: Allow traffic to group of servers - src_cidr: 192.0.1.0/24 - src_port: any - dest_cidr: 192.0.2.0/24 - dest_port: any - protocol: any - policy: permit - delegate_to: localhost - -- name: Set one firewall rule and enable logging of the default rule - meraki_mx_l3_firewall: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - rules: - - comment: Block traffic to server - src_cidr: 192.0.1.0/24 - src_port: any - dest_cidr: 192.0.2.2/32 - dest_port: any - protocol: any - policy: deny - syslog_default_rule: yes - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Firewall rules associated to network. - returned: success - type: complex - contains: - comment: - description: Comment to describe the firewall rule. - returned: always - type: str - sample: Block traffic to server - src_cidr: - description: Comma separated list of CIDR notation source networks. - returned: always - type: str - sample: 192.0.1.1/32,192.0.1.2/32 - src_port: - description: Comma separated list of source ports. - returned: always - type: str - sample: 80,443 - dest_cidr: - description: Comma separated list of CIDR notation destination networks. - returned: always - type: str - sample: 192.0.1.1/32,192.0.1.2/32 - dest_port: - description: Comma separated list of destination ports. - returned: always - type: str - sample: 80,443 - protocol: - description: Network protocol for which to match against. - returned: always - type: str - sample: tcp - policy: - description: Action to take when rule is matched. - returned: always - type: str - syslog_enabled: - description: Whether to log to syslog when rule is matched. - returned: always - type: bool - sample: true -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def assemble_payload(meraki): - params_map = {'policy': 'policy', - 'protocol': 'protocol', - 'dest_port': 'destPort', - 'dest_cidr': 'destCidr', - 'src_port': 'srcPort', - 'src_cidr': 'srcCidr', - 'syslog_enabled': 'syslogEnabled', - 'comment': 'comment', - } - rules = [] - for rule in meraki.params['rules']: - proposed_rule = dict() - for k, v in rule.items(): - proposed_rule[params_map[k]] = v - rules.append(proposed_rule) - payload = {'rules': rules} - return payload - - -def get_rules(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - response = meraki.request(path, method='GET') - if meraki.status == 200: - return response - - -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'), - ) - - # 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_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 - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - # FIXME: Work with Meraki so they can implement a check mode - if module.check_mode: - meraki.exit_json(**meraki.result) - - # 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)) - - 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']: - 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 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 - for r in range(len(rules) - 1): - 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: - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py b/lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py deleted file mode 100644 index f8f87a2eafa..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py +++ /dev/null @@ -1,506 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Kevin Breit (@kbreit) -# 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_l7_firewall -short_description: Manage MX appliance layer 7 firewalls in the Meraki cloud -version_added: "2.9" -description: -- Allows for creation, management, and visibility into layer 7 firewalls implemented on Meraki MX firewalls. -notes: -- Module assumes a complete list of firewall rules are passed as a parameter. -- If there is interest in this module allowing manipulation of a single firewall rule, please submit an issue against this module. -options: - state: - description: - - Query or modify a firewall rule. - 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 - rules: - description: - - List of layer 7 firewall rules. - type: list - suboptions: - policy: - description: - - Policy to apply if rule is hit. - choices: [deny] - default: deny - type: str - type: - description: - - Type of policy to apply. - choices: [application, - application_category, - blacklisted_countries, - host, - ip_range, - port, - whitelisted_countries] - type: str - application: - description: - - Application to filter. - suboptions: - name: - description: - - Name of application to filter as defined by Meraki. - type: str - id: - description: - - URI of application as defined by Meraki. - type: str - application_category: - description: - - Category of applications to filter. - suboptions: - name: - description: - - Name of application category to filter as defined by Meraki. - type: str - id: - description: - - URI of application category as defined by Meraki. - type: str - host: - description: - - FQDN of host to filter. - type: str - ip_range: - description: - - CIDR notation range of IP addresses to apply rule to. - - Port can be appended to range with a C(":"). - type: str - port: - description: - - TCP or UDP based port to filter. - type: str - countries: - description: - - List of countries to whitelist or blacklist. - - The countries follow the two-letter ISO 3166-1 alpha-2 format. - type: list - categories: - description: - - When C(True), specifies that applications and application categories should be queried instead of firewall rules. - type: bool -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query firewall rules - meraki_mx_l7_firewall: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: query - delegate_to: localhost - -- name: Query applications and application categories - meraki_mx_l7_firewall: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - categories: yes - state: query - delegate_to: localhost - -- name: Set firewall rules - meraki_mx_l7_firewall: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - rules: - - type: whitelisted_countries - countries: - - US - - FR - - type: blacklisted_countries - countries: - - CN - - policy: deny - type: port - port: 8080 - - type: port - port: 1234 - - type: host - host: asdf.com - - type: application - application: - id: meraki:layer7/application/205 - - type: application_category - application: - id: meraki:layer7/category/24 - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Firewall rules associated to network. - returned: success - type: complex - contains: - rules: - description: Ordered list of firewall rules. - returned: success, when not querying applications - type: list - contains: - policy: - description: Action to apply when rule is hit. - returned: success - type: str - sample: deny - type: - description: Type of rule category. - returned: success - type: str - sample: applications - applications: - description: List of applications within a category. - type: list - contains: - id: - description: URI of application. - returned: success - type: str - sample: Gmail - name: - description: Descriptive name of application. - returned: success - type: str - sample: meraki:layer7/application/4 - applicationCategory: - description: List of application categories within a category. - type: list - contains: - id: - description: URI of application. - returned: success - type: str - sample: Gmail - name: - description: Descriptive name of application. - returned: success - type: str - sample: meraki:layer7/application/4 - port: - description: Port number in rule. - returned: success - type: str - sample: 23 - ipRange: - description: Range of IP addresses in rule. - returned: success - type: str - sample: 1.1.1.0/23 - whitelistedCountries: - description: Countries to be whitelisted. - returned: success - type: str - sample: CA - blacklistedCountries: - description: Countries to be blacklisted. - returned: success - type: str - sample: RU - application_categories: - description: List of application categories and applications. - type: list - returned: success, when querying applications - contains: - applications: - description: List of applications within a category. - type: list - contains: - id: - description: URI of application. - returned: success - type: str - sample: Gmail - name: - description: Descriptive name of application. - returned: success - type: str - sample: meraki:layer7/application/4 - id: - description: URI of application category. - returned: success - type: str - sample: Email - name: - description: Descriptive name of application category. - returned: success - type: str - sample: layer7/category/1 -''' - -import copy -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_applications(meraki, net_id): - path = meraki.construct_path('get_categories', net_id=net_id) - return meraki.request(path, method='GET') - - -def lookup_application(meraki, net_id, application): - response = get_applications(meraki, net_id) - for category in response['applicationCategories']: - if category['name'].lower() == application.lower(): - return category['id'] - for app in category['applications']: - if app['name'].lower() == application.lower(): - return app['id'] - meraki.fail_json(msg="No application or category named {0} found".format(application)) - - -def assemble_payload(meraki, net_id, rule): - if rule['type'] == 'application': - new_rule = {'policy': rule['policy'], - 'type': 'application', - } - if rule['application']['id']: - new_rule['value'] = {'id': rule['application']['id']} - elif rule['application']['name']: - new_rule['value'] = {'id': lookup_application(meraki, net_id, rule['application']['name'])} - elif rule['type'] == 'application_category': - new_rule = {'policy': rule['policy'], - 'type': 'applicationCategory', - } - if rule['application']['id']: - new_rule['value'] = {'id': rule['application']['id']} - elif rule['application']['name']: - new_rule['value'] = {'id': lookup_application(meraki, net_id, rule['application']['name'])} - elif rule['type'] == 'ip_range': - new_rule = {'policy': rule['policy'], - 'type': 'ipRange', - 'value': rule['ip_range']} - elif rule['type'] == 'host': - new_rule = {'policy': rule['policy'], - 'type': rule['type'], - 'value': rule['host']} - elif rule['type'] == 'port': - new_rule = {'policy': rule['policy'], - 'type': rule['type'], - 'value': rule['port']} - elif rule['type'] == 'blacklisted_countries': - new_rule = {'policy': rule['policy'], - 'type': 'blacklistedCountries', - 'value': rule['countries'] - } - elif rule['type'] == 'whitelisted_countries': - new_rule = {'policy': rule['policy'], - 'type': 'whitelistedCountries', - 'value': rule['countries'] - } - return new_rule - - -def restructure_response(rules): - for rule in rules['rules']: - type = rule['type'] - rule[type] = copy.deepcopy(rule['value']) - del rule['value'] - return rules - - -def get_rules(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - response = meraki.request(path, method='GET') - if meraki.status == 200: - return response - - -def rename_id_to_appid(rules): - for rule in rules['rules']: - print(rule['type']) - if rule['type'] == 'application' or rule['type'] == 'applicationCategory': - rule['value']['appId'] = rule['value'].pop('id') - return rules - - -def rename_appid_to_id(rules): - for rule in rules['rules']: - if rule['type'] == 'application' or rule['type'] == 'applicationCategory': - rule['value']['id'] = rule['value'].pop('appId') - return rules - - -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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_nat.py b/lib/ansible/modules/network/meraki/meraki_nat.py deleted file mode 100644 index 69c2f7e6573..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_nat.py +++ /dev/null @@ -1,673 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Kevin Breit (@kbreit) -# 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_nat -short_description: Manage NAT rules in Meraki cloud -version_added: "2.9" -description: -- Allows for creation, management, and visibility of NAT rules (1:1, 1:many, port forwarding) within Meraki. - -options: - state: - description: - - Create or modify an organization. - choices: [present, query] - default: present - type: str - net_name: - description: - - Name of a network. - aliases: [name, network] - type: str - net_id: - description: - - ID number of a network. - type: str - org_id: - description: - - ID of organization associated to a network. - type: str - subset: - description: - - Specifies which NAT components to query. - choices: ['1:1', '1:many', all, port_forwarding] - default: all - type: list - one_to_one: - description: - - List of 1:1 NAT rules. - type: list - suboptions: - name: - description: - - A descriptive name for the rule. - type: str - public_ip: - description: - - The IP address that will be used to access the internal resource from the WAN. - type: str - lan_ip: - description: - - The IP address of the server or device that hosts the internal resource that you wish to make available on the WAN. - type: str - uplink: - description: - - The physical WAN interface on which the traffic will arrive. - choices: [both, internet1, internet2] - type: str - allowed_inbound: - description: - - The ports this mapping will provide access on, and the remote IPs that will be allowed access to the resource. - type: list - suboptions: - protocol: - description: - - Protocol to apply NAT rule to. - choices: [any, icmp-ping, tcp, udp] - type: str - default: any - destination_ports: - description: - - List of ports or port ranges that will be forwarded to the host on the LAN. - type: list - allowed_ips: - description: - - ranges of WAN IP addresses that are allowed to make inbound connections on the specified ports or port ranges, or 'any'. - type: list - one_to_many: - description: - - List of 1:many NAT rules. - type: list - suboptions: - public_ip: - description: - - The IP address that will be used to access the internal resource from the WAN. - type: str - uplink: - description: - - The physical WAN interface on which the traffic will arrive. - choices: [both, internet1, internet2] - type: str - port_rules: - description: - - List of associated port rules. - type: list - suboptions: - name: - description: - - A description of the rule. - type: str - protocol: - description: - - Protocol to apply NAT rule to. - choices: [tcp, udp] - type: str - public_port: - description: - - Destination port of the traffic that is arriving on the WAN. - type: str - local_ip: - description: - - Local IP address to which traffic will be forwarded. - type: str - local_port: - description: - - Destination port of the forwarded traffic that will be sent from the MX to the specified host on the LAN. - - If you simply wish to forward the traffic without translating the port, this should be the same as the Public port. - type: str - allowed_ips: - description: - - Remote IP addresses or ranges that are permitted to access the internal resource via this port forwarding rule, or 'any'. - type: list - port_forwarding: - description: - - List of port forwarding rules. - type: list - suboptions: - name: - description: - - A descriptive name for the rule. - type: str - lan_ip: - description: - - The IP address of the server or device that hosts the internal resource that you wish to make available on the WAN. - type: str - uplink: - description: - - The physical WAN interface on which the traffic will arrive. - choices: [both, internet1, internet2] - type: str - public_port: - description: - - A port or port ranges that will be forwarded to the host on the LAN. - type: int - local_port: - description: - - A port or port ranges that will receive the forwarded traffic from the WAN. - type: int - allowed_ips: - description: - - List of ranges of WAN IP addresses that are allowed to make inbound connections on the specified ports or port ranges (or any). - type: list - protocol: - description: - - Protocol to forward traffic for. - choices: [tcp, udp] - type: str - -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query all NAT rules - meraki_nat: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: query - subset: all - delegate_to: localhost - -- name: Query 1:1 NAT rules - meraki_nat: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: query - subset: '1:1' - delegate_to: localhost - -- name: Create 1:1 rule - meraki_nat: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - one_to_one: - - name: Service behind NAT - public_ip: 1.2.1.2 - lan_ip: 192.168.128.1 - uplink: internet1 - allowed_inbound: - - protocol: tcp - destination_ports: - - 80 - allowed_ips: - - 10.10.10.10 - delegate_to: localhost - -- name: Create 1:many rule - meraki_nat: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - one_to_many: - - public_ip: 1.1.1.1 - uplink: internet1 - port_rules: - - name: Test rule - protocol: tcp - public_port: 10 - local_ip: 192.168.128.1 - local_port: 11 - allowed_ips: - - any - delegate_to: localhost - -- name: Create port forwarding rule - meraki_nat: - auth_key: abc123 - org_name: YourOrg - net_name: YourNet - state: present - port_forwarding: - - name: Test map - lan_ip: 192.168.128.1 - uplink: both - protocol: tcp - allowed_ips: - - 1.1.1.1 - public_port: 10 - local_port: 11 - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information about the created or manipulated object. - returned: success - type: complex - contains: - one_to_one: - description: Information about 1:1 NAT object. - returned: success, when 1:1 NAT object is in task - type: complex - contains: - rules: - description: List of 1:1 NAT rules. - returned: success, when 1:1 NAT object is in task - type: complex - contains: - name: - description: Name of NAT object. - returned: success, when 1:1 NAT object is in task - type: str - example: Web server behind NAT - lanIp: - description: Local IP address to be mapped. - returned: success, when 1:1 NAT object is in task - type: str - example: 192.168.128.22 - publicIp: - description: Public IP address to be mapped. - returned: success, when 1:1 NAT object is in task - type: str - example: 148.2.5.100 - uplink: - description: Internet port where rule is applied. - returned: success, when 1:1 NAT object is in task - type: str - example: internet1 - allowedInbound: - description: List of inbound forwarding rules. - returned: success, when 1:1 NAT object is in task - type: complex - contains: - protocol: - description: Protocol to apply NAT rule to. - returned: success, when 1:1 NAT object is in task - type: str - example: tcp - destinationPorts: - description: Ports to apply NAT rule to. - returned: success, when 1:1 NAT object is in task - type: str - example: 80 - allowedIps: - description: List of IP addresses to be forwarded. - returned: success, when 1:1 NAT object is in task - type: list - example: 10.80.100.0/24 - one_to_many: - description: Information about 1:many NAT object. - returned: success, when 1:many NAT object is in task - type: complex - contains: - rules: - description: List of 1:many NAT rules. - returned: success, when 1:many NAT object is in task - type: complex - contains: - publicIp: - description: Public IP address to be mapped. - returned: success, when 1:many NAT object is in task - type: str - example: 148.2.5.100 - uplink: - description: Internet port where rule is applied. - returned: success, when 1:many NAT object is in task - type: str - example: internet1 - portRules: - description: List of NAT port rules. - returned: success, when 1:many NAT object is in task - type: complex - contains: - name: - description: Name of NAT object. - returned: success, when 1:many NAT object is in task - type: str - example: Web server behind NAT - protocol: - description: Protocol to apply NAT rule to. - returned: success, when 1:1 NAT object is in task - type: str - example: tcp - publicPort: - description: Destination port of the traffic that is arriving on WAN. - returned: success, when 1:1 NAT object is in task - type: int - example: 9443 - localIp: - description: Local IP address traffic will be forwarded. - returned: success, when 1:1 NAT object is in task - type: str - example: 192.0.2.10 - localPort: - description: Destination port to be forwarded to. - returned: success, when 1:1 NAT object is in task - type: int - example: 443 - allowedIps: - description: List of IP addresses to be forwarded. - returned: success, when 1:1 NAT object is in task - type: list - example: 10.80.100.0/24 - port_forwarding: - description: Information about port forwarding rules. - returned: success, when port forwarding is in task - type: complex - contains: - rules: - description: List of port forwarding rules. - returned: success, when port forwarding is in task - type: complex - contains: - lanIp: - description: Local IP address to be mapped. - returned: success, when port forwarding is in task - type: str - example: 192.168.128.22 - allowedIps: - description: List of IP addresses to be forwarded. - returned: success, when port forwarding is in task - type: list - example: 10.80.100.0/24 - name: - description: Name of NAT object. - returned: success, when port forwarding is in task - type: str - example: Web server behind NAT - protocol: - description: Protocol to apply NAT rule to. - returned: success, when port forwarding is in task - type: str - example: tcp - publicPort: - description: Destination port of the traffic that is arriving on WAN. - returned: success, when port forwarding is in task - type: int - example: 9443 - localPort: - description: Destination port to be forwarded to. - returned: success, when port forwarding is in task - type: int - example: 443 - uplink: - description: Internet port where rule is applied. - returned: success, when port forwarding is in task - type: str - example: internet1 -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - -key_map = {'name': 'name', - 'public_ip': 'publicIp', - 'lan_ip': 'lanIp', - 'uplink': 'uplink', - 'allowed_inbound': 'allowedInbound', - 'protocol': 'protocol', - 'destination_ports': 'destinationPorts', - 'allowed_ips': 'allowedIps', - 'port_rules': 'portRules', - 'public_port': 'publicPort', - 'local_ip': 'localIp', - 'local_port': 'localPort', - } - - -def construct_payload(params): - if isinstance(params, list): - items = [] - for item in params: - items.append(construct_payload(item)) - return items - elif isinstance(params, dict): - info = {} - for param in params: - info[key_map[param]] = construct_payload(params[param]) - return info - elif isinstance(params, str) or isinstance(params, int): - return params - - -def list_int_to_str(data): - return [str(item) for item in data] - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - - one_to_one_allowed_inbound_spec = dict(protocol=dict(type='str', choices=['tcp', 'udp', 'icmp-ping', 'any'], default='any'), - destination_ports=dict(type='list', element='str'), - allowed_ips=dict(type='list'), - ) - - one_to_many_port_inbound_spec = dict(protocol=dict(type='str', choices=['tcp', 'udp']), - name=dict(type='str'), - local_ip=dict(type='str'), - local_port=dict(type='str'), - allowed_ips=dict(type='list'), - public_port=dict(type='str'), - ) - - one_to_one_spec = dict(name=dict(type='str'), - public_ip=dict(type='str'), - lan_ip=dict(type='str'), - uplink=dict(type='str', choices=['internet1', 'internet2', 'both']), - allowed_inbound=dict(type='list', element='dict', options=one_to_one_allowed_inbound_spec), - ) - - one_to_many_spec = dict(public_ip=dict(type='str'), - uplink=dict(type='str', choices=['internet1', 'internet2', 'both']), - port_rules=dict(type='list', element='dict', options=one_to_many_port_inbound_spec), - ) - - port_forwarding_spec = dict(name=dict(type='str'), - lan_ip=dict(type='str'), - uplink=dict(type='str', choices=['internet1', 'internet2', 'both']), - protocol=dict(type='str', choices=['tcp', 'udp']), - public_port=dict(type='int'), - local_port=dict(type='int'), - allowed_ips=dict(type='list'), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update( - net_id=dict(type='str'), - net_name=dict(type='str', aliases=['name', 'network']), - state=dict(type='str', choices=['present', 'query'], default='present'), - subset=dict(type='list', choices=['1:1', '1:many', 'all', 'port_forwarding'], default='all'), - one_to_one=dict(type='list', elements='dict', options=one_to_one_spec), - one_to_many=dict(type='list', elements='dict', options=one_to_many_spec), - port_forwarding=dict(type='list', elements='dict', options=port_forwarding_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='nat') - module.params['follow_redirects'] = 'all' - - one_to_one_payload = None - one_to_many_payload = None - port_forwarding_payload = None - if meraki.params['state'] == 'present': - if meraki.params['one_to_one'] is not None: - rules = [] - for i in meraki.params['one_to_one']: - data = {'name': i['name'], - 'publicIp': i['public_ip'], - 'uplink': i['uplink'], - 'lanIp': i['lan_ip'], - 'allowedInbound': construct_payload(i['allowed_inbound']) - } - for inbound in data['allowedInbound']: - inbound['destinationPorts'] = list_int_to_str(inbound['destinationPorts']) - rules.append(data) - one_to_one_payload = {'rules': rules} - if meraki.params['one_to_many'] is not None: - rules = [] - for i in meraki.params['one_to_many']: - data = {'publicIp': i['public_ip'], - 'uplink': i['uplink'], - } - port_rules = [] - for port_rule in i['port_rules']: - rule = {'name': port_rule['name'], - 'protocol': port_rule['protocol'], - 'publicPort': str(port_rule['public_port']), - 'localIp': port_rule['local_ip'], - 'localPort': str(port_rule['local_port']), - 'allowedIps': port_rule['allowed_ips'], - } - port_rules.append(rule) - data['portRules'] = port_rules - rules.append(data) - one_to_many_payload = {'rules': rules} - if meraki.params['port_forwarding'] is not None: - port_forwarding_payload = {'rules': construct_payload(meraki.params['port_forwarding'])} - for rule in port_forwarding_payload['rules']: - rule['localPort'] = str(rule['localPort']) - rule['publicPort'] = str(rule['publicPort']) - - onetomany_urls = {'nat': '/networks/{net_id}/oneToManyNatRules'} - onetoone_urls = {'nat': '/networks/{net_id}/oneToOneNatRules'} - port_forwarding_urls = {'nat': '/networks/{net_id}/portForwardingRules'} - meraki.url_catalog['1:many'] = onetomany_urls - meraki.url_catalog['1:1'] = onetoone_urls - meraki.url_catalog['port_forwarding'] = port_forwarding_urls - - if meraki.params['net_name'] and meraki.params['net_id']: - meraki.fail_json(msg='net_name and net_id are mutually exclusive') - - org_id = meraki.params['org_id'] - if not org_id: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(org_id, meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - if meraki.params['subset'][0] == 'all': - path = meraki.construct_path('1:many', net_id=net_id) - data = {'1:many': meraki.request(path, method='GET')} - path = meraki.construct_path('1:1', net_id=net_id) - data['1:1'] = meraki.request(path, method='GET') - path = meraki.construct_path('port_forwarding', net_id=net_id) - data['port_forwarding'] = meraki.request(path, method='GET') - meraki.result['data'] = data - else: - for subset in meraki.params['subset']: - path = meraki.construct_path(subset, net_id=net_id) - data = {subset: meraki.request(path, method='GET')} - try: - meraki.result['data'][subset] = data - except KeyError: - meraki.result['data'] = {subset: data} - elif meraki.params['state'] == 'present': - meraki.result['data'] = dict() - if one_to_one_payload is not None: - path = meraki.construct_path('1:1', net_id=net_id) - current = meraki.request(path, method='GET') - if meraki.is_update_required(current, one_to_one_payload): - if meraki.module.check_mode is True: - diff = recursive_diff(current, one_to_one_payload) - current.update(one_to_one_payload) - if 'diff' not in meraki.result: - meraki.result['diff'] = {'before': {}, 'after': {}} - meraki.result['diff']['before'].update({'one_to_one': diff[0]}) - meraki.result['diff']['after'].update({'one_to_one': diff[1]}) - meraki.result['data'] = {'one_to_one': current} - meraki.result['changed'] = True - else: - r = meraki.request(path, method='PUT', payload=json.dumps(one_to_one_payload)) - if meraki.status == 200: - diff = recursive_diff(current, one_to_one_payload) - if 'diff' not in meraki.result: - meraki.result['diff'] = {'before': {}, 'after': {}} - meraki.result['diff']['before'].update({'one_to_one': diff[0]}) - meraki.result['diff']['after'].update({'one_to_one': diff[1]}) - meraki.result['data'] = {'one_to_one': r} - meraki.result['changed'] = True - else: - meraki.result['data']['one_to_one'] = current - if one_to_many_payload is not None: - path = meraki.construct_path('1:many', net_id=net_id) - current = meraki.request(path, method='GET') - if meraki.is_update_required(current, one_to_many_payload): - if meraki.module.check_mode is True: - diff = recursive_diff(current, one_to_many_payload) - current.update(one_to_many_payload) - if 'diff' not in meraki.result: - meraki.result['diff'] = {'before': {}, 'after': {}} - meraki.result['diff']['before'].update({'one_to_many': diff[0]}) - meraki.result['diff']['after'].update({'one_to_many': diff[1]}) - meraki.result['data']['one_to_many'] = current - meraki.result['changed'] = True - else: - r = meraki.request(path, method='PUT', payload=json.dumps(one_to_many_payload)) - if meraki.status == 200: - diff = recursive_diff(current, one_to_many_payload) - if 'diff' not in meraki.result: - meraki.result['diff'] = {'before': {}, 'after': {}} - meraki.result['diff']['before'].update({'one_to_many': diff[0]}) - meraki.result['diff']['after'].update({'one_to_many': diff[1]}) - meraki.result['data'].update({'one_to_many': r}) - meraki.result['changed'] = True - else: - meraki.result['data']['one_to_many'] = current - if port_forwarding_payload is not None: - path = meraki.construct_path('port_forwarding', net_id=net_id) - current = meraki.request(path, method='GET') - if meraki.is_update_required(current, port_forwarding_payload): - if meraki.module.check_mode is True: - diff = recursive_diff(current, port_forwarding_payload) - current.update(port_forwarding_payload) - if 'diff' not in meraki.result: - meraki.result['diff'] = {'before': {}, 'after': {}} - meraki.result['diff']['before'].update({'port_forwarding': diff[0]}) - meraki.result['diff']['after'].update({'port_forwarding': diff[1]}) - meraki.result['data']['port_forwarding'] = current - meraki.result['changed'] = True - else: - r = meraki.request(path, method='PUT', payload=json.dumps(port_forwarding_payload)) - if meraki.status == 200: - if 'diff' not in meraki.result: - meraki.result['diff'] = {'before': {}, 'after': {}} - diff = recursive_diff(current, port_forwarding_payload) - meraki.result['diff']['before'].update({'port_forwarding': diff[0]}) - meraki.result['diff']['after'].update({'port_forwarding': diff[1]}) - meraki.result['data'].update({'port_forwarding': r}) - meraki.result['changed'] = True - else: - meraki.result['data']['port_forwarding'] = current - - # 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() diff --git a/lib/ansible/modules/network/meraki/meraki_network.py b/lib/ansible/modules/network/meraki/meraki_network.py deleted file mode 100644 index 3863b5d163c..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_network.py +++ /dev/null @@ -1,390 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, 2019 Kevin Breit (@kbreit) -# 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_network -short_description: Manage networks in the Meraki cloud -version_added: "2.6" -description: -- Allows for creation, management, and visibility into networks within Meraki. - -options: - state: - description: - - Create or modify an organization. - choices: [ absent, present, query ] - default: present - net_name: - description: - - Name of a network. - aliases: [ name, network ] - net_id: - description: - - ID number of a network. - type: - description: - - Type of network device network manages. - - Required when creating a network. - - As of Ansible 2.8, C(combined) type is no longer accepted. - - As of Ansible 2.8, changes to this parameter are no longer idempotent. - choices: [ appliance, switch, wireless ] - aliases: [ net_type ] - type: list - tags: - type: list - description: - - List of tags to assign to network. - - C(tags) name conflicts with the tags parameter in Ansible. Indentation problems may cause unexpected behaviors. - - Ansible 2.8 converts this to a list from a comma separated list. - timezone: - description: - - Timezone associated to network. - - See U(https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for a list of valid timezones. - enable_vlans: - description: - - Boolean value specifying whether VLANs should be supported on a network. - - Requires C(net_name) or C(net_id) to be specified. - type: bool - version_added: '2.9' - disable_my_meraki: - description: > - - Disables the local device status pages (U[my.meraki.com](my.meraki.com), U[ap.meraki.com](ap.meraki.com), U[switch.meraki.com](switch.meraki.com), - U[wired.meraki.com](wired.meraki.com)). - - Mutually exclusive of C(enable_my_meraki). - - Will be deprecated in Ansible 2.13 in favor of C(enable_my_meraki). - type: bool - version_added: '2.7' - enable_my_meraki: - description: > - - Enables the local device status pages (U[my.meraki.com](my.meraki.com), U[ap.meraki.com](ap.meraki.com), U[switch.meraki.com](switch.meraki.com), - U[wired.meraki.com](wired.meraki.com)). - - Ansible 2.7 had this parameter as C(disable_my_meraki). - type: bool - version_added: '2.9' - enable_remote_status_page: - description: - - Enables access to the device status page (U(http://device LAN IP)). - - Can only be set if C(enable_my_meraki:) is set to C(yes). - type: bool - version_added: '2.9' - -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- delegate_to: localhost - block: - - name: List all networks associated to the YourOrg organization - meraki_network: - auth_key: abc12345 - state: query - org_name: YourOrg - - name: Query network named MyNet in the YourOrg organization - meraki_network: - auth_key: abc12345 - state: query - org_name: YourOrg - net_name: MyNet - - name: Create network named MyNet in the YourOrg organization - meraki_network: - auth_key: abc12345 - state: present - org_name: YourOrg - net_name: MyNet - type: switch - timezone: America/Chicago - tags: production, chicago - - name: Create combined network named MyNet in the YourOrg organization - meraki_network: - auth_key: abc12345 - state: present - org_name: YourOrg - net_name: MyNet - type: - - switch - - appliance - timezone: America/Chicago - tags: production, chicago - - name: Enable VLANs on a network - meraki_network: - auth_key: abc12345 - state: query - org_name: YourOrg - net_name: MyNet - enable_vlans: yes -''' - -RETURN = r''' -data: - description: Information about the created or manipulated object. - returned: info - type: complex - contains: - id: - description: Identification string of network. - returned: success - type: str - sample: N_12345 - name: - description: Written name of network. - returned: success - type: str - sample: YourNet - organization_id: - description: Organization ID which owns the network. - returned: success - type: str - sample: 0987654321 - tags: - description: Space delimited tags assigned to network. - returned: success - type: str - sample: " production wireless " - time_zone: - description: Timezone where network resides. - returned: success - type: str - sample: America/Chicago - type: - description: Functional type of network. - returned: success - type: str - sample: switch - disable_my_meraki_com: - description: States whether U(my.meraki.com) and other device portals should be disabled. - returned: success - type: bool - sample: true - disableRemoteStatusPage: - description: Disables access to the device status page. - returned: success - type: bool - sample: true -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def is_net_valid(data, net_name=None, net_id=None): - if net_name is None and net_id is None: - return False - for n in data: - if net_name: - if n['name'] == net_name: - return True - elif net_id: - if n['id'] == net_id: - return True - return False - - -def construct_tags(tags): - formatted_tags = ' '.join(tags) - return ' {0} '.format(formatted_tags) # Meraki needs space padding - - -def list_to_string(data): - new_string = str() - for i, item in enumerate(data): - if i == len(new_string) - 1: - new_string += i - else: - new_string = "{0}{1} ".format(new_string, item) - return new_string.strip() - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - - argument_spec = meraki_argument_spec() - argument_spec.update( - net_id=dict(type='str'), - type=dict(type='list', choices=['wireless', 'switch', 'appliance'], aliases=['net_type']), - tags=dict(type='list'), - timezone=dict(type='str'), - net_name=dict(type='str', aliases=['name', 'network']), - state=dict(type='str', choices=['present', 'query', 'absent'], default='present'), - enable_vlans=dict(type='bool'), - disable_my_meraki=dict(type='bool', removed_in_version=2.13), - enable_my_meraki=dict(type='bool'), - enable_remote_status_page=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=False, - mutually_exclusive=[('disable_my_meraki', 'enable_my_meraki'), - ] - ) - - meraki = MerakiModule(module, function='network') - module.params['follow_redirects'] = 'all' - payload = None - - create_urls = {'network': '/organizations/{org_id}/networks'} - update_urls = {'network': '/networks/{net_id}'} - delete_urls = {'network': '/networks/{net_id}'} - enable_vlans_urls = {'network': '/networks/{net_id}/vlansEnabledState'} - get_vlan_status_urls = {'network': '/networks/{net_id}/vlansEnabledState'} - meraki.url_catalog['create'] = create_urls - meraki.url_catalog['update'] = update_urls - meraki.url_catalog['delete'] = delete_urls - meraki.url_catalog['enable_vlans'] = enable_vlans_urls - meraki.url_catalog['status_vlans'] = get_vlan_status_urls - - if not meraki.params['org_name'] and not meraki.params['org_id']: - meraki.fail_json(msg='org_name or org_id parameters are required') - if meraki.params['state'] != 'query': - if not meraki.params['net_name'] and not meraki.params['net_id']: - meraki.fail_json(msg='net_name or net_id is required for present or absent states') - if meraki.params['net_name'] and meraki.params['net_id']: - meraki.fail_json(msg='net_name and net_id are mutually exclusive') - if not meraki.params['net_name'] and not meraki.params['net_id']: - if meraki.params['enable_vlans']: - meraki.fail_json(msg="The parameter 'enable_vlans' requires 'net_name' or 'net_id' to be specified") - if meraki.params['enable_my_meraki'] is True and meraki.params['enable_remote_status_page'] is False: - meraki.fail_json(msg='enable_my_meraki must be true when setting enable_remote_status_page') - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - if module.check_mode: - return meraki.result - - # Construct payload - if meraki.params['state'] == 'present': - payload = dict() - if meraki.params['net_name']: - payload['name'] = meraki.params['net_name'] - if meraki.params['type']: - payload['type'] = list_to_string(meraki.params['type']) - if meraki.params['tags']: - payload['tags'] = construct_tags(meraki.params['tags']) - if meraki.params['timezone']: - payload['timeZone'] = meraki.params['timezone'] - if meraki.params['enable_my_meraki'] is not None: - if meraki.params['enable_my_meraki'] is True: - payload['disableMyMerakiCom'] = False - else: - payload['disableMyMerakiCom'] = True - elif meraki.params['disable_my_meraki'] is not None: - payload['disableMyMerakiCom'] = meraki.params['disable_my_meraki'] - if meraki.params['enable_remote_status_page'] is not None: - if meraki.params['enable_remote_status_page'] is True: - payload['disableRemoteStatusPage'] = False - # meraki.fail_json(msg="Debug", payload=payload) - else: - payload['disableRemoteStatusPage'] = True - - # 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 not org_id: - org_id = meraki.get_org_id(meraki.params['org_name']) - nets = meraki.get_nets(org_id=org_id) - - # check if network is created - net_id = meraki.params['net_id'] - net_exists = False - if net_id is not None: - if is_net_valid(nets, net_id=net_id) is False: - meraki.fail_json(msg="Network specified by net_id does not exist.") - net_exists = True - elif meraki.params['net_name']: - if is_net_valid(nets, net_name=meraki.params['net_name']) is True: - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - net_exists = True - - if meraki.params['state'] == 'query': - if not meraki.params['net_name'] and not meraki.params['net_id']: - meraki.result['data'] = nets - elif meraki.params['net_name'] or meraki.params['net_id'] is not None: - meraki.result['data'] = meraki.get_net(meraki.params['org_name'], - meraki.params['net_name'], - data=nets - ) - elif meraki.params['state'] == 'present': - if net_exists is False: # Network needs to be created - if 'type' not in meraki.params or meraki.params['type'] is None: - meraki.fail_json(msg="type parameter is required when creating a network.") - path = meraki.construct_path('create', - org_id=org_id - ) - r = meraki.request(path, - method='POST', - payload=json.dumps(payload) - ) - if meraki.status == 201: - meraki.result['data'] = r - meraki.result['changed'] = True - else: # Network exists, make changes - # meraki.fail_json(msg="nets", nets=nets, net_id=net_id) - # meraki.fail_json(msg="compare", original=net, payload=payload) - if meraki.params['enable_vlans'] is not None: # Modify VLANs configuration - status_path = meraki.construct_path('status_vlans', net_id=net_id) - status = meraki.request(status_path, method='GET') - payload = {'enabled': meraki.params['enable_vlans']} - # meraki.fail_json(msg="here", payload=payload) - if meraki.is_update_required(status, payload): - path = meraki.construct_path('enable_vlans', net_id=net_id) - r = meraki.request(path, - method='PUT', - payload=json.dumps(payload)) - if meraki.status == 200: - meraki.result['data'] = r - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - else: - meraki.result['data'] = status - meraki.exit_json(**meraki.result) - net = meraki.get_net(meraki.params['org_name'], net_id=net_id, data=nets) - if meraki.is_update_required(net, payload): - path = meraki.construct_path('update', net_id=net_id) - # meraki.fail_json(msg="Payload", path=path, payload=payload) - r = meraki.request(path, - method='PUT', - payload=json.dumps(payload)) - if meraki.status == 200: - meraki.result['data'] = r - meraki.result['changed'] = True - else: - meraki.result['data'] = net - elif meraki.params['state'] == 'absent': - if is_net_valid(nets, net_id=net_id) is True: - path = meraki.construct_path('delete', net_id=net_id) - r = meraki.request(path, method='DELETE') - if meraki.status == 204: - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_organization.py b/lib/ansible/modules/network/meraki/meraki_organization.py deleted file mode 100644 index 85a644a5af8..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_organization.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_organization -short_description: Manage organizations in the Meraki cloud -version_added: "2.6" -description: -- Allows for creation, management, and visibility into organizations within Meraki. -options: - state: - description: - - Create or modify an organization. - - C(org_id) must be specified if multiple organizations of the same name exist. - - C(absent) WILL DELETE YOUR ENTIRE ORGANIZATION, AND ALL ASSOCIATED OBJECTS, WITHOUT CONFIRMATION. USE WITH CAUTION. - choices: ['absent', 'present', 'query'] - default: present - clone: - description: - - Organization to clone to a new organization. - org_name: - description: - - Name of organization. - - If C(clone) is specified, C(org_name) is the name of the new organization. - aliases: [ name, organization ] - org_id: - description: - - ID of organization. - aliases: [ id ] - type: str -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Create a new organization named YourOrg - meraki_organization: - auth_key: abc12345 - org_name: YourOrg - state: present - delegate_to: localhost - -- name: Delete an organization named YourOrg - meraki_organization: - auth_key: abc12345 - org_name: YourOrg - state: absent - delegate_to: localhost - -- name: Query information about all organizations associated to the user - meraki_organization: - auth_key: abc12345 - state: query - delegate_to: localhost - -- name: Query information about a single organization named YourOrg - meraki_organization: - auth_key: abc12345 - org_name: YourOrg - state: query - delegate_to: localhost - -- name: Rename an organization to RenamedOrg - meraki_organization: - auth_key: abc12345 - org_id: 987654321 - org_name: RenamedOrg - state: present - delegate_to: localhost - -- name: Clone an organization named Org to a new one called ClonedOrg - meraki_organization: - auth_key: abc12345 - clone: Org - org_name: ClonedOrg - state: present - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information about the organization which was created or modified - returned: success - type: complex - contains: - id: - description: Unique identification number of organization - returned: success - type: int - sample: 2930418 - name: - description: Name of organization - returned: success - type: str - sample: YourOrg - -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_org(meraki, org_id, data): - # meraki.fail_json(msg=str(org_id), data=data, oid0=data[0]['id'], oid1=data[1]['id']) - for o in data: - # meraki.fail_json(msg='o', data=o['id'], type=str(type(o['id']))) - if o['id'] == org_id: - return o - return -1 - - -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']), - ) - - # 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='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.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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_snmp.py b/lib/ansible/modules/network/meraki/meraki_snmp.py deleted file mode 100644 index 097d9704b72..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_snmp.py +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_snmp -short_description: Manage organizations in the Meraki cloud -version_added: "2.6" -description: -- Allows for management of SNMP settings for Meraki. -options: - state: - description: - - Specifies whether SNMP information should be queried or modified. - choices: ['query', 'present'] - default: present - type: str - v2c_enabled: - description: - - Specifies whether SNMPv2c is enabled. - type: bool - v3_enabled: - description: - - Specifies whether SNMPv3 is enabled. - type: bool - v3_auth_mode: - description: - - Sets authentication mode for SNMPv3. - choices: ['MD5', 'SHA'] - type: str - v3_auth_pass: - description: - - Authentication password for SNMPv3. - - Must be at least 8 characters long. - type: str - v3_priv_mode: - description: - - Specifies privacy mode for SNMPv3. - choices: ['DES', 'AES128'] - type: str - v3_priv_pass: - description: - - Privacy password for SNMPv3. - - Must be at least 8 characters long. - type: str - peer_ips: - description: - - Semi-colon delimited IP addresses which can perform SNMP queries. - type: str - net_name: - description: - - Name of network. - type: str - version_added: '2.9' - net_id: - description: - - ID of network. - type: str - version_added: '2.9' - access: - description: - - Type of SNMP access. - choices: [community, none, users] - type: str - version_added: '2.9' - community_string: - description: - - SNMP community string. - - Only relevant if C(access) is set to C(community). - type: str - version_added: '2.9' - users: - description: - - Information about users with access to SNMP. - - Only relevant if C(access) is set to C(users). - type: list - version_added: '2.9' - suboptions: - username: - description: Username of user with access. - type: str - version_added: '2.9' - passphrase: - description: Passphrase for user SNMP access. - type: str - version_added: '2.9' -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query SNMP values - meraki_snmp: - auth_key: abc12345 - org_name: YourOrg - state: query - delegate_to: localhost - -- name: Enable SNMPv2 - meraki_snmp: - auth_key: abc12345 - org_name: YourOrg - state: present - v2c_enabled: yes - delegate_to: localhost - -- name: Disable SNMPv2 - meraki_snmp: - auth_key: abc12345 - org_name: YourOrg - state: present - v2c_enabled: no - delegate_to: localhost - -- name: Enable SNMPv3 - meraki_snmp: - auth_key: abc12345 - org_name: YourOrg - state: present - v3_enabled: true - v3_auth_mode: SHA - v3_auth_pass: ansiblepass - v3_priv_mode: AES128 - v3_priv_pass: ansiblepass - peer_ips: 192.0.1.1;192.0.1.2 - delegate_to: localhost - -- name: Set network access type to community string - meraki_snmp: - auth_key: abc1235 - org_name: YourOrg - net_name: YourNet - state: present - access: community - community_string: abc123 - delegate_to: localhost - -- name: Set network access type to username - meraki_snmp: - auth_key: abc1235 - org_name: YourOrg - net_name: YourNet - state: present - access: users - users: - - username: ansibleuser - passphrase: ansiblepass - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information about SNMP settings. - type: complex - returned: always - contains: - hostname: - description: Hostname of SNMP server. - returned: success and no network specified. - type: str - sample: n1.meraki.com - peerIps: - description: Semi-colon delimited list of IPs which can poll SNMP information. - returned: success and no network specified. - type: str - sample: 192.0.1.1 - port: - description: Port number of SNMP. - returned: success and no network specified. - type: str - sample: 16100 - v2c_enabled: - description: Shows enabled state of SNMPv2c - returned: success and no network specified. - type: bool - sample: true - v3_enabled: - description: Shows enabled state of SNMPv3 - returned: success and no network specified. - type: bool - sample: true - v3_auth_mode: - description: The SNMP version 3 authentication mode either MD5 or SHA. - returned: success and no network specified. - type: str - sample: SHA - v3_priv_mode: - description: The SNMP version 3 privacy mode DES or AES128. - returned: success and no network specified. - type: str - sample: AES128 - v2_community_string: - description: Automatically generated community string for SNMPv2c. - returned: When SNMPv2c is enabled and no network specified. - type: str - sample: o/8zd-JaSb - v3_user: - description: Automatically generated username for SNMPv3. - returned: When SNMPv3c is enabled and no network specified. - type: str - sample: o/8zd-JaSb - access: - description: Type of SNMP access. - type: str - returned: success, when network specified - community_string: - description: SNMP community string. Only relevant if C(access) is set to C(community). - type: str - returned: success, when network specified - users: - description: Information about users with access to SNMP. Only relevant if C(access) is set to C(users). - type: complex - contains: - username: - description: Username of user with access. - type: str - returned: success, when network specified - passphrase: - description: Passphrase for user SNMP access. - type: str - returned: success, when network specified -''' - -from ansible.module_utils.basic import AnsibleModule, json -from ansible.module_utils.common.dict_transformations import recursive_diff, snake_dict_to_camel_dict -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_snmp(meraki, org_id): - path = meraki.construct_path('get_all', org_id=org_id) - r = meraki.request(path, - method='GET', - ) - if meraki.status == 200: - return r - - -def set_snmp(meraki, org_id): - payload = dict() - if meraki.params['peer_ips']: - if len(meraki.params['peer_ips']) > 7: - if ';' not in meraki.params['peer_ips']: - meraki.fail_json(msg='Peer IP addresses are semi-colon delimited.') - if meraki.params['v2c_enabled'] is not None: - payload = {'v2cEnabled': meraki.params['v2c_enabled'], - } - if meraki.params['v3_enabled'] is True: - if len(meraki.params['v3_auth_pass']) < 8 or len(meraki.params['v3_priv_pass']) < 8: - meraki.fail_json(msg='v3_auth_pass and v3_priv_pass must both be at least 8 characters long.') - if (meraki.params['v3_auth_mode'] is None or - meraki.params['v3_auth_pass'] is None or - meraki.params['v3_priv_mode'] is None or - meraki.params['v3_priv_pass'] is None): - meraki.fail_json(msg='v3_auth_mode, v3_auth_pass, v3_priv_mode, and v3_auth_pass are required') - payload = {'v3Enabled': meraki.params['v3_enabled'], - 'v3AuthMode': meraki.params['v3_auth_mode'].upper(), - 'v3AuthPass': meraki.params['v3_auth_pass'], - 'v3PrivMode': meraki.params['v3_priv_mode'].upper(), - 'v3PrivPass': meraki.params['v3_priv_pass'], - } - if meraki.params['peer_ips'] is not None: - payload['peerIps'] = meraki.params['peer_ips'] - elif meraki.params['v3_enabled'] is False: - payload = {'v3Enabled': False} - full_compare = snake_dict_to_camel_dict(payload) - path = meraki.construct_path('create', org_id=org_id) - snmp = get_snmp(meraki, org_id) - ignored_parameters = ['v3AuthPass', 'v3PrivPass', 'hostname', 'port', 'v2CommunityString', 'v3User'] - if meraki.is_update_required(snmp, full_compare, optional_ignore=ignored_parameters): - if meraki.module.check_mode is True: - diff = recursive_diff(snmp, full_compare) - snmp.update(payload) - meraki.result['data'] = snmp - meraki.result['changed'] = True - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1]} - meraki.exit_json(**meraki.result) - r = meraki.request(path, - method='PUT', - payload=json.dumps(payload)) - if meraki.status == 200: - diff = recursive_diff(snmp, r) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1]} - meraki.result['changed'] = True - return r - else: - return snmp - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - user_arg_spec = dict(username=dict(type='str'), - passphrase=dict(type='str', no_log=True), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update(state=dict(type='str', choices=['present', 'query'], default='present'), - v2c_enabled=dict(type='bool'), - v3_enabled=dict(type='bool'), - v3_auth_mode=dict(type='str', choices=['SHA', 'MD5']), - v3_auth_pass=dict(type='str', no_log=True), - v3_priv_mode=dict(type='str', choices=['DES', 'AES128']), - v3_priv_pass=dict(type='str', no_log=True), - peer_ips=dict(type='str'), - access=dict(type='str', choices=['none', 'community', 'users']), - community_string=dict(type='str', no_log=True), - users=dict(type='list', default=None, elements='', options=user_arg_spec), - net_name=dict(type='str'), - net_id=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='snmp') - meraki.params['follow_redirects'] = 'all' - - query_urls = {'snmp': '/organizations/{org_id}/snmp'} - query_net_urls = {'snmp': '/networks/{net_id}/snmpSettings'} - update_urls = {'snmp': '/organizations/{org_id}/snmp'} - update_net_urls = {'snmp': '/networks/{net_id}/snmpSettings'} - - meraki.url_catalog['get_all'].update(query_urls) - meraki.url_catalog['query_net_all'] = query_net_urls - meraki.url_catalog['create'] = update_urls - meraki.url_catalog['create_net'] = update_net_urls - - payload = None - - if not meraki.params['org_name'] and not meraki.params['org_id']: - meraki.fail_json(msg='org_name or org_id is required') - - org_id = meraki.params['org_id'] - if org_id is None: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None and meraki.params['net_name']: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(org_id, meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'present': - if net_id is not None: - payload = {'access': meraki.params['access']} - if meraki.params['community_string'] is not None: - payload['communityString'] = meraki.params['community_string'] - elif meraki.params['users'] is not None: - payload['users'] = meraki.params['users'] - - if meraki.params['state'] == 'query': - if net_id is None: - meraki.result['data'] = get_snmp(meraki, org_id) - else: - path = meraki.construct_path('query_net_all', net_id=net_id) - response = meraki.request(path, method='GET') - if meraki.status == 200: - meraki.result['data'] = response - elif meraki.params['state'] == 'present': - if net_id is None: - meraki.result['data'] = set_snmp(meraki, org_id) - else: - path = meraki.construct_path('query_net_all', net_id=net_id) - original = meraki.request(path, method='GET') - if meraki.is_update_required(original, payload): - path = meraki.construct_path('create_net', net_id=net_id) - response = meraki.request(path, method='PUT', payload=json.dumps(payload)) - if meraki.status == 200: - if response['access'] == 'none': - meraki.result['data'] = {} - else: - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_ssid.py b/lib/ansible/modules/network/meraki/meraki_ssid.py deleted file mode 100644 index 7148feadcf5..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_ssid.py +++ /dev/null @@ -1,606 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_ssid -short_description: Manage wireless SSIDs in the Meraki cloud -version_added: "2.7" -description: -- Allows for management of SSIDs in a Meraki wireless environment. -notes: -- Deleting an SSID does not delete RADIUS servers. -options: - state: - description: - - Specifies whether SNMP information should be queried or modified. - type: str - choices: [ absent, query, present ] - default: present - number: - description: - - SSID number within network. - type: int - aliases: [ssid_number] - name: - description: - - Name of SSID. - type: str - net_name: - description: - - Name of network. - type: str - net_id: - description: - - ID of network. - type: str - enabled: - description: - - Enable or disable SSID network. - type: bool - auth_mode: - description: - - Set authentication mode of network. - type: str - choices: [open, psk, open-with-radius, 8021x-meraki, 8021x-radius] - encryption_mode: - description: - - Set encryption mode of network. - type: str - choices: [wpa, eap, wpa-eap] - psk: - description: - - Password for wireless network. - - Requires auth_mode to be set to psk. - type: str - wpa_encryption_mode: - description: - - Encryption mode within WPA2 specification. - type: str - choices: [WPA1 and WPA2, WPA2 only] - splash_page: - description: - - Set to enable splash page and specify type of splash. - type: str - choices: ['None', - 'Click-through splash page', - 'Billing', - 'Password-protected with Meraki RADIUS', - 'Password-protected with custom RADIUS', - 'Password-protected with Active Directory', - 'Password-protected with LDAP', - 'SMS authentication', - 'Systems Manager Sentry', - 'Facebook Wi-Fi', - 'Google OAuth', - 'Sponsored guest'] - radius_servers: - description: - - List of RADIUS servers. - type: list - suboptions: - host: - description: - - IP address or hostname of RADIUS server. - type: str - port: - description: - - Port number RADIUS server is listening to. - type: int - secret: - description: - - RADIUS password. - - Setting password is not idempotent. - type: str - radius_coa_enabled: - description: - - Enable or disable RADIUS CoA (Change of Authorization) on SSID. - type: bool - radius_failover_policy: - description: - - Set client access policy in case RADIUS servers aren't available. - type: str - choices: [Deny access, Allow access] - radius_load_balancing_policy: - description: - - Set load balancing policy when multiple RADIUS servers are specified. - type: str - choices: [Strict priority order, Round robin] - radius_accounting_enabled: - description: - - Enable or disable RADIUS accounting. - type: bool - radius_accounting_servers: - description: - - List of RADIUS servers for RADIUS accounting. - type: list - suboptions: - host: - description: - - IP address or hostname of RADIUS server. - type: str - port: - description: - - Port number RADIUS server is listening to. - type: int - secret: - description: - - RADIUS password. - - Setting password is not idempotent. - type: str - ip_assignment_mode: - description: - - Method of which SSID uses to assign IP addresses. - type: str - choices: ['NAT mode', - 'Bridge mode', - 'Layer 3 roaming', - 'Layer 3 roaming with a concentrator', - 'VPN'] - use_vlan_tagging: - description: - - Set whether to use VLAN tagging. - - Requires C(default_vlan_id) to be set. - type: bool - default_vlan_id: - description: - - Default VLAN ID. - - Requires C(ip_assignment_mode) to be C(Bridge mode) or C(Layer 3 roaming). - type: int - vlan_id: - description: - - ID number of VLAN on SSID. - - Requires C(ip_assignment_mode) to be C(ayer 3 roaming with a concentrator) or C(VPN). - type: int - ap_tags_vlan_ids: - description: - - List of VLAN tags. - - Requires C(ip_assignment_mode) to be C(Bridge mode) or C(Layer 3 roaming). - - Requires C(use_vlan_tagging) to be C(True). - type: list - suboptions: - tags: - description: - - List of AP tags. - type: list - vlan_id: - description: - - Numerical identifier that is assigned to the VLAN. - type: int - walled_garden_enabled: - description: - - Enable or disable walled garden functionality. - type: bool - walled_garden_ranges: - description: - - List of walled garden ranges. - type: list - min_bitrate: - description: - - Minimum bitrate (Mbps) allowed on SSID. - type: float - choices: [1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54] - band_selection: - description: - - Set band selection mode. - type: str - choices: ['Dual band operation', '5 GHz band only', 'Dual band operation with Band Steering'] - per_client_bandwidth_limit_up: - description: - - Maximum bandwidth in Mbps devices on SSID can upload. - type: int - per_client_bandwidth_limit_down: - description: - - Maximum bandwidth in Mbps devices on SSID can download. - type: int - concentrator_network_id: - description: - - The concentrator to use for 'Layer 3 roaming with a concentrator' or 'VPN'. - type: str -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Enable and name SSID - meraki_ssid: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: WiFi - name: GuestSSID - enabled: true - delegate_to: localhost - -- name: Set PSK with invalid encryption mode - meraki_ssid: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: WiFi - name: GuestSSID - auth_mode: psk - psk: abc1234 - encryption_mode: eap - ignore_errors: yes - delegate_to: localhost - -- name: Configure RADIUS servers - meraki_ssid: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: WiFi - name: GuestSSID - auth_mode: open-with-radius - radius_servers: - - host: 192.0.1.200 - port: 1234 - secret: abc98765 - delegate_to: localhost - -- name: Enable click-through splash page - meraki_ssid: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: WiFi - name: GuestSSID - splash_page: Click-through splash page - delegate_to: localhost -''' - -RETURN = r''' -data: - description: List of wireless SSIDs. - returned: success - type: complex - contains: - number: - description: Zero-based index number for SSIDs. - returned: success - type: int - sample: 0 - name: - description: - - Name of wireless SSID. - - This value is what is broadcasted. - returned: success - type: str - sample: CorpWireless - enabled: - description: Enabled state of wireless network. - returned: success - type: bool - sample: true - splash_page: - description: Splash page to show when user authenticates. - returned: success - type: str - sample: Click-through splash page - ssid_admin_accessible: - description: Whether SSID is administratively accessible. - returned: success - type: bool - sample: true - auth_mode: - description: Authentication method. - returned: success - type: str - sample: psk - psk: - description: Secret wireless password. - returned: success - type: str - sample: SecretWiFiPass - encryption_mode: - description: Wireless traffic encryption method. - returned: success - type: str - sample: wpa - wpa_encryption_mode: - description: Enabled WPA versions. - returned: success - type: str - sample: WPA2 only - ip_assignment_mode: - description: Wireless client IP assignment method. - returned: success - type: str - sample: NAT mode - min_bitrate: - description: Minimum bitrate a wireless client can connect at. - returned: success - type: int - sample: 11 - band_selection: - description: Wireless RF frequency wireless network will be broadcast on. - returned: success - type: str - sample: 5 GHz band only - per_client_bandwidth_limit_up: - description: Maximum upload bandwidth a client can use. - returned: success - type: int - sample: 1000 - per_client_bandwidth_limit_down: - description: Maximum download bandwidth a client can use. - returned: success - type: int - sample: 0 -''' - -from ansible.module_utils.basic import AnsibleModule, json -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_available_number(data): - for item in data: - if 'Unconfigured SSID' in item['name']: - return item['number'] - return False - - -def get_ssid_number(name, data): - for ssid in data: - if name == ssid['name']: - return ssid['number'] - return False - - -def get_ssids(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - return meraki.request(path, method='GET') - - -def main(): - - param_map = {'name': 'name', - 'enabled': 'enabled', - 'authMode': 'auth_mode', - 'encryptionMode': 'encryption_mode', - 'psk': 'psk', - 'wpaEncryptionMode': 'wpa_encryption_mode', - 'splashPage': 'splash_page', - 'radiusServers': 'radius_servers', - 'radiusCoaEnabled': 'radius_coa_enabled', - 'radiusFailoverPolicy': 'radius_failover_policy', - 'radiusLoadBalancingPolicy': 'radius_load_balancing_policy', - 'radiusAccountingEnabled': 'radius_accounting_enabled', - 'radiusAccountingServers': 'radius_accounting_servers', - 'ipAssignmentMode': 'ip_assignment_mode', - 'useVlanTagging': 'use_vlan_tagging', - 'concentratorNetworkId': 'concentrator_network_id', - 'vlanId': 'vlan_id', - 'defaultVlanId': 'default_vlan_id', - 'apTagsAndVlanIds': 'ap_tags_vlan_ids', - 'walledGardenEnabled': 'walled_garden_enabled', - 'walledGardenRanges': 'walled_garden_ranges', - 'minBitrate': 'min_bitrate', - 'bandSelection': 'band_selection', - 'perClientBandwidthLimitUp': 'per_client_bandwidth_limit_up', - 'perClientBandwidthLimitDown': 'per_client_bandwidth_limit_down', - } - - default_payload = {'name': 'Unconfigured SSID', - 'auth_mode': 'open', - 'splashPage': 'None', - 'perClientBandwidthLimitUp': 0, - 'perClientBandwidthLimitDown': 0, - 'ipAssignmentMode': 'NAT mode', - 'enabled': False, - 'bandSelection': 'Dual band operation', - 'minBitrate': 11, - } - - # define the available arguments/parameters that a user can pass to - # the module - radius_arg_spec = dict(host=dict(type='str', required=True), - port=dict(type='int'), - secret=dict(type='str', no_log=True), - ) - vlan_arg_spec = dict(tags=dict(type='list', elements='str'), - vlan_id=dict(type='int'), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update(state=dict(type='str', choices=['absent', 'present', 'query'], default='present'), - number=dict(type='int', aliases=['ssid_number']), - name=dict(type='str'), - org_name=dict(type='str', aliases=['organization']), - org_id=dict(type='str'), - net_name=dict(type='str'), - net_id=dict(type='str'), - enabled=dict(type='bool'), - auth_mode=dict(type='str', choices=['open', 'psk', 'open-with-radius', '8021x-meraki', '8021x-radius']), - encryption_mode=dict(type='str', choices=['wpa', 'eap', 'wpa-eap']), - psk=dict(type='str', no_log=True), - wpa_encryption_mode=dict(type='str', choices=['WPA1 and WPA2', 'WPA2 only']), - splash_page=dict(type='str', choices=['None', - 'Click-through splash page', - 'Billing', - 'Password-protected with Meraki RADIUS', - 'Password-protected with custom RADIUS', - 'Password-protected with Active Directory', - 'Password-protected with LDAP', - 'SMS authentication', - 'Systems Manager Sentry', - 'Facebook Wi-Fi', - 'Google OAuth', - 'Sponsored guest']), - radius_servers=dict(type='list', default=None, elements='dict', options=radius_arg_spec), - radius_coa_enabled=dict(type='bool'), - radius_failover_policy=dict(type='str', choices=['Deny access', 'Allow access']), - radius_load_balancing_policy=dict(type='str', choices=['Strict priority order', 'Round robin']), - radius_accounting_enabled=dict(type='bool'), - radius_accounting_servers=dict(type='list', elements='dict', options=radius_arg_spec), - ip_assignment_mode=dict(type='str', choices=['NAT mode', - 'Bridge mode', - 'Layer 3 roaming', - 'Layer 3 roaming with a concentrator', - 'VPN']), - use_vlan_tagging=dict(type='bool'), - concentrator_network_id=dict(type='str'), - vlan_id=dict(type='int'), - default_vlan_id=dict(type='int'), - ap_tags_vlan_ids=dict(type='list', default=None, elements='dict', options=vlan_arg_spec), - walled_garden_enabled=dict(type='bool'), - walled_garden_ranges=dict(type='list'), - min_bitrate=dict(type='float', choices=[1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54]), - band_selection=dict(type='str', choices=['Dual band operation', - '5 GHz band only', - 'Dual band operation with Band Steering']), - per_client_bandwidth_limit_up=dict(type='int'), - per_client_bandwidth_limit_down=dict(type='int'), - ) - - # 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='ssid') - meraki.params['follow_redirects'] = 'all' - - query_urls = {'ssid': '/networks/{net_id}/ssids'} - query_url = {'ssid': '/networks/{net_id}/ssids/{number}'} - update_url = {'ssid': '/networks/{net_id}/ssids/'} - - meraki.url_catalog['get_all'].update(query_urls) - meraki.url_catalog['get_one'].update(query_url) - meraki.url_catalog['update'] = update_url - - payload = None - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - # FIXME: Work with Meraki so they can implement a check mode - if module.check_mode: - meraki.exit_json(**meraki.result) - - # execute checks for argument completeness - if meraki.params['psk']: - if meraki.params['auth_mode'] != 'psk': - meraki.fail_json(msg='PSK is only allowed when auth_mode is set to psk') - if meraki.params['encryption_mode'] != 'wpa': - meraki.fail_json(msg='PSK requires encryption_mode be set to wpa') - if meraki.params['radius_servers']: - if meraki.params['auth_mode'] not in ('open-with-radius', '8021x-radius'): - meraki.fail_json(msg='radius_servers requires auth_mode to be open-with-radius or 8021x-radius') - if meraki.params['radius_accounting_enabled'] is True: - if meraki.params['auth_mode'] not in ('open-with-radius', '8021x-radius'): - meraki.fails_json(msg='radius_accounting_enabled is only allowed when auth_mode is open-with-radius or 8021x-radius') - if meraki.params['radius_accounting_servers'] is True: - if meraki.params['auth_mode'] not in ('open-with-radius', '8021x-radius') or meraki.params['radius_accounting_enabled'] is False: - meraki.fail_json(msg='radius_accounting_servers is only allowed when auth_mode is open_with_radius or 8021x-radius and \ - radius_accounting_enabled is true') - if meraki.params['use_vlan_tagging'] is True: - if meraki.params['default_vlan_id'] is None: - meraki.fail_json(msg="default_vlan_id is required when use_vlan_tagging is True") - - # 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'] - net_id = meraki.params['net_id'] - if org_id is None: - org_id = meraki.get_org_id(meraki.params['org_name']) - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(org_id, meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - if meraki.params['name']: - ssid_id = get_ssid_number(meraki.params['name'], get_ssids(meraki, net_id)) - path = meraki.construct_path('get_one', net_id=net_id, custom={'number': ssid_id}) - meraki.result['data'] = meraki.request(path, method='GET') - elif meraki.params['number'] is not None: - path = meraki.construct_path('get_one', net_id=net_id, custom={'number': meraki.params['number']}) - meraki.result['data'] = meraki.request(path, method='GET') - else: - meraki.result['data'] = get_ssids(meraki, net_id) - elif meraki.params['state'] == 'present': - payload = dict() - for k, v in param_map.items(): - if meraki.params[v] is not None: - payload[k] = meraki.params[v] - # Short term solution for camelCase/snake_case differences - # Will be addressed later with a method in module utils - if meraki.params['ap_tags_vlan_ids'] is not None: - for i in payload['apTagsAndVlanIds']: - try: - i['vlanId'] = i['vlan_id'] - del i['vlan_id'] - except KeyError: - pass - try: - tags = ','.join(i['tags']) - del i['tags'] - i['tags'] = tags - except KeyError: - pass - ssids = get_ssids(meraki, net_id) - number = meraki.params['number'] - if number is None: - number = get_ssid_number(meraki.params['name'], ssids) - original = ssids[number] - if meraki.is_update_required(original, payload, optional_ignore=['secret']): - ssid_id = meraki.params['number'] - if ssid_id is None: # Name should be used to lookup number - ssid_id = get_ssid_number(meraki.params['name'], ssids) - if ssid_id is False: - ssid_id = get_available_number(ssids) - if ssid_id is False: - meraki.fail_json(msg='No unconfigured SSIDs are available. Specify a number.') - path = meraki.construct_path('update', net_id=net_id) + str(ssid_id) - result = meraki.request(path, 'PUT', payload=json.dumps(payload)) - meraki.result['data'] = result - meraki.result['changed'] = True - else: - meraki.result['data'] = original - elif meraki.params['state'] == 'absent': - ssids = get_ssids(meraki, net_id) - ssid_id = meraki.params['number'] - if ssid_id is None: # Name should be used to lookup number - ssid_id = get_ssid_number(meraki.params['name'], ssids) - if ssid_id is False: - ssid_id = get_available_number(ssids) - if ssid_id is False: - meraki.fail_json(msg='No SSID found by specified name and no number was referenced.') - path = meraki.construct_path('update', net_id=net_id) + str(ssid_id) - payload = default_payload - payload['name'] = payload['name'] + ' ' + str(ssid_id + 1) - result = meraki.request(path, 'PUT', payload=json.dumps(payload)) - meraki.result['data'] = result - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_static_route.py b/lib/ansible/modules/network/meraki/meraki_static_route.py deleted file mode 100644 index b9e1acd9e6e..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_static_route.py +++ /dev/null @@ -1,375 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, 2019 Kevin Breit (@kbreit) -# 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_static_route -short_description: Manage static routes in the Meraki cloud -version_added: "2.8" -description: -- Allows for creation, management, and visibility into static routes within Meraki. - -options: - state: - description: - - Create or modify an organization. - choices: [ absent, query, present ] - default: present - type: str - net_name: - description: - - Name of a network. - type: str - net_id: - description: - - ID number of a network. - type: str - name: - description: - - Descriptive name of the static route. - type: str - subnet: - description: - - CIDR notation based subnet for static route. - type: str - gateway_ip: - description: - - IP address of the gateway for the subnet. - type: str - route_id: - description: - - Unique ID of static route. - type: str - fixed_ip_assignments: - description: - - List of fixed MAC to IP bindings for DHCP. - type: list - suboptions: - mac: - description: - - MAC address of endpoint. - type: str - ip: - description: - - IP address of endpoint. - type: str - name: - description: - - Hostname of endpoint. - type: str - reserved_ip_ranges: - description: - - List of IP ranges reserved for static IP assignments. - type: list - suboptions: - start: - description: - - First IP address of reserved range. - type: str - end: - description: - - Last IP address of reserved range. - type: str - comment: - description: - - Human readable description of reservation range. - type: str - enabled: - description: - - Indicates whether static route is enabled within a network. - type: bool - - -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Create static_route - meraki_static_route: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - name: Test Route - subnet: 192.0.1.0/24 - gateway_ip: 192.168.128.1 - delegate_to: localhost - -- name: Update static route with fixed IP assignment - meraki_static_route: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - route_id: d6fa4821-1234-4dfa-af6b-ae8b16c20c39 - fixed_ip_assignments: - - mac: aa:bb:cc:dd:ee:ff - ip: 192.0.1.11 - comment: Server - delegate_to: localhost - -- name: Query static routes - meraki_static_route: - auth_key: abc123 - state: query - org_name: YourOrg - net_name: YourNet - delegate_to: localhost - -- name: Delete static routes - meraki_static_route: - auth_key: abc123 - state: absent - org_name: YourOrg - net_name: YourNet - route_id: '{{item}}' - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information about the created or manipulated object. - returned: info - type: complex - contains: - id: - description: Unique identification string assigned to each static route. - returned: success - type: str - sample: d6fa4821-1234-4dfa-af6b-ae8b16c20c39 - net_id: - description: Identification string of network. - returned: query or update - type: str - sample: N_12345 - name: - description: Name of static route. - returned: success - type: str - sample: Data Center static route - subnet: - description: CIDR notation subnet for static route. - returned: success - type: str - sample: 192.0.1.0/24 - gatewayIp: - description: Next hop IP address. - returned: success - type: str - sample: 192.1.1.1 - enabled: - description: Enabled state of static route. - returned: query or update - type: bool - sample: True - reservedIpRanges: - description: List of IP address ranges which are reserved for static assignment. - returned: query or update - type: complex - contains: - start: - description: First address in reservation range, inclusive. - returned: query or update - type: str - sample: 192.0.1.2 - end: - description: Last address in reservation range, inclusive. - returned: query or update - type: str - sample: 192.0.1.10 - comment: - description: Human readable description of range. - returned: query or update - type: str - sample: Server range - fixedIpAssignments: - description: List of static MAC to IP address bindings. - returned: query or update - type: complex - contains: - mac: - description: Key is MAC address of endpoint. - returned: query or update - type: complex - contains: - ip: - description: IP address to be bound to the endpoint. - returned: query or update - type: str - sample: 192.0.1.11 - name: - description: Hostname given to the endpoint. - returned: query or update - type: str - sample: JimLaptop -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def fixed_ip_factory(meraki, data): - fixed_ips = dict() - for item in data: - fixed_ips[item['mac']] = {'ip': item['ip'], 'name': item['name']} - return fixed_ips - - -def get_static_routes(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - r = meraki.request(path, method='GET') - return r - - -def get_static_route(meraki, net_id, route_id): - path = meraki.construct_path('get_one', net_id=net_id, custom={'route_id': meraki.params['route_id']}) - r = meraki.request(path, method='GET') - return r - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - - fixed_ip_arg_spec = dict(mac=dict(type='str'), - ip=dict(type='str'), - name=dict(type='str'), - ) - - reserved_ip_arg_spec = dict(start=dict(type='str'), - end=dict(type='str'), - comment=dict(type='str'), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update( - net_id=dict(type='str'), - net_name=dict(type='str'), - name=dict(type='str'), - subnet=dict(type='str'), - gateway_ip=dict(type='str'), - state=dict(type='str', default='present', choices=['absent', 'present', 'query']), - fixed_ip_assignments=dict(type='list', elements='dict', options=fixed_ip_arg_spec), - reserved_ip_ranges=dict(type='list', elements='dict', options=reserved_ip_arg_spec), - route_id=dict(type='str'), - enabled=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='static_route') - module.params['follow_redirects'] = 'all' - payload = None - - query_urls = {'static_route': '/networks/{net_id}/staticRoutes'} - query_one_urls = {'static_route': '/networks/{net_id}/staticRoutes/{route_id}'} - create_urls = {'static_route': '/networks/{net_id}/staticRoutes/'} - update_urls = {'static_route': '/networks/{net_id}/staticRoutes/{route_id}'} - delete_urls = {'static_route': '/networks/{net_id}/staticRoutes/{route_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 - - if not meraki.params['org_name'] and not meraki.params['org_id']: - meraki.fail_json(msg="Parameters 'org_name' or 'org_id' parameters are required") - if not meraki.params['net_name'] and not meraki.params['net_id']: - meraki.fail_json(msg="Parameters 'net_name' or 'net_id' parameters are required") - if meraki.params['net_name'] and meraki.params['net_id']: - meraki.fail_json(msg="'net_name' and 'net_id' are mutually exclusive") - - # Construct payload - if meraki.params['state'] == 'present': - payload = dict() - if meraki.params['net_name']: - payload['name'] = meraki.params['net_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) - - org_id = meraki.params['org_id'] - if not org_id: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - if meraki.params['route_id'] is not None: - meraki.result['data'] = get_static_route(meraki, net_id, meraki.params['route_id']) - else: - meraki.result['data'] = get_static_routes(meraki, net_id) - elif meraki.params['state'] == 'present': - payload = {'name': meraki.params['name'], - 'subnet': meraki.params['subnet'], - 'gatewayIp': meraki.params['gateway_ip'], - } - if meraki.params['fixed_ip_assignments'] is not None: - payload['fixedIpAssignments'] = fixed_ip_factory(meraki, - meraki.params['fixed_ip_assignments']) - if meraki.params['reserved_ip_ranges'] is not None: - payload['reservedIpRanges'] = meraki.params['reserved_ip_ranges'] - # meraki.fail_json(msg="payload", payload=payload) - if meraki.params['enabled'] is not None: - payload['enabled'] = meraki.params['enabled'] - if meraki.params['route_id']: - existing_route = get_static_route(meraki, net_id, meraki.params['route_id']) - proposed = existing_route.copy() - proposed.update(payload) - if module.check_mode: - meraki.result['data'] = proposed - meraki.result['data'].update(payload) - meraki.exit_json(**meraki.result) - if meraki.is_update_required(existing_route, proposed, optional_ignore=['id']): - path = meraki.construct_path('update', net_id=net_id, custom={'route_id': meraki.params['route_id']}) - meraki.result['data'] = meraki.request(path, method="PUT", payload=json.dumps(payload)) - meraki.result['changed'] = True - else: - meraki.result['data'] = existing_route - else: - if module.check_mode: - meraki.result['data'] = payload - meraki.exit_json(**meraki.result) - path = meraki.construct_path('create', net_id=net_id) - meraki.result['data'] = meraki.request(path, method="POST", payload=json.dumps(payload)) - meraki.result['changed'] = True - elif meraki.params['state'] == 'absent': - if module.check_mode: - meraki.exit_json(**meraki.result) - path = meraki.construct_path('delete', net_id=net_id, custom={'route_id': meraki.params['route_id']}) - meraki.result['data'] = meraki.request(path, method='DELETE') - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_switchport.py b/lib/ansible/modules/network/meraki/meraki_switchport.py deleted file mode 100644 index d84ad46620f..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_switchport.py +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_switchport -short_description: Manage switchports on a switch in the Meraki cloud -version_added: "2.7" -description: -- Allows for management of switchports settings for Meraki MS switches. -options: - state: - description: - - Specifies whether a switchport should be queried or modified. - choices: [query, present] - default: query - type: str - access_policy_number: - description: - - Number of the access policy to apply. - - Only applicable to access port types. - allowed_vlans: - description: - - List of VLAN numbers to be allowed on switchport. - default: all - enabled: - description: - - Whether a switchport should be enabled or disabled. - type: bool - default: yes - isolation_enabled: - description: - - Isolation status of switchport. - default: no - type: bool - link_negotiation: - description: - - Link speed for the switchport. - default: Auto negotiate - choices: [Auto negotiate, 100Megabit (auto), 100 Megabit full duplex (forced)] - name: - description: - - Switchport description. - aliases: [description] - number: - description: - - Port number. - poe_enabled: - description: - - Enable or disable Power Over Ethernet on a port. - type: bool - default: true - rstp_enabled: - description: - - Enable or disable Rapid Spanning Tree Protocol on a port. - type: bool - default: true - serial: - description: - - Serial nubmer of the switch. - stp_guard: - description: - - Set state of STP guard. - choices: [disabled, root guard, bpdu guard, loop guard] - default: disabled - tags: - description: - - Space delimited list of tags to assign to a port. - type: - description: - - Set port type. - choices: [access, trunk] - default: access - vlan: - description: - - VLAN number assigned to port. - - If a port is of type trunk, the specified VLAN is the native VLAN. - voice_vlan: - description: - - VLAN number assigned to a port for voice traffic. - - Only applicable to access port type. - -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query information about all switchports on a switch - meraki_switchport: - auth_key: abc12345 - state: query - serial: ABC-123 - delegate_to: localhost - -- name: Query information about all switchports on a switch - meraki_switchport: - auth_key: abc12345 - state: query - serial: ABC-123 - number: 2 - delegate_to: localhost - -- name: Name switchport - meraki_switchport: - auth_key: abc12345 - state: present - serial: ABC-123 - number: 7 - name: Test Port - delegate_to: localhost - -- name: Configure access port with voice VLAN - meraki_switchport: - auth_key: abc12345 - state: present - serial: ABC-123 - number: 7 - enabled: true - name: Test Port - tags: desktop - type: access - vlan: 10 - voice_vlan: 11 - delegate_to: localhost - -- name: Check access port for idempotency - meraki_switchport: - auth_key: abc12345 - state: present - serial: ABC-123 - number: 7 - enabled: true - name: Test Port - tags: desktop - type: access - vlan: 10 - voice_vlan: 11 - delegate_to: localhost - -- name: Configure trunk port with specific VLANs - meraki_switchport: - auth_key: abc12345 - state: present - serial: ABC-123 - number: 7 - enabled: true - name: Server port - tags: server - type: trunk - allowed_vlans: - - 10 - - 15 - - 20 - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information queried or updated switchports. - returned: success - type: complex - contains: - number: - description: Number of port. - returned: success - type: int - sample: 1 - name: - description: Human friendly description of port. - returned: success - type: str - sample: "Jim Phone Port" - tags: - description: Space delimited list of tags assigned to port. - returned: success - type: str - sample: phone marketing - enabled: - description: Enabled state of port. - returned: success - type: bool - sample: true - poe_enabled: - description: Power Over Ethernet enabled state of port. - returned: success - type: bool - sample: true - type: - description: Type of switchport. - returned: success - type: str - sample: trunk - vlan: - description: VLAN assigned to port. - returned: success - type: int - sample: 10 - voice_vlan: - description: VLAN assigned to port with voice VLAN enabled devices. - returned: success - type: int - sample: 20 - isolation_enabled: - description: Port isolation status of port. - returned: success - type: bool - sample: true - rstp_enabled: - description: Enabled or disabled state of Rapid Spanning Tree Protocol (RSTP) - returned: success - type: bool - sample: true - stp_guard: - description: State of STP guard - returned: success - type: str - sample: "Root Guard" - access_policy_number: - description: Number of assigned access policy. Only applicable to access ports. - returned: success - type: int - sample: 1234 - link_negotiation: - description: Link speed for the port. - returned: success - type: str - sample: "Auto negotiate" -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_native -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - -param_map = {'access_policy_number': 'accessPolicyNumber', - 'allowed_vlans': 'allowedVlans', - 'enabled': 'enabled', - 'isolation_enabled': 'isolationEnabled', - 'link_negotiation': 'linkNegotiation', - 'name': 'name', - 'number': 'number', - 'poe_enabled': 'poeEnabled', - 'rstp_enabled': 'rstpEnabled', - 'stp_guard': 'stpGuard', - 'tags': 'tags', - 'type': 'type', - 'vlan': 'vlan', - 'voice_vlan': 'voiceVlan', - } - - -def sort_vlans(meraki, vlans): - converted = set() - for vlan in vlans: - converted.add(int(vlan)) - vlans_sorted = sorted(converted) - vlans_str = [] - for vlan in vlans_sorted: - vlans_str.append(str(vlan)) - return ','.join(vlans_str) - - -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'], default='query'), - serial=dict(type='str', required=True), - number=dict(type='str'), - name=dict(type='str', aliases=['description']), - tags=dict(type='str'), - enabled=dict(type='bool', default=True), - type=dict(type='str', choices=['access', 'trunk'], default='access'), - vlan=dict(type='int'), - voice_vlan=dict(type='int'), - allowed_vlans=dict(type='list', default='all'), - poe_enabled=dict(type='bool', default=True), - isolation_enabled=dict(type='bool', default=False), - rstp_enabled=dict(type='bool', default=True), - stp_guard=dict(type='str', choices=['disabled', 'root guard', 'bpdu guard', 'loop guard'], default='disabled'), - access_policy_number=dict(type='str'), - link_negotiation=dict(type='str', - choices=['Auto negotiate', '100Megabit (auto)', '100 Megabit full duplex (forced)'], - default='Auto negotiate'), - ) - - # 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='switchport') - meraki.params['follow_redirects'] = 'all' - - if meraki.params['type'] == 'trunk': - if not meraki.params['allowed_vlans']: - meraki.params['allowed_vlans'] = ['all'] # Backdoor way to set default without conflicting on access - - query_urls = {'switchport': '/devices/{serial}/switchPorts'} - query_url = {'switchport': '/devices/{serial}/switchPorts/{number}'} - update_url = {'switchport': '/devices/{serial}/switchPorts/{number}'} - - meraki.url_catalog['get_all'].update(query_urls) - meraki.url_catalog['get_one'].update(query_url) - meraki.url_catalog['update'] = update_url - - payload = None - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - # FIXME: Work with Meraki so they can implement a check mode - if module.check_mode: - meraki.exit_json(**meraki.result) - - # 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) - if meraki.params['state'] == 'query': - if meraki.params['number']: - path = meraki.construct_path('get_one', custom={'serial': meraki.params['serial'], - 'number': meraki.params['number'], - }) - response = meraki.request(path, method='GET') - meraki.result['data'] = response - else: - path = meraki.construct_path('get_all', custom={'serial': meraki.params['serial']}) - response = meraki.request(path, method='GET') - meraki.result['data'] = response - elif meraki.params['state'] == 'present': - payload = dict() - - for k, v in meraki.params.items(): - try: - payload[param_map[k]] = v - except KeyError: - pass - - allowed = set() # Use a set to remove duplicate items - if meraki.params['allowed_vlans'][0] == 'all': - allowed.add('all') - else: - for vlan in meraki.params['allowed_vlans']: - allowed.add(str(vlan)) - if meraki.params['vlan'] is not None: - allowed.add(str(meraki.params['vlan'])) - if len(allowed) > 1: # Convert from list to comma separated - payload['allowedVlans'] = sort_vlans(meraki, allowed) - else: - payload['allowedVlans'] = next(iter(allowed)) - - # Exceptions need to be made for idempotency check based on how Meraki returns - if meraki.params['type'] == 'access': - if not meraki.params['vlan']: # VLAN needs to be specified in access ports, but can't default to it - payload['vlan'] = 1 - - proposed = payload.copy() - query_path = meraki.construct_path('get_one', custom={'serial': meraki.params['serial'], - 'number': meraki.params['number'], - }) - original = meraki.request(query_path, method='GET') - if meraki.params['type'] == 'trunk': - proposed['voiceVlan'] = original['voiceVlan'] # API shouldn't include voice VLAN on a trunk port - if meraki.is_update_required(original, proposed, optional_ignore=['number']): - path = meraki.construct_path('update', custom={'serial': meraki.params['serial'], - 'number': meraki.params['number'], - }) - response = meraki.request(path, method='PUT', payload=json.dumps(payload)) - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/meraki/meraki_syslog.py b/lib/ansible/modules/network/meraki/meraki_syslog.py deleted file mode 100644 index 43bba92eb6c..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_syslog.py +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_syslog -short_description: Manage syslog server settings in the Meraki cloud. -version_added: "2.8" -description: -- Allows for creation and management of Syslog servers within Meraki. -notes: -- Changes to existing syslog servers replaces existing configuration. If you need to add to an - existing configuration set state to query to gather the existing configuration and then modify or add. -options: - auth_key: - description: - - Authentication key provided by the dashboard. Required if environmental variable MERAKI_KEY is not set. - type: str - state: - description: - - Query or edit syslog servers - - To delete a syslog server, do not include server in list of servers - choices: [present, query] - default: present - type: str - net_name: - description: - - Name of a network. - aliases: [name, network] - type: str - net_id: - description: - - ID number of a network. - type: str - servers: - description: - - List of syslog server settings. - type: list - suboptions: - host: - description: - - IP address or hostname of Syslog server. - type: str - port: - description: - - Port number Syslog server is listening on. - default: "514" - type: int - roles: - description: - - List of applicable Syslog server roles. - choices: ['Wireless Event log', - 'Appliance event log', - 'Switch event log', - 'Air Marshal events', - 'Flows', - 'URLs', - 'IDS alerts', - 'Security events'] - type: list - -author: - - Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query syslog configurations on network named MyNet in the YourOrg organization - meraki_syslog: - auth_key: abc12345 - status: query - org_name: YourOrg - net_name: MyNet - delegate_to: localhost - -- name: Add single syslog server with Appliance event log role - meraki_syslog: - auth_key: abc12345 - status: query - org_name: YourOrg - net_name: MyNet - servers: - - host: 192.0.1.2 - port: 514 - roles: - - Appliance event log - delegate_to: localhost - -- name: Add multiple syslog servers - meraki_syslog: - auth_key: abc12345 - status: query - org_name: YourOrg - net_name: MyNet - servers: - - host: 192.0.1.2 - port: 514 - roles: - - Appliance event log - - host: 192.0.1.3 - port: 514 - roles: - - Appliance event log - - Flows - delegate_to: localhost -''' - -RETURN = r''' -data: - description: Information about the created or manipulated object. - returned: info - type: complex - contains: - host: - description: Hostname or IP address of syslog server. - returned: success - type: str - sample: 192.0.1.1 - port: - description: Port number for syslog communication. - returned: success - type: str - sample: 443 - roles: - description: List of roles assigned to syslog server. - returned: success - type: list - sample: "Wireless event log, URLs" -''' - -from ansible.module_utils.basic import AnsibleModule, json -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def main(): - - # define the available arguments/parameters that a user can pass to - # the module - - server_arg_spec = dict(host=dict(type='str'), - port=dict(type='int', default="514"), - roles=dict(type='list', choices=['Wireless Event log', - 'Appliance event log', - 'Switch event log', - 'Air Marshal events', - 'Flows', - 'URLs', - 'IDS alerts', - 'Security events', - ]), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update(net_id=dict(type='str'), - servers=dict(type='list', elements='dict', options=server_arg_spec), - state=dict(type='str', choices=['present', 'query'], default='present'), - net_name=dict(type='str', aliases=['name', 'network']), - ) - - # 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='syslog') - module.params['follow_redirects'] = 'all' - payload = None - - syslog_urls = {'syslog': '/networks/{net_id}/syslogServers'} - meraki.url_catalog['query_update'] = syslog_urls - - if not meraki.params['org_name'] and not meraki.params['org_id']: - meraki.fail_json(msg='org_name or org_id parameters are required') - if meraki.params['state'] != 'query': - if not meraki.params['net_name'] and not meraki.params['net_id']: - meraki.fail_json(msg='net_name or net_id is required for present or absent states') - if meraki.params['net_name'] and meraki.params['net_id']: - meraki.fail_json(msg='net_name and net_id are mutually exclusive') - - # if the user is working with this module in only check mode we do not - # want to make any changes to the environment, just return the current - # state with no modifications - - # 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 not org_id: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - path = meraki.construct_path('query_update', net_id=net_id) - r = meraki.request(path, method='GET') - if meraki.status == 200: - meraki.result['data'] = r - elif meraki.params['state'] == 'present': - # Construct payload - payload = dict() - payload['servers'] = meraki.params['servers'] - - # Convert port numbers to string for idempotency checks - for server in payload['servers']: - if server['port']: - server['port'] = str(server['port']) - path = meraki.construct_path('query_update', net_id=net_id) - r = meraki.request(path, method='GET') - if meraki.status == 200: - original = dict() - original['servers'] = r - - if meraki.is_update_required(original, payload): - if meraki.module.check_mode is True: - diff = recursive_diff(original, payload) - original.update(payload) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1]} - meraki.result['data'] = original - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - path = meraki.construct_path('query_update', net_id=net_id) - r = meraki.request(path, method='PUT', payload=json.dumps(payload)) - if meraki.status == 200: - meraki.result['data'] = r - meraki.result['changed'] = True - else: - if meraki.module.check_mode is True: - meraki.result['data'] = original - meraki.exit_json(**meraki.result) - 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() diff --git a/lib/ansible/modules/network/meraki/meraki_vlan.py b/lib/ansible/modules/network/meraki/meraki_vlan.py deleted file mode 100644 index 3cb17e7492e..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_vlan.py +++ /dev/null @@ -1,446 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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_vlan -short_description: Manage VLANs in the Meraki cloud -version_added: "2.7" -description: -- Create, edit, query, or delete VLANs in a Meraki environment. -notes: -- Meraki's API will return an error if VLANs aren't enabled on a network. VLANs are returned properly if VLANs are enabled on a network. -- Some of the options are likely only used for developers within Meraki. -- Meraki's API defaults to networks having VLAN support disabled and there is no way to enable VLANs support in the API. VLAN support must be enabled manually. -options: - state: - description: - - Specifies whether object should be queried, created/modified, or removed. - choices: [absent, present, query] - default: query - type: str - net_name: - description: - - Name of network which VLAN is in or should be in. - aliases: [network] - type: str - net_id: - description: - - ID of network which VLAN is in or should be in. - type: str - vlan_id: - description: - - ID number of VLAN. - - ID should be between 1-4096. - type: int - name: - description: - - Name of VLAN. - aliases: [vlan_name] - type: str - subnet: - description: - - CIDR notation of network subnet. - type: str - appliance_ip: - description: - - IP address of appliance. - - Address must be within subnet specified in C(subnet) parameter. - type: str - dns_nameservers: - description: - - Semi-colon delimited list of DNS IP addresses. - - Specify one of the following options for preprogrammed DNS entries opendns, google_dns, upstream_dns - type: str - reserved_ip_range: - description: - - IP address ranges which should be reserve and not distributed via DHCP. - type: list - vpn_nat_subnet: - description: - - The translated VPN subnet if VPN and VPN subnet translation are enabled on the VLAN. - type: str - fixed_ip_assignments: - description: - - Static IP address assignments to be distributed via DHCP by MAC address. - type: list -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Query all VLANs in a network. - meraki_vlan: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - state: query - delegate_to: localhost - -- name: Query information about a single VLAN by ID. - meraki_vlan: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - vlan_id: 2 - state: query - delegate_to: localhost - -- name: Create a VLAN. - meraki_vlan: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - state: present - vlan_id: 2 - name: TestVLAN - subnet: 192.0.1.0/24 - appliance_ip: 192.0.1.1 - delegate_to: localhost - -- name: Update a VLAN. - meraki_vlan: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - state: present - vlan_id: 2 - name: TestVLAN - subnet: 192.0.1.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - -- name: Delete a VLAN. - meraki_vlan: - auth_key: abc12345 - org_name: YourOrg - net_name: YourNet - state: absent - vlan_id: 2 - delegate_to: localhost -''' - -RETURN = r''' - -response: - description: Information about the organization which was created or modified - returned: success - type: complex - contains: - appliance_ip: - description: IP address of Meraki appliance in the VLAN - returned: success - type: str - sample: 192.0.1.1 - dnsnamservers: - description: IP address or Meraki defined DNS servers which VLAN should use by default - returned: success - type: str - sample: upstream_dns - fixed_ip_assignments: - description: List of MAC addresses which have IP addresses assigned. - returned: success - type: complex - contains: - macaddress: - description: MAC address which has IP address assigned to it. Key value is the actual MAC address. - returned: success - type: complex - contains: - ip: - description: IP address which is assigned to the MAC address. - returned: success - type: str - sample: 192.0.1.4 - name: - description: Descriptive name for binding. - returned: success - type: str - sample: fixed_ip - reserved_ip_ranges: - description: List of IP address ranges which are reserved for static assignment. - returned: success - type: complex - contains: - comment: - description: Description for IP address reservation. - returned: success - type: str - sample: reserved_range - end: - description: Last IP address in reservation range. - returned: success - type: str - sample: 192.0.1.10 - start: - description: First IP address in reservation range. - returned: success - type: str - sample: 192.0.1.5 - id: - description: VLAN ID number. - returned: success - type: int - sample: 2 - name: - description: Descriptive name of VLAN. - returned: success - type: str - sample: TestVLAN - networkId: - description: ID number of Meraki network which VLAN is associated to. - returned: success - type: str - sample: N_12345 - subnet: - description: CIDR notation IP subnet of VLAN. - returned: success - type: str - sample: "192.0.1.0/24" - dhcp_handling: - description: Status of DHCP server on VLAN. - returned: success - type: str - sample: Run a DHCP server - dhcp_lease_time: - description: DHCP lease time when server is active. - returned: success - type: str - sample: 1 day - dhcp_boot_options_enabled: - description: Whether DHCP boot options are enabled. - returned: success - type: bool - sample: no - dhcp_boot_next_server: - description: DHCP boot option to direct boot clients to the server to load the boot file from. - returned: success - type: str - sample: 192.0.1.2 - dhcp_boot_filename: - description: Filename for boot file. - returned: success - type: str - sample: boot.txt - dhcp_options: - description: DHCP options. - returned: success - type: complex - contains: - code: - description: - - Code for DHCP option. - - Integer between 2 and 254. - returned: success - type: int - sample: 43 - type: - description: - - Type for DHCP option. - - Choices are C(text), C(ip), C(hex), C(integer). - returned: success - type: str - sample: text - value: - description: Value for the DHCP option. - returned: success - type: str - sample: 192.0.1.2 -''' - -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils._text import to_native -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def fixed_ip_factory(meraki, data): - fixed_ips = dict() - for item in data: - fixed_ips[item['mac']] = {'ip': item['ip'], 'name': item['name']} - return fixed_ips - - -def get_vlans(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - return meraki.request(path, method='GET') - - -# TODO: Allow method to return actual item if True to reduce number of calls needed -def is_vlan_valid(meraki, net_id, vlan_id): - vlans = get_vlans(meraki, net_id) - for vlan in vlans: - if vlan_id == vlan['id']: - return True - return False - - -def format_dns(nameservers): - return nameservers.replace(';', '\n') - - -def main(): - # define the available arguments/parameters that a user can pass to - # the module - - fixed_ip_arg_spec = dict(mac=dict(type='str'), - ip=dict(type='str'), - name=dict(type='str'), - ) - - reserved_ip_arg_spec = dict(start=dict(type='str'), - end=dict(type='str'), - comment=dict(type='str'), - ) - - argument_spec = meraki_argument_spec() - argument_spec.update(state=dict(type='str', choices=['absent', 'present', 'query'], default='query'), - net_name=dict(type='str', aliases=['network']), - net_id=dict(type='str'), - vlan_id=dict(type='int'), - name=dict(type='str', aliases=['vlan_name']), - subnet=dict(type='str'), - appliance_ip=dict(type='str'), - fixed_ip_assignments=dict(type='list', default=None, elements='dict', options=fixed_ip_arg_spec), - reserved_ip_range=dict(type='list', default=None, elements='dict', options=reserved_ip_arg_spec), - vpn_nat_subnet=dict(type='str'), - dns_nameservers=dict(type='str'), - ) - - # 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='vlan') - - meraki.params['follow_redirects'] = 'all' - - query_urls = {'vlan': '/networks/{net_id}/vlans'} - query_url = {'vlan': '/networks/{net_id}/vlans/{vlan_id}'} - create_url = {'vlan': '/networks/{net_id}/vlans'} - update_url = {'vlan': '/networks/{net_id}/vlans/'} - delete_url = {'vlan': '/networks/{net_id}/vlans/'} - - meraki.url_catalog['get_all'].update(query_urls) - meraki.url_catalog['get_one'].update(query_url) - meraki.url_catalog['create'] = create_url - meraki.url_catalog['update'] = update_url - meraki.url_catalog['delete'] = delete_url - - payload = None - - org_id = meraki.params['org_id'] - if org_id is None: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - - if meraki.params['state'] == 'query': - if not meraki.params['vlan_id']: - meraki.result['data'] = get_vlans(meraki, net_id) - else: - path = meraki.construct_path('get_one', net_id=net_id, custom={'vlan_id': meraki.params['vlan_id']}) - response = meraki.request(path, method='GET') - meraki.result['data'] = response - elif meraki.params['state'] == 'present': - payload = {'id': meraki.params['vlan_id'], - 'name': meraki.params['name'], - 'subnet': meraki.params['subnet'], - 'applianceIp': meraki.params['appliance_ip'], - } - if is_vlan_valid(meraki, net_id, meraki.params['vlan_id']) is False: # Create new VLAN - if meraki.module.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) - response = meraki.request(path, method='POST', payload=json.dumps(payload)) - meraki.result['changed'] = True - meraki.result['data'] = response - else: # Update existing VLAN - path = meraki.construct_path('get_one', net_id=net_id, custom={'vlan_id': meraki.params['vlan_id']}) - original = meraki.request(path, method='GET') - if meraki.params['dns_nameservers']: - if meraki.params['dns_nameservers'] not in ('opendns', 'google_dns', 'upstream_dns'): - payload['dnsNameservers'] = format_dns(meraki.params['dns_nameservers']) - else: - payload['dnsNameservers'] = meraki.params['dns_nameservers'] - if meraki.params['fixed_ip_assignments']: - payload['fixedIpAssignments'] = fixed_ip_factory(meraki, meraki.params['fixed_ip_assignments']) - if meraki.params['reserved_ip_range']: - payload['reservedIpRanges'] = meraki.params['reserved_ip_range'] - if meraki.params['vpn_nat_subnet']: - payload['vpnNatSubnet'] = meraki.params['vpn_nat_subnet'] - ignored = ['networkId'] - if meraki.is_update_required(original, payload, optional_ignore=ignored): - meraki.result['diff'] = dict() - diff = recursive_diff(original, payload) - meraki.result['diff']['before'] = diff[0] - meraki.result['diff']['after'] = diff[1] - if meraki.module.check_mode is True: - original.update(payload) - meraki.result['changed'] = True - meraki.result['data'] = original - meraki.exit_json(**meraki.result) - path = meraki.construct_path('update', net_id=net_id) + str(meraki.params['vlan_id']) - response = meraki.request(path, method='PUT', payload=json.dumps(payload)) - meraki.result['changed'] = True - meraki.result['data'] = response - else: - if meraki.module.check_mode is True: - meraki.result['data'] = original - meraki.exit_json(**meraki.result) - meraki.result['data'] = original - elif meraki.params['state'] == 'absent': - if is_vlan_valid(meraki, net_id, meraki.params['vlan_id']): - if meraki.module.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) + str(meraki.params['vlan_id']) - response = meraki.request(path, 'DELETE') - meraki.result['changed'] = True - meraki.result['data'] = response - - # 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() diff --git a/lib/ansible/modules/network/meraki/meraki_webhook.py b/lib/ansible/modules/network/meraki/meraki_webhook.py deleted file mode 100644 index 53fc62ffa53..00000000000 --- a/lib/ansible/modules/network/meraki/meraki_webhook.py +++ /dev/null @@ -1,342 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Kevin Breit (@kbreit) -# 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_webhook -short_description: Manage webhooks configured in the Meraki cloud -version_added: "2.9" -description: -- Configure and query information about webhooks within the Meraki cloud. -notes: -- Some of the options are likely only used for developers within Meraki. -options: - state: - description: - - Specifies whether object should be queried, created/modified, or removed. - choices: [absent, present, query] - default: query - type: str - net_name: - description: - - Name of network which configuration is applied to. - aliases: [network] - type: str - net_id: - description: - - ID of network which configuration is applied to. - type: str - name: - description: - - Name of webhook. - type: str - shared_secret: - description: - - Secret password to use when accessing webhook. - type: str - url: - description: - - URL to access when calling webhook. - type: str - webhook_id: - description: - - Unique ID of webhook. - type: str - test: - description: - - Indicates whether to test or query status. - type: str - choices: [test, status] - test_id: - description: - - ID of webhook test query. - type: str -author: -- Kevin Breit (@kbreit) -extends_documentation_fragment: meraki -''' - -EXAMPLES = r''' -- name: Create webhook - meraki_webhook: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - name: Test_Hook - url: https://webhook.url/ - shared_secret: shhhdonttellanyone - delegate_to: localhost - -- name: Query one webhook - meraki_webhook: - auth_key: abc123 - state: query - org_name: YourOrg - net_name: YourNet - name: Test_Hook - delegate_to: localhost - -- name: Query all webhooks - meraki_webhook: - auth_key: abc123 - state: query - org_name: YourOrg - net_name: YourNet - delegate_to: localhost - -- name: Delete webhook - meraki_webhook: - auth_key: abc123 - state: absent - org_name: YourOrg - net_name: YourNet - name: Test_Hook - delegate_to: localhost - -- name: Test webhook - meraki_webhook: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - test: test - url: https://webhook.url/abc123 - delegate_to: localhost - -- name: Get webhook status - meraki_webhook: - auth_key: abc123 - state: present - org_name: YourOrg - net_name: YourNet - test: status - test_id: abc123531234 - delegate_to: localhost -''' - -RETURN = r''' -data: - description: List of administrators. - returned: success - type: complex - contains: - id: - description: Unique ID of webhook. - returned: success - type: str - sample: aHR0cHM6Ly93ZWJob22LnvpdGUvOGViNWI3NmYtYjE2Ny00Y2I4LTlmYzQtND32Mj3F5NzIaMjQ0 - name: - description: Descriptive name of webhook. - returned: success - type: str - sample: Test_Hook - networkId: - description: ID of network containing webhook object. - returned: success - type: str - sample: N_12345 - shared_secret: - description: Password for webhook. - returned: success - type: str - sample: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER - url: - description: URL of webhook endpoint. - returned: success - type: str - sample: https://webhook.url/abc123 - status: - description: Status of webhook test. - returned: success, when testing webhook - type: str - sample: enqueued -''' - -import os -from ansible.module_utils.basic import AnsibleModule, json, env_fallback -from ansible.module_utils._text import to_native -from ansible.module_utils.common.dict_transformations import recursive_diff -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec - - -def get_webhook_id(name, webhooks): - for webhook in webhooks: - if name == webhook['name']: - return webhook['id'] - return None - - -def get_all_webhooks(meraki, net_id): - path = meraki.construct_path('get_all', net_id=net_id) - response = meraki.request(path, method='GET') - if meraki.status == 200: - return response - - -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=['absent', 'present', 'query'], default='query'), - net_name=dict(type='str', aliases=['network']), - net_id=dict(type='str'), - name=dict(type='str'), - url=dict(type='str'), - shared_secret=dict(type='str', no_log=True), - webhook_id=dict(type='str'), - test=dict(type='str', choices=['test', 'status']), - test_id=dict(type='str'), - ) - - # 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='webhooks') - - meraki.params['follow_redirects'] = 'all' - - query_url = {'webhooks': '/networks/{net_id}/httpServers'} - query_one_url = {'webhooks': '/networks/{net_id}/httpServers/{hookid}'} - create_url = {'webhooks': '/networks/{net_id}/httpServers'} - update_url = {'webhooks': '/networks/{net_id}/httpServers/{hookid}'} - delete_url = {'webhooks': '/networks/{net_id}/httpServers/{hookid}'} - test_url = {'webhooks': '/networks/{net_id}/httpServers/webhookTests'} - test_status_url = {'webhooks': '/networks/{net_id}/httpServers/webhookTests/{testid}'} - - meraki.url_catalog['get_all'].update(query_url) - meraki.url_catalog['get_one'].update(query_one_url) - meraki.url_catalog['create'] = create_url - meraki.url_catalog['update'] = update_url - meraki.url_catalog['delete'] = delete_url - meraki.url_catalog['test'] = test_url - meraki.url_catalog['test_status'] = test_status_url - - org_id = meraki.params['org_id'] - if org_id is None: - org_id = meraki.get_org_id(meraki.params['org_name']) - net_id = meraki.params['net_id'] - if net_id is None: - nets = meraki.get_nets(org_id=org_id) - net_id = meraki.get_net_id(net_name=meraki.params['net_name'], data=nets) - webhook_id = meraki.params['webhook_id'] - if webhook_id is None and meraki.params['name']: - webhooks = get_all_webhooks(meraki, net_id) - webhook_id = get_webhook_id(meraki.params['name'], webhooks) - - if meraki.params['state'] == 'present' and meraki.params['test'] is None: - payload = {'name': meraki.params['name'], - 'url': meraki.params['url'], - 'sharedSecret': meraki.params['shared_secret']} - - if meraki.params['state'] == 'query': - if webhook_id is not None: # Query a single webhook - path = meraki.construct_path('get_one', net_id=net_id, custom={'hookid': webhook_id}) - response = meraki.request(path, method='GET') - if meraki.status == 200: - meraki.result['data'] = response - else: - path = meraki.construct_path('get_all', net_id=net_id) - response = meraki.request(path, method='GET') - if meraki.status == 200: - meraki.result['data'] = response - elif meraki.params['state'] == 'present': - if meraki.params['test'] == 'test': - payload = {'url': meraki.params['url']} - path = meraki.construct_path('test', net_id=net_id) - response = meraki.request(path, method='POST', payload=json.dumps(payload)) - if meraki.status == 200: - meraki.result['data'] = response - meraki.exit_json(**meraki.result) - elif meraki.params['test'] == 'status': - if meraki.params['test_id'] is None: - meraki.fail_json("test_id is required when querying test status.") - path = meraki.construct_path('test_status', net_id=net_id, custom={'testid': meraki.params['test_id']}) - response = meraki.request(path, method='GET') - if meraki.status == 200: - meraki.result['data'] = response - meraki.exit_json(**meraki.result) - if webhook_id is None: # Make sure it is downloaded - if webhooks is None: - webhooks = get_all_webhooks(meraki, net_id) - webhook_id = get_webhook_id(meraki.params['name'], webhooks) - if webhook_id is None: # Test to see if it needs to be created - if meraki.check_mode is True: - meraki.result['data'] = payload - meraki.result['data']['networkId'] = net_id - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - 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: # Need to update - path = meraki.construct_path('get_one', net_id=net_id, custom={'hookid': webhook_id}) - original = meraki.request(path, method='GET') - if meraki.is_update_required(original, payload): - if meraki.check_mode is True: - diff = recursive_diff(original, payload) - original.update(payload) - meraki.result['diff'] = {'before': diff[0], - 'after': diff[1]} - meraki.result['data'] = original - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - path = meraki.construct_path('update', net_id=net_id, custom={'hookid': webhook_id}) - 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'] = original - elif meraki.params['state'] == 'absent': - if webhook_id is None: # Make sure it is downloaded - if webhooks is None: - webhooks = get_all_webhooks(meraki, net_id) - webhook_id = get_webhook_id(meraki.params['name'], webhooks) - if webhook_id is None: - meraki.fail_json(msg="There is no webhook with the name {0}".format(meraki.params['name'])) - if webhook_id: # Test to see if it exists - if meraki.module.check_mode is True: - meraki.result['data'] = None - meraki.result['changed'] = True - meraki.exit_json(**meraki.result) - path = meraki.construct_path('delete', net_id=net_id, custom={'hookid': webhook_id}) - response = meraki.request(path, method='DELETE') - if meraki.status == 204: - 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) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/plugins/doc_fragments/meraki.py b/lib/ansible/plugins/doc_fragments/meraki.py deleted file mode 100644 index 8a5cd98d943..00000000000 --- a/lib/ansible/plugins/doc_fragments/meraki.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -class ModuleDocFragment(object): - # Standard files for documentation fragment - DOCUMENTATION = r''' -notes: -- More information about the Meraki API can be found at U(https://dashboard.meraki.com/api_docs). -- Some of the options are likely only used for developers within Meraki. -- As of Ansible 2.9, Meraki modules output keys as snake case. To use camel case, set the C(ANSIBLE_MERAKI_FORMAT) environment variable to C(camelcase). -- Ansible's Meraki modules will stop supporting camel case output in Ansible 2.13. Please update your playbooks. -options: - auth_key: - description: - - Authentication key provided by the dashboard. Required if environmental variable C(MERAKI_KEY) is not set. - type: str - required: yes - host: - description: - - Hostname for Meraki dashboard. - - Can be used to access regional Meraki environments, such as China. - type: str - default: api.meraki.com - use_proxy: - description: - - If C(no), it will not use a proxy, even if one is defined in an environment variable on the target hosts. - type: bool - use_https: - description: - - If C(no), it will use HTTP. Otherwise it will use HTTPS. - - Only useful for internal Meraki developers. - type: bool - default: yes - output_format: - description: - - Instructs module whether response keys should be snake case (ex. C(net_id)) or camel case (ex. C(netId)). - type: str - choices: [snakecase, camelcase] - default: snakecase - output_level: - description: - - Set amount of debug output during module execution. - type: str - choices: [ debug, normal ] - default: normal - timeout: - description: - - Time to timeout for HTTP requests. - type: int - default: 30 - validate_certs: - description: - - Whether to validate HTTP certificates. - type: bool - default: yes - org_name: - description: - - Name of organization. - type: str - aliases: [ organization ] - org_id: - description: - - ID of organization. - type: str - rate_limit_retry_time: - description: - - Number of seconds to retry if rate limiter is triggered. - type: int - default: 165 - internal_error_retry_time: - description: - - Number of seconds to retry if server returns an internal server error. - type: int - default: 60 -''' diff --git a/test/integration/targets/meraki_admin/tasks/main.yml b/test/integration/targets/meraki_admin/tasks/main.yml deleted file mode 100644 index 2fcc9eb6e91..00000000000 --- a/test/integration/targets/meraki_admin/tasks/main.yml +++ /dev/null @@ -1,384 +0,0 @@ -# Test code for the Meraki Admin module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Create new administrator in check mode - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jane Doe - email: '{{email_prefix}}+janedoe@{{email_domain}}' - org_access: read-only - delegate_to: localhost - check_mode: yes - register: create_org_check - - - name: Create new admin check mode assertion - assert: - that: - - create_org_check is changed - - 'create_org_check.data.name == "Jane Doe"' - - - name: Create new administrator - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jane Doe - email: '{{email_prefix}}+janedoe@{{email_domain}}' - org_access: read-only - delegate_to: localhost - register: create_orgaccess - - - name: Create new admin assertion - assert: - that: - - create_orgaccess.changed == true - - 'create_orgaccess.data.name == "Jane Doe"' - - - name: Delete recently created administrator with check mode - meraki_admin: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - email: '{{email_prefix}}+janedoe@{{email_domain}}' - delegate_to: localhost - register: delete_one_check - check_mode: yes - - - assert: - that: - - delete_one_check is changed - - - name: Delete recently created administrator - meraki_admin: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - email: '{{email_prefix}}+janedoe@{{email_domain}}' - delegate_to: localhost - register: delete_one - - - name: Create new administrator with org_id - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_id: '{{test_org_id}}' - name: Jane Doe - email: '{{email_prefix}}+janedoe@{{email_domain}}' - orgAccess: read-only - delegate_to: localhost - register: create_orgaccess_id - - - name: Create new admin assertion - assert: - that: - - create_orgaccess_id.changed == true - - 'create_orgaccess_id.data.name == "Jane Doe"' - - - name: Create administrator with tags with check mode - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: John Doe - email: '{{email_prefix}}+johndoe@{{email_domain}}' - orgAccess: none - tags: - - { "tag": "production", "access": "read-only" } - - tag: beta - access: full - delegate_to: localhost - register: create_tags_check - check_mode: yes - - - debug: - var: create_tags_check - - - assert: - that: - - create_tags_check is changed - - create_tags_check.data.name == "John Doe" - - create_tags_check.data.tags | length == 2 - - - name: Create administrator with tags - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: John Doe - email: '{{email_prefix}}+johndoe@{{email_domain}}' - orgAccess: none - tags: - - { "tag": "production", "access": "read-only" } - - tag: beta - access: full - delegate_to: localhost - register: create_tags - - - assert: - that: - - create_tags.changed == true - - create_tags.data.name == "John Doe" - - create_tags.data.tags | length == 2 - - - name: Create administrator with invalid tags - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jake Doe - email: '{{email_prefix}}+jakedoe@{{email_domain}}' - orgAccess: none - tags: - - { "tag": "production", "access": "read-only" } - - { "tag": "alpha", "access": "invalid" } - delegate_to: localhost - register: create_tags_invalid - ignore_errors: yes - - - assert: - that: - - '"400" in create_tags_invalid.msg' - # - '"must contain only valid tags" in create_tags_invalid.msg' - - - name: Create administrator with invalid tag permission - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jake Doe - email: '{{email_prefix}}+jakedoe@{{email_domain}}' - orgAccess: none - tags: - - { "tag": "production", "access": "read-only" } - - { "tag": "beta", "access": "invalid" } - delegate_to: localhost - register: create_tags_invalid_permission - ignore_errors: yes - - - assert: - that: - - '"400" in create_tags_invalid_permission.msg' - # - '"Invalid permission type" in create_tags_invalid_permission.msg' - - - name: Make sure TestNet and TestNet2 are created - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{item}}' - type: switch - loop: - - TestNet - - TestNet2 - - - name: Create administrator with networks with check mode - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jim Doe - email: '{{email_prefix}}+jimdoe@{{email_domain}}' - orgAccess: none - networks: - - { "network": "TestNet", "access": "read-only" } - - { "network": "TestNet2", "access": "full" } - delegate_to: localhost - register: create_network_check - check_mode: yes - - - assert: - that: - - create_network_check is changed - - create_network_check.data.name == "Jim Doe" - - create_network_check.data.networks | length == 2 - - - name: Create administrator with networks - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jim Doe - email: '{{email_prefix}}+jimdoe@{{email_domain}}' - orgAccess: none - networks: - - { "network": "TestNet", "access": "read-only" } - - { "network": "TestNet2", "access": "full" } - delegate_to: localhost - register: create_network - - - assert: - that: - - create_network.changed == true - - create_network.data.name == "Jim Doe" - - create_network.data.networks | length == 2 - - - name: Update administrator with check mode - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jim Doe - email: '{{email_prefix}}+jimdoe@{{email_domain}}' - orgAccess: none - networks: - - { "network": "TestNet", "access": "full" } - delegate_to: localhost - register: update_network_check - check_mode: yes - - - debug: - var: update_network_check - - - assert: - that: - - update_network_check is changed - - update_network_check.data.networks.0.access == "full" - - update_network_check.data.networks | length == 1 - - - name: Update administrator - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jim Doe - email: '{{email_prefix}}+jimdoe@{{email_domain}}' - orgAccess: none - networks: - - { "network": "TestNet", "access": "full" } - delegate_to: localhost - register: update_network - - - assert: - that: - - update_network.changed == true - - update_network.data.networks.0.access == "full" - - update_network.data.networks | length == 1 - - - name: Update administrator for idempotency check with check mode - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jim Doe - email: '{{email_prefix}}+jimdoe@{{email_domain}}' - orgAccess: none - networks: - - { "network": "TestNet", "access": "full" } - delegate_to: localhost - register: update_network_idempotent_check - check_mode: yes - - - debug: - var: update_network_idempotent_check - - - assert: - that: - - update_network_idempotent_check is not changed - - - name: Update administrator for idempotency - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: Jim Doe - email: '{{email_prefix}}+jimdoe@{{email_domain}}' - orgAccess: none - networks: - - { "network": "TestNet", "access": "full" } - delegate_to: localhost - register: update_network_idempotent - - - assert: - that: - - update_network_idempotent.changed == false - - update_network_idempotent.data is defined - - - name: Create administrator with invalid network - meraki_admin: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - name: John Doe - email: '{{email_prefix}}+John@{{email_domain}}' - orgAccess: none - networks: - - { "network": "readnet", "access": "read-only" } - delegate_to: localhost - register: create_network_invalid - ignore_errors: yes - - - assert: - that: - - '"No network found with the name" in create_network_invalid.msg' - # - '"400" in create_network_invalid.msg' - - - name: Query all administrators - meraki_admin: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - delegate_to: localhost - register: query_all - - - assert: - that: - - query_all.data | length == 4 - - query_all.changed == False - - - name: Query admin by name - meraki_admin: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - name: Jane Doe - delegate_to: localhost - register: query_name - - - name: Query admin by email - meraki_admin: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - email: '{{email_prefix}}+janedoe@{{email_domain}}' - delegate_to: localhost - register: query_email - - - assert: - that: - - query_name.data.name == "Jane Doe" - - 'query_email.data.email == "{{email_prefix}}+janedoe@{{email_domain}}"' - - always: - ############################################################################# - # Tear down starts here - ############################################################################# - - name: Delete administrators - meraki_admin: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - email: '{{item}}' - delegate_to: localhost - register: delete_all - ignore_errors: yes - loop: - - '{{email_prefix}}+janedoe@{{email_domain}}' - - '{{email_prefix}}+johndoe@{{email_domain}}' - - '{{email_prefix}}+jimdoe@{{email_domain}}' - - - name: Query all administrators - meraki_admin: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - delegate_to: localhost - register: query_all_deleted - - - assert: - that: - - query_all_deleted.data | length == 1 \ No newline at end of file diff --git a/test/integration/targets/meraki_config_template/aliases b/test/integration/targets/meraki_config_template/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_config_template/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_config_template/tasks/main.yml b/test/integration/targets/meraki_config_template/tasks/main.yml deleted file mode 100644 index 12b18d1a280..00000000000 --- a/test/integration/targets/meraki_config_template/tasks/main.yml +++ /dev/null @@ -1,196 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Query all configuration templates - meraki_config_template: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - register: get_all - - - name: Delete non-existant configuration template - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - config_template: FakeConfigTemplate - register: deleted - ignore_errors: yes - - - assert: - that: - - '"No configuration template named" in deleted.msg' - - - name: Create a network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - type: appliance - delegate_to: localhost - register: net_info - - - set_fact: - net_id: '{{net_info.data.id}}' - - - name: Bind a template to a network with check mode - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: '{{test_template_name}}' - check_mode: yes - register: bind_check - - - name: Bind a template to a network - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: '{{test_template_name}}' - register: bind - - - assert: - that: - bind.changed == True - - - assert: - that: - bind_check is changed - - - name: Bind a template to a network when it's already bound - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: '{{test_template_name}}' - register: bind_invalid - ignore_errors: yes - - - assert: - that: - - bind_invalid.changed == False - - - name: Unbind a template from a network - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: '{{test_template_name}}' - register: unbind - - - assert: - that: - unbind.changed == True - - - name: Unbind a template from a network when it's not bound - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: '{{test_template_name}}' - register: unbind_invalid - - - assert: - that: - unbind_invalid.changed == False - - - name: Bind a template to a network via id - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_id: '{{net_id}}' - config_template: '{{test_template_name}}' - register: bind_id - - - assert: - that: - bind_id.changed == True - - - name: Bind a template to a network via id for idempotency - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_id: '{{net_id}}' - config_template: '{{test_template_name}}' - register: bind_id_idempotent - - - assert: - that: - - bind_id_idempotent.changed == False - - bind_id_idempotent.data is defined - - - name: Unbind a template from a network via id with check mode - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_id: '{{net_id}}' - config_template: '{{test_template_name}}' - check_mode: yes - register: unbind_id_check - - - assert: - that: - unbind_id_check is changed - - - name: Unbind a template from a network via id - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_id: '{{net_id}}' - config_template: '{{test_template_name}}' - register: unbind_id - - - assert: - that: - unbind_id.changed == True - - # This is disabled by default since they can't be created via API - - name: Delete sacrificial template with check mode - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - config_template: sacrificial_template - check_mode: yes - register: delete_template_check - - # This is disabled by default since they can't be created via API - - name: Delete sacrificial template - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - config_template: sacrificial_template - output_level: debug - register: delete_template - - - debug: - var: delete_template - - always: - - name: Delete network - meraki_network: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - delegate_to: localhost diff --git a/test/integration/targets/meraki_content_filtering/aliases b/test/integration/targets/meraki_content_filtering/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_content_filtering/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_content_filtering/meraki_config_template/aliases b/test/integration/targets/meraki_content_filtering/meraki_config_template/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_content_filtering/meraki_config_template/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_content_filtering/meraki_config_template/tasks/main.yml b/test/integration/targets/meraki_content_filtering/meraki_config_template/tasks/main.yml deleted file mode 100644 index 4bec7d21deb..00000000000 --- a/test/integration/targets/meraki_content_filtering/meraki_config_template/tasks/main.yml +++ /dev/null @@ -1,117 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Use an invalid domain - meraki_config_template: - auth_key: '{{ auth_key }}' - host: marrrraki.com - state: query - org_name: DevTestOrg - output_level: debug - delegate_to: localhost - register: invalid_domain - ignore_errors: yes - - - name: Connection assertions - assert: - that: - - '"Failed to connect to" in invalid_domain.msg' - - - name: Query all configuration templates - meraki_config_template: - auth_key: '{{auth_key}}' - state: query - org_name: DevTestOrg - register: get_all - - - name: Delete non-existant configuration template - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: DevTestOrg - config_template: DevConfigTemplateInvalid - register: deleted - ignore_errors: yes - - - assert: - that: - - '"No configuration template named" in deleted.msg' - - - name: Create a network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - type: appliance - delegate_to: localhost - - - name: Bind a template to a network - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: DevConfigTemplate - register: bind - - - assert: - that: - bind.changed == True - - - name: Bind a template to a network when it's already bound - meraki_config_template: - auth_key: '{{auth_key}}' - state: present - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: DevConfigTemplate - register: bind_invalid - ignore_errors: yes - - - assert: - that: - - bind_invalid.changed == False - - - name: Unbind a template from a network - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: DevConfigTemplate - register: unbind - - - assert: - that: - unbind.changed == True - - - name: Unbind a template from a network when it's not bound - meraki_config_template: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - config_template: DevConfigTemplate - register: unbind_invalid - - - assert: - that: - unbind_invalid.changed == False - - always: - - name: Delete network - meraki_network: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{ test_org_name }}' - net_name: '{{ test_net_name }}' - delegate_to: localhost \ No newline at end of file diff --git a/test/integration/targets/meraki_content_filtering/tasks/main.yml b/test/integration/targets/meraki_content_filtering/tasks/main.yml deleted file mode 100644 index 92cf19d2ad2..00000000000 --- a/test/integration/targets/meraki_content_filtering/tasks/main.yml +++ /dev/null @@ -1,247 +0,0 @@ -# Test code for the Meraki Content Filteringmodule -# Copyright: (c) 2019, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create network - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - type: appliance - timezone: America/Chicago - delegate_to: localhost - register: create_net_appliance - - - name: Test net_name and id exclusivity - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - net_id: 12345 - state: present - allowed_urls: - - "http://www.ansible.com/*" - register: net_exclusive - ignore_errors: yes - - - assert: - that: - - 'net_exclusive.msg == "net_name and net_id are mutually exclusive"' - - - name: Set single allowed URL pattern with check mode - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - allowed_urls: - - "http://www.ansible.com/*" - register: single_allowed_check - check_mode: yes - - - assert: - that: - - single_allowed_check.data.allowed_url_patterns | length == 1 - - single_allowed_check is changed - - - name: Set single allowed URL pattern - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - allowed_urls: - - "http://www.ansible.com/*" - register: single_allowed - - - assert: - that: - - single_allowed.data.allowed_url_patterns | length == 1 - - - name: Set single allowed URL pattern for idempotency with check mode - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - allowed_urls: - - "http://www.ansible.com/*" - register: single_allowed_idempotent_check - check_mode: yes - - - debug: - var: single_allowed_idempotent_check - - - assert: - that: - - single_allowed_idempotent_check is not changed - - single_allowed.data.allowed_url_patterns | length == 1 - - - name: Set single allowed URL pattern for idempotency - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - allowed_urls: - - "http://www.ansible.com/*" - register: single_allowed_idempotent - - - debug: - var: single_allowed_idempotent - - - assert: - that: - - single_allowed_idempotent.changed == False - - single_allowed_idempotent.data is defined - - - name: Set single blocked URL pattern - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - blocked_urls: - - "http://www.ansible.com/*" - register: single_blocked - - - debug: - var: single_blocked - - - assert: - that: - - single_blocked.data.blocked_url_patterns | length == 1 - - - name: Set two allowed URL pattern - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - allowed_urls: - - "http://www.ansible.com/*" - - "http://www.redhat.com" - register: two_allowed - - - debug: - var: two_allowed - - - assert: - that: - - two_allowed.changed == True - - two_allowed.data.allowed_url_patterns | length == 2 - - - name: Set blocked URL category - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - category_list_size: full list - blocked_categories: - - "Adult and Pornography" - register: blocked_category - - - debug: - var: blocked_category - - - assert: - that: - - blocked_category.changed == True - - blocked_category.data.blocked_url_categories | length == 1 - - blocked_category.data.url_category_list_size == "fullList" - - - name: Set blocked URL category with top sites - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - category_list_size: top sites - blocked_categories: - - "Adult and Pornography" - register: blocked_category - - - debug: - var: blocked_category - - - assert: - that: - - blocked_category.changed == True - - blocked_category.data.blocked_url_categories | length == 1 - - blocked_category.data.url_category_list_size == "topSites" - - - name: Query all content filtering information - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - delegate_to: localhost - register: query_all - - - debug: - var: query_all - - - name: Query all content filtering assertion - assert: - that: - - query_all.data.categories is defined - - query_all.data.policy is defined - - - name: Query categories - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - subset: categories - delegate_to: localhost - register: query_categories - - - debug: - var: query_categories - - - name: Query categories assertion - assert: - that: - - query_categories.data is defined - - - name: Query content filtering policies - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - subset: policy - state: query - delegate_to: localhost - register: query_policy - - - debug: - var: query_policy - - - name: Query contnet filtering policy assertion - assert: - that: - - query_policy.data is defined - - always: - - name: Reset policies - meraki_content_filtering: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - category_list_size: full list - allowed_urls: - - - blocked_urls: - - diff --git a/test/integration/targets/meraki_device/aliases b/test/integration/targets/meraki_device/aliases deleted file mode 100644 index 89aea537d13..00000000000 --- a/test/integration/targets/meraki_device/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported \ No newline at end of file diff --git a/test/integration/targets/meraki_device/tasks/main.yml b/test/integration/targets/meraki_device/tasks/main.yml deleted file mode 100644 index e0a973ab9bc..00000000000 --- a/test/integration/targets/meraki_device/tasks/main.yml +++ /dev/null @@ -1,215 +0,0 @@ ---- -- block: - # This is commented out because a device cannot be unclaimed via API - # - name: Claim a device into an organization - # meraki_device: - # auth_key: '{{auth_key}}' - # org_name: '{{test_org_name}}' - # serial: '{{serial}}' - # state: present - # delegate_to: localhost - # register: claim_device_org - - # - assert: - # that: - # - claim_device_org.changed == true - - - name: Query status of all devices in an organization - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: query - delegate_to: localhost - register: query_device_org - - - debug: - msg: '{{query_device_org}}' - - - name: Claim a device into a network - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial: '{{serial}}' - state: present - delegate_to: localhost - register: claim_device - - - debug: - msg: '{{claim_device}}' - - - assert: - that: - - claim_device.changed == true - - - name: Query all devices in one network by network ID - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_id: '{{test_net_id}}' - state: query - delegate_to: localhost - register: query_one_net_id - - - debug: - msg: '{{query_one_net_id}}' - - - name: Query all devices in one network - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - delegate_to: localhost - register: query_one_net - - - debug: - msg: '{{query_one_net}}' - - - name: Query device by serial - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - serial: '{{serial}}' - state: query - delegate_to: localhost - register: query_serial_no_net - - - debug: - msg: '{{query_serial_no_net}}' - - - name: Query device by serial - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial: '{{serial}}' - state: query - delegate_to: localhost - register: query_serial - - - debug: - msg: '{{query_serial}}' - - - assert: - that: - - query_serial.changed == False - - - name: Query uplink information for a device - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial_uplink: '{{serial}}' - state: query - delegate_to: localhost - register: query_serial_uplink - - - debug: - msg: '{{query_serial_uplink}}' - - - name: Query LLDP/CDP information about a device - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial_lldp_cdp: '{{serial}}' - lldp_cdp_timespan: 6000 - state: query - delegate_to: localhost - register: query_serial_lldp_cdp - - - debug: - msg: '{{query_serial_lldp_cdp}}' - - - name: Query a device by hostname - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - hostname: test-hostname - state: query - delegate_to: localhost - register: query_hostname - - - debug: - msg: '{{query_hostname}}' - - - name: Query a device by model - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - model: MR26 - state: query - delegate_to: localhost - register: query_model - - - debug: - msg: '{{query_model}}' - - - name: Update a device - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial: '{{serial}}' - name: mr26 - address: 1060 W. Addison St., Chicago, IL - lat: 41.948038 - lng: -87.65568 - tags: recently-added - state: present - move_map_marker: True - note: Test device notes - delegate_to: localhost - register: update_device - - - assert: - that: - - update_device.changed == true - - update_device.data.0.notes == "Test device notes" - - '"1060 W. Addison St., Chicago, IL" in update_device.data.0.address' - - - name: Update a device with idempotency - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial: '{{serial}}' - name: mr26 - address: 1060 W. Addison St., Chicago, IL - lat: 41.948038 - lng: -87.65568 - tags: recently-added - state: present - move_map_marker: True - note: Test device notes - delegate_to: localhost - register: update_device_idempotent - - - debug: - msg: '{{update_device_idempotent}}' - - - assert: - that: - - update_device_idempotent.changed == False - - update_device_idempotent.data is defined - - always: - - name: Remove a device from a network - meraki_device: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - serial: '{{serial}}' - state: absent - delegate_to: localhost - register: delete_device - - - debug: - msg: '{{delete_device}}' - - - assert: - that: - - delete_device.changed == true \ No newline at end of file diff --git a/test/integration/targets/meraki_firewalled_services/aliases b/test/integration/targets/meraki_firewalled_services/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_firewalled_services/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_firewalled_services/tasks/main.yml b/test/integration/targets/meraki_firewalled_services/tasks/main.yml deleted file mode 100644 index 60aa04a9635..00000000000 --- a/test/integration/targets/meraki_firewalled_services/tasks/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Test code for the Meraki Firewalled Services module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- name: Run test cases - include: tests.yml ansible_connection=local diff --git a/test/integration/targets/meraki_firewalled_services/tasks/tests.yml b/test/integration/targets/meraki_firewalled_services/tasks/tests.yml deleted file mode 100644 index ec23edf2210..00000000000 --- a/test/integration/targets/meraki_firewalled_services/tasks/tests.yml +++ /dev/null @@ -1,196 +0,0 @@ -# Test code for the Meraki modules -# Copyright: (c) 2019, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Create network - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - type: appliance - register: create - - - set_fact: - net_id: create.data.id - - - name: Set icmp service to blocked with check mode - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: ICMP - access: blocked - register: icmp_blocked_check - check_mode: yes - - - debug: - var: icmp_blocked_check - - - assert: - that: - - icmp_blocked_check.data is defined - - icmp_blocked_check is changed - - - name: Set icmp service to blocked - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: ICMP - access: blocked - register: icmp_blocked - - - debug: - var: icmp_blocked - - - assert: - that: - - icmp_blocked.data is defined - - icmp_blocked is changed - - - name: Set icmp service to blocked with idempotency - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: ICMP - access: blocked - register: icmp_blocked_idempotent - - - debug: - var: icmp_blocked_idempotent - - - assert: - that: - - icmp_blocked_idempotent.data is defined - - icmp_blocked_idempotent is not changed - - - name: Set icmp service to restricted with check mode - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: web - access: restricted - allowed_ips: - - 192.0.1.1 - - 192.0.1.2 - check_mode: yes - register: web_restricted_check - - - debug: - var: web_restricted_check - - - assert: - that: - - web_restricted_check.data is defined - - web_restricted_check is changed - - - name: Set icmp service to restricted - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: web - access: restricted - allowed_ips: - - 192.0.1.1 - - 192.0.1.2 - register: web_restricted - - - debug: - var: web_restricted - - - assert: - that: - - web_restricted.data is defined - - web_restricted is changed - - - name: Set icmp service to restricted with idempotency - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: web - access: restricted - allowed_ips: - - 192.0.1.1 - - 192.0.1.2 - register: web_restricted_idempotent - - - debug: - var: web_restricted_idempotent - - - assert: - that: - - web_restricted_idempotent.data is defined - - web_restricted_idempotent is not changed - - - name: Test error for access restricted and allowed_ips - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: web - access: unrestricted - allowed_ips: - - 192.0.1.1 - - 192.0.1.2 - register: access_error - ignore_errors: yes - - - assert: - that: - - 'access_error.msg == "allowed_ips is only allowed when access is restricted."' - - - name: Query appliance services - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: query - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - register: query_appliance - - - debug: - var: query_appliance - - - assert: - that: - - query_appliance.data is defined - - - name: Query services - meraki_firewalled_services: - auth_key: '{{ auth_key }}' - state: query - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - service: ICMP - register: query_service - - - debug: - var: query_service - - - assert: - that: - - query_service.data is defined - -############################################################################# -# Tear down starts here -############################################################################# - always: - - name: Delete all networks - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance diff --git a/test/integration/targets/meraki_malware/aliases b/test/integration/targets/meraki_malware/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_malware/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_malware/tasks/main.yml b/test/integration/targets/meraki_malware/tasks/main.yml deleted file mode 100644 index b387479debb..00000000000 --- a/test/integration/targets/meraki_malware/tasks/main.yml +++ /dev/null @@ -1,247 +0,0 @@ -# Test code for the Meraki VLAN module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create test network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - type: appliance - delegate_to: localhost - register: net - - - set_fact: - net_id: '{{net.data.id}}' - - - name: Enable malware protection with check mode - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - delegate_to: localhost - check_mode: yes - register: get_malware_check - - - assert: - that: - - get_malware_check is changed - - get_malware_check.data is defined - - - name: Enable malware protection - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - delegate_to: localhost - register: get_malware - - - debug: - var: get_malware - - - assert: - that: - - get_malware is changed - - get_malware.data.mode is defined - - - name: Enable malware protection with idempotency - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - delegate_to: localhost - register: get_malware_idempotent - - - debug: - var: get_malware_idempotent - - - assert: - that: - - get_malware_idempotent is not changed - - get_malware_idempotent.data is defined - - - name: Test error when mode is not set - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - allowed_files: - - sha256: e82c5f7d75004727e1f3b94426b9a11c8bc4c312a9170ac9a73abace40aef503 - comment: random zip - delegate_to: localhost - register: test_mode_err - ignore_errors: yes - - - assert: - that: - - test_mode_err.msg == "mode must be set when allowed_files or allowed_urls is set." - - - name: Set whitelisted file with check mode - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - allowed_files: - - sha256: e82c5f7d75004727e1f3b94426b9a11c8bc4c312a9170ac9a73abace40aef503 - comment: random zip - delegate_to: localhost - check_mode: yes - register: set_file_check - - - debug: - var: - set_file_check - - - assert: - that: - - set_file_check is changed - - set_file_check.data is defined - - - name: Set whitelisted file - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_id: '{{net_id}}' - mode: enabled - allowed_files: - - sha256: e82c5f7d75004727e1f3b94426b9a11c8bc4c312a9170ac9a73abace40aef503 - comment: random zip - delegate_to: localhost - register: set_file - - - debug: - var: set_file - - - assert: - that: - - set_file is changed - - set_file.data.mode is defined - - - name: Set whitelisted file with idempotency - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - allowed_files: - - sha256: e82c5f7d75004727e1f3b94426b9a11c8bc4c312a9170ac9a73abace40aef503 - comment: random zip - delegate_to: localhost - register: set_file_idempotent - - - debug: - var: set_file_idempotent - - - assert: - that: - - set_file_idempotent is not changed - - set_file_idempotent.data is defined - - - name: Set whitelisted url with check mode - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - allowed_urls: - - url: www.google.com - comment: Google - delegate_to: localhost - check_mode: yes - register: set_url_check - - - debug: - var: - set_url_check - - - assert: - that: - - set_url_check is changed - - set_url_check.data is defined - - - name: Set whitelisted url - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - allowed_urls: - - url: www.google.com - comment: Google - delegate_to: localhost - register: set_url - - - debug: - var: set_url - - - assert: - that: - - set_url is changed - - set_url.data.mode is defined - - - name: Set whitelisted url with idempotency - meraki_malware: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - mode: enabled - allowed_urls: - - url: www.google.com - comment: Google - delegate_to: localhost - register: set_url_idempotent - - - debug: - var: set_url_idempotent - - - assert: - that: - - set_url_idempotent is not changed - - set_url_idempotent.data is defined - - - name: Get malware settings - meraki_malware: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - delegate_to: localhost - register: get_malware - - - assert: - that: - - get_malware.data is defined - - ############################################################################# - # Tear down starts here - ############################################################################# - always: - - name: Delete test network - meraki_network: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}} - Malware' - delegate_to: localhost diff --git a/test/integration/targets/meraki_mr_l3_firewall/aliases b/test/integration/targets/meraki_mr_l3_firewall/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_mr_l3_firewall/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_mr_l3_firewall/tasks/main.yml b/test/integration/targets/meraki_mr_l3_firewall/tasks/main.yml deleted file mode 100644 index 75a110b2851..00000000000 --- a/test/integration/targets/meraki_mr_l3_firewall/tasks/main.yml +++ /dev/null @@ -1,100 +0,0 @@ -# Test code for the Meraki modules -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Create wireless network - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetWireless - type: wireless - delegate_to: localhost - register: new_net - - - set_fact: - net: '{{new_net.data.id}}' - - - name: Create single firewall rule - meraki_mr_l3_firewall: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_id: '{{net}}' - number: 1 - rules: - - comment: Integration test rule - policy: allow - protocol: tcp - dest_port: 80 - dest_cidr: 192.0.2.0/24 - allow_lan_access: no - delegate_to: localhost - register: create_one - - - debug: - msg: '{{create_one}}' - - - assert: - that: - - create_one.data.0.comment == 'Integration test rule' - - create_one.data.1.policy == 'deny' - - create_one.data is defined - - - name: Enable local LAN access - meraki_mr_l3_firewall: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_id: '{{net}}' - number: 1 - rules: - allow_lan_access: yes - delegate_to: localhost - register: enable_lan - - - assert: - that: - - enable_lan.data.1.policy == 'allow' - - - name: Query firewall rules - meraki_mr_l3_firewall: - auth_key: '{{ auth_key }}' - state: query - org_name: '{{test_org_name}}' - net_id: '{{net}}' - number: 1 - delegate_to: localhost - register: query - - - debug: - msg: '{{query}}' - - - assert: - that: - - query.data.1.comment == 'Wireless clients accessing LAN' - - query.data.2.comment == 'Default rule' - - query.changed == False - -############################################################################ -# Tear down starts here -############################################################################ - always: - - name: Delete wireless SSID - meraki_ssid: - auth_key: '{{ auth_key }}' - state: absent - org_name: '{{test_org_name}}' - net_id: '{{net}}' - number: 1 - delegate_to: localhost - - - name: Delete wireless network - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - org_name: '{{test_org_name}}' - net_id: '{{net}}' - delegate_to: localhost diff --git a/test/integration/targets/meraki_mx_l3_firewall/aliases b/test/integration/targets/meraki_mx_l3_firewall/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_mx_l3_firewall/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_mx_l3_firewall/tasks/main.yml b/test/integration/targets/meraki_mx_l3_firewall/tasks/main.yml deleted file mode 100644 index cc70f9788c7..00000000000 --- a/test/integration/targets/meraki_mx_l3_firewall/tasks/main.yml +++ /dev/null @@ -1,203 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create network - meraki_network: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - type: appliance - delegate_to: localhost - - - name: Query firewall rules - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: query - delegate_to: localhost - register: query - - - assert: - that: - - query.data|length == 1 - - - name: Set one firewall rule - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - comment: Deny to documentation address - src_port: any - src_cidr: any - dest_port: 80,443 - dest_cidr: 192.0.1.1/32 - protocol: tcp - policy: deny - delegate_to: localhost - register: create_one - - - debug: - var: create_one - - - assert: - that: - - create_one.data|length == 2 - - create_one.data.0.dest_cidr == '192.0.1.1/32' - - create_one.data.0.protocol == 'tcp' - - create_one.data.0.policy == 'deny' - - create_one.changed == True - - create_one.data is defined - - - name: Check for idempotency - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - comment: Deny to documentation address - src_port: any - src_cidr: any - dest_port: 80,443 - dest_cidr: 192.0.1.1/32 - protocol: tcp - policy: deny - delegate_to: localhost - register: create_one_idempotent - - - debug: - msg: '{{create_one_idempotent}}' - - - assert: - that: - - create_one_idempotent.changed == False - - create_one_idempotent.data is defined - - - name: Create syslog in network - meraki_syslog: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - servers: - - host: 192.0.2.10 - port: 514 - roles: - - Appliance event log - - Flows - delegate_to: localhost - - - name: Enable syslog for default rule - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - comment: Deny to documentation address - src_port: any - src_cidr: any - dest_port: 80,443 - dest_cidr: 192.0.1.1/32 - protocol: tcp - policy: deny - syslog_default_rule: yes - delegate_to: localhost - register: default_syslog - - - debug: - msg: '{{default_syslog}}' - - - assert: - that: - - default_syslog.data is defined - - - name: Query firewall rules - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: query - delegate_to: localhost - register: query - - - debug: - msg: '{{query.data.1}}' - - - assert: - that: - - query.data.1.syslog_enabled == True - - default_syslog.changed == True - - - name: Disable syslog for default rule - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - comment: Deny to documentation address - src_port: any - src_cidr: any - dest_port: 80,443 - dest_cidr: 192.0.1.1/32 - protocol: tcp - policy: deny - syslog_default_rule: no - delegate_to: localhost - register: disable_syslog - - - debug: - msg: '{{disable_syslog}}' - - - assert: - that: - - disable_syslog.data is defined - - - name: Query firewall rules - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: query - delegate_to: localhost - register: query - - - debug: - msg: '{{query.data.1}}' - - - assert: - that: - - query.data.1.syslog_enabled == False - - disable_syslog.changed == True - - always: - - name: Delete all firewall rules - meraki_mx_l3_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: [] - delegate_to: localhost - register: delete_all - - - name: Delete network - meraki_network: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: absent - delegate_to: localhost diff --git a/test/integration/targets/meraki_mx_l7_firewall/aliases b/test/integration/targets/meraki_mx_l7_firewall/aliases deleted file mode 100644 index 06fe32bc66d..00000000000 --- a/test/integration/targets/meraki_mx_l7_firewall/aliases +++ /dev/null @@ -1,2 +0,0 @@ -unsupported - diff --git a/test/integration/targets/meraki_mx_l7_firewall/tasks/main.yml b/test/integration/targets/meraki_mx_l7_firewall/tasks/main.yml deleted file mode 100644 index bb4c6fc5941..00000000000 --- a/test/integration/targets/meraki_mx_l7_firewall/tasks/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- name: Run test cases - include: tests.yml ansible_connection=local \ No newline at end of file diff --git a/test/integration/targets/meraki_mx_l7_firewall/tasks/tests.yml b/test/integration/targets/meraki_mx_l7_firewall/tasks/tests.yml deleted file mode 100644 index 72adef560ec..00000000000 --- a/test/integration/targets/meraki_mx_l7_firewall/tasks/tests.yml +++ /dev/null @@ -1,494 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create network - meraki_network: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - type: appliance - - - name: Query firewall rules - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: query - register: query - - - debug: - var: query - - - assert: - that: - - query.data is defined - - - name: Query firewall application categories - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: query - categories: yes - register: query_categories - - - assert: - that: - - query_categories.data is defined - - - name: Create firewall rule for IP range in check mode - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range_check - check_mode: yes - - - debug: - var: create_ip_range_check - - - assert: - that: - - create_ip_range_check is changed - - - name: Create firewall rule for IP range - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range - - - debug: - var: create_ip_range - - - assert: - that: - - create_ip_range is changed - - create_ip_range.data.rules | length == 1 - - - name: Create firewall rule for IP range with idempotency with check mode - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range_idempotent_check - check_mode: yes - - - assert: - that: - - create_ip_range_idempotent_check is not changed - - - name: Create firewall rule for IP range with idempotency - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range_idempotent - - - assert: - that: - - create_ip_range_idempotent is not changed - - - name: Create firewall rule for IP and port - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.1:23 - register: create_ip_range_port - - - debug: - var: create_ip_range_port - - - assert: - that: - - create_ip_range_port is changed - - - name: Create firewall rule for IP range - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range - - - debug: - var: create_ip_range - - - assert: - that: - - create_ip_range is changed - - create_ip_range.data.rules | length == 1 - - - name: Create firewall rule for IP range with idempotency with check mode - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range_idempotent_check - check_mode: yes - - - assert: - that: - - create_ip_range_idempotent_check is not changed - - - name: Create firewall rule for IP range with idempotency - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: ip_range - ip_range: 10.11.12.0/24 - register: create_ip_range_idempotent - - - assert: - that: - - create_ip_range_idempotent is not changed - - - name: Create firewall rule for application - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application - application: - name: facebook - register: application_rule - - - assert: - that: - - application_rule is changed - - application_rule.data.rules is defined - - - name: Create firewall rule for application via ID - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application - application: - id: meraki:layer7/application/205 - register: application_rule_id - - - assert: - that: - - application_rule_id is changed - - - name: Create firewall rule for invalid application - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application - application: - name: ansible - register: application_rule_invalid - ignore_errors: yes - - - name: Create firewall rule for application category - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application_category - application: - name: Advertising - register: application_category_rule - - - debug: - var: application_category_rule - - - assert: - that: - - application_category_rule is changed - - - name: Create firewall rule for application category with ID and conflict - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application_category - application: - id: meraki:layer7/category/27 - register: application_category_rule_id_conflict - - - assert: - that: - - application_category_rule_id_conflict is not changed - - - name: Create firewall rule for application category with ID - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application_category - application: - id: meraki:layer7/category/24 - register: application_category_rule_id - - - assert: - that: - - application_category_rule_id is changed - - - name: Create firewall rule for host - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: host - host: asdf.com - register: host_rule - - - assert: - that: - - host_rule is changed - - - name: Create firewall rule for port - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: port - port: 1234 - register: port_rule - - - assert: - that: - - port_rule is changed - - - name: Create firewall rule for blacklisted countries - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: blacklisted_countries - countries: - - CA - - AX - register: blacklist_countries - - - assert: - that: - - blacklist_countries is changed - - - name: Create firewall rule for whitelisted countries - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: whitelisted_countries - countries: - - US - - FR - register: whitelist_countries - - - assert: - that: - - whitelist_countries is changed - - - name: Create firewall rule for whitelisted countries with idempotency - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: whitelisted_countries - countries: - - US - - FR - register: whitelist_countries_idempotent - - - assert: - that: - - whitelist_countries_idempotent is not changed - - - name: Create multiple firewall rules - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application_category - application: - id: meraki:layer7/category/27 - - type: blacklisted_countries - countries: - - CN - - policy: deny - type: port - port: 8080 - register: multiple_rules - - - debug: - var: multiple_rules - - - assert: - that: - - multiple_rules.data.rules | length == 3 - - multiple_rules is changed - - ######################################### - ## Tests for argument completeness ## - ######################################### - - - name: Test whitelisted_countries incomplete arguments - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: whitelisted_countries - register: error_whitelist - ignore_errors: yes - - - assert: - that: - - 'error_whitelist.msg == "countries argument is required when type is whitelisted_countries."' - - - name: Test blacklisted_countries incomplete arguments - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: blacklisted_countries - register: error_blacklist - ignore_errors: yes - - - assert: - that: - - 'error_blacklist.msg == "countries argument is required when type is blacklisted_countries."' - - - name: Test application_category incomplete arguments - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application_category - register: error_app_cat - ignore_errors: yes - - - assert: - that: - - 'error_app_cat.msg == "application argument is required when type is application_category."' - - - name: Test application incomplete arguments - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: application - register: error_app_cat - ignore_errors: yes - - - assert: - that: - - 'error_app_cat.msg == "application argument is required when type is application."' - - - name: Test host incomplete arguments - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: host - register: error_app_cat - ignore_errors: yes - - - assert: - that: - - 'error_app_cat.msg == "host argument is required when type is host."' - - - name: Test port incomplete arguments - meraki_mx_l7_firewall: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: TestNetAppliance - state: present - rules: - - type: port - register: error_app_cat - ignore_errors: yes - - - assert: - that: - - 'error_app_cat.msg == "port argument is required when type is port."' - - ################# - ## Cleanup ## - ################# - - # always: - # - name: Delete network - # meraki_network: - # auth_key: '{{ auth_key }}' - # org_name: '{{test_org_name}}' - # net_name: TestNetAppliance - # state: absent - # delegate_to: localhost diff --git a/test/integration/targets/meraki_nat/tasks/main.yml b/test/integration/targets/meraki_nat/tasks/main.yml deleted file mode 100644 index 721a93007b9..00000000000 --- a/test/integration/targets/meraki_nat/tasks/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- name: Run test cases - include: tests.yml ansible_connection=local diff --git a/test/integration/targets/meraki_nat/tasks/tests.yml b/test/integration/targets/meraki_nat/tasks/tests.yml deleted file mode 100644 index 11193d135e9..00000000000 --- a/test/integration/targets/meraki_nat/tasks/tests.yml +++ /dev/null @@ -1,363 +0,0 @@ -# Test code for the Meraki NAT module -# Copyright: (c) 2019, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Create test network - meraki_network: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - type: appliance - - - name: Create 1:1 rule with check mode - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - one_to_one: - - name: Service behind NAT - public_ip: 1.2.1.2 - lan_ip: 192.168.128.1 - uplink: internet1 - allowed_inbound: - - protocol: tcp - destination_ports: - - 80 - allowed_ips: - - 10.10.10.10 - register: create_one_one_check - check_mode: yes - - - debug: - var: create_one_one_check - - - assert: - that: - - create_one_one_check is changed - - - name: Create 1:1 rule - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - one_to_one: - - name: Service behind NAT - public_ip: 1.2.1.2 - lan_ip: 192.168.128.1 - uplink: internet1 - allowed_inbound: - - protocol: tcp - destination_ports: - - 80 - allowed_ips: - - 10.10.10.10 - register: create_one_one - - - debug: - var: create_one_one - - - assert: - that: - - create_one_one is changed - - - name: Create 1:1 rule with idempotency - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - one_to_one: - - name: Service behind NAT - public_ip: 1.2.1.2 - lan_ip: 192.168.128.1 - uplink: internet1 - allowed_inbound: - - protocol: tcp - destination_ports: - - 80 - allowed_ips: - - 10.10.10.10 - register: create_one_one_idempotent - - - debug: - var: create_one_one_idempotent - - - assert: - that: - - create_one_one_idempotent is not changed - - - name: Create 1:many rule with check mode - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - one_to_many: - - public_ip: 1.1.1.1 - uplink: internet1 - port_rules: - - name: Test rule - protocol: tcp - public_port: 10 - local_ip: 192.168.128.1 - local_port: 11 - allowed_ips: - - any - register: create_one_many_check - check_mode: yes - - - debug: - var: create_one_many_check - - - assert: - that: - - create_one_many_check is changed - - - name: Create 1:many rule - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - one_to_many: - - public_ip: 1.1.1.1 - uplink: internet1 - port_rules: - - name: Test rule - protocol: tcp - public_port: 10 - local_ip: 192.168.128.1 - local_port: 11 - allowed_ips: - - any - register: create_one_many - - - debug: - var: create_one_many - - - assert: - that: - - create_one_many is changed - - - name: Create 1:many rule with idempotency - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - one_to_many: - - public_ip: 1.1.1.1 - uplink: internet1 - port_rules: - - name: Test rule - protocol: tcp - public_port: 10 - local_ip: 192.168.128.1 - local_port: 11 - allowed_ips: - - any - register: create_one_many_idempotent - - - debug: - var: create_one_many_idempotent - - - assert: - that: - - create_one_many_idempotent is not changed - - - name: Create port forwarding rule with check mode - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - port_forwarding: - - name: Test map - lan_ip: 192.168.128.1 - uplink: both - protocol: tcp - allowed_ips: - - 1.1.1.1 - public_port: 10 - local_port: 11 - register: create_pf_check - check_mode: yes - - - debug: - var: create_pf_check - - - assert: - that: - - create_pf_check is changed - - - name: Create port forwarding rule - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - port_forwarding: - - name: Test map - lan_ip: 192.168.128.1 - uplink: both - protocol: tcp - allowed_ips: - - 1.1.1.1 - public_port: 10 - local_port: 11 - register: create_pf - - - debug: - var: create_pf - - - assert: - that: - - create_pf is changed - - - name: Create port forwarding rule with idempotency - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - port_forwarding: - - name: Test map - lan_ip: 192.168.128.1 - uplink: both - protocol: tcp - allowed_ips: - - 1.1.1.1 - public_port: 10 - local_port: 11 - register: create_pf_idempotent - - - debug: - var: create_pf_idempotent - - - assert: - that: - - create_pf_idempotent is not changed - - create_pf_idempotent.data.port_forwarding is defined - - - name: Create multiple rules - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - port_forwarding: - - name: Test map - lan_ip: 192.168.128.1 - uplink: both - protocol: tcp - allowed_ips: - - 1.1.1.2 - public_port: 10 - local_port: 11 - one_to_many: - - public_ip: 1.1.1.3 - uplink: internet1 - port_rules: - - name: Test rule - protocol: tcp - public_port: 10 - local_ip: 192.168.128.1 - local_port: 11 - allowed_ips: - - any - register: create_multiple - - - debug: - var: create_multiple - - - assert: - that: - - create_multiple is changed - - create_multiple.data.one_to_many is defined - - create_multiple.data.port_forwarding is defined - - - assert: - that: - - create_multiple is changed - - create_multiple.data.one_to_many is defined - - create_multiple.data.port_forwarding is defined - - create_multiple.diff.before.one_to_many is defined - - create_multiple.diff.before.port_forwarding is defined - - create_multiple.diff.after.one_to_many is defined - - create_multiple.diff.after.port_forwarding is defined - - - name: Query all NAT rules - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - subset: all - register: query_all - - - debug: - var: query_all - - - name: Query 1:1 NAT rules - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - subset: '1:1' - register: query_1to1 - - - debug: - var: query_1to1 - - - name: Query 1:many NAT rules - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - subset: '1:many' - register: query_1tomany - - - debug: - var: query_1tomany - - - name: Query port forwarding rules - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - subset: port_forwarding - register: query_pf - - - debug: - var: query_pf - - - name: Query multiple rules - meraki_nat: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - subset: - - '1:1' - - '1:many' - register: query_multiple - - - debug: - var: query_multiple - - always: - - name: Delete test network - meraki_network: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: absent - \ No newline at end of file diff --git a/test/integration/targets/meraki_network/aliases b/test/integration/targets/meraki_network/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_network/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_network/tasks/main.yml b/test/integration/targets/meraki_network/tasks/main.yml deleted file mode 100644 index c81c7f9ab11..00000000000 --- a/test/integration/targets/meraki_network/tasks/main.yml +++ /dev/null @@ -1,402 +0,0 @@ -# Test code for the Meraki modules -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Create network without type - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - timezone: America/Chicago - delegate_to: localhost - register: create_net_no_type - ignore_errors: yes - - - assert: - that: - - create_net_no_type.msg == 'type parameter is required when creating a network.' - - - name: Create network without organization - meraki_network: - auth_key: '{{ auth_key }}' - state: present - net_name: IntTestNetwork - timezone: America/Chicago - delegate_to: localhost - register: create_net_no_org - ignore_errors: yes - - - name: Create network with type switch - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkSwitch - type: switch - timezone: America/Chicago - delegate_to: localhost - register: create_net_switch - - - name: Create network with type switch by org ID - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_id: '{{test_org_id}}' - net_name: IntTestNetworkSwitchOrgID - type: switch - timezone: America/Chicago - delegate_to: localhost - register: create_net_switch_org_id - - - name: Create network with type appliance and no timezone - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkAppliance - type: appliance - delegate_to: localhost - register: create_net_appliance_no_tz - - - name: Enable VLAN support on appliance network - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{ test_org_name }}' - net_name: IntTestNetworkAppliance - enable_vlans: yes - delegate_to: localhost - register: enable_vlan - - - assert: - that: - - enable_vlan.data.enabled == True - - - name: Enable VLAN support on appliance network with idempotency - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{ test_org_name }}' - net_name: IntTestNetworkAppliance - enable_vlans: yes - delegate_to: localhost - register: enable_vlan_idempotent - - - debug: - var: enable_vlan_idempotent - - - assert: - that: - - enable_vlan_idempotent is not changed - - enable_vlan_idempotent.data is defined - - - name: Disable VLAN support on appliance network - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{ test_org_name }}' - net_name: IntTestNetworkAppliance - enable_vlans: no - delegate_to: localhost - register: disable_vlan - - - assert: - that: - - disable_vlan.data.enabled == False - - - name: Disable VLAN support on appliance network with idempotency - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{ test_org_name }}' - net_name: IntTestNetworkAppliance - enable_vlans: no - delegate_to: localhost - register: disable_vlan_idempotent - - - assert: - that: - - disable_vlan_idempotent is not changed - - disable_vlan_idempotent.data is defined - - - name: Create network with type wireless and disable my.meraki.com - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkWireless - type: wireless - timezone: America/Chicago - disable_my_meraki: yes - delegate_to: localhost - register: create_net_wireless - - - name: Create network with type wireless, disable my.meraki.com, and check for idempotency - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkWireless - type: wireless - timezone: America/Chicago - disable_my_meraki: yes - delegate_to: localhost - register: create_net_wireless_idempotent - - - assert: - that: - - create_net_wireless_idempotent.data is defined - - - name: Create network with type combined and disable my.meraki.com - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{ test_org_name }}' - net_name: IntTestNetworkCombined - type: - - appliance - - switch - timezone: America/Chicago - enable_my_meraki: no - delegate_to: localhost - register: create_net_combined - - - name: Reenable my.meraki.com - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkCombined - enable_my_meraki: yes - delegate_to: localhost - register: enable_meraki_com - - - name: Disable my.meraki.com for next test - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkCombined - enable_my_meraki: no - delegate_to: localhost - - - name: Enable remote status page - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkCombined - enable_remote_status_page: yes - delegate_to: localhost - register: disable_remote_status - - - debug: - msg: '{{disable_remote_status}}' - - - assert: - that: - - disable_remote_status.data.disable_remote_status_page == False - - - name: Disable remote status page - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkCombined - enable_remote_status_page: no - delegate_to: localhost - register: enable_remote_status - - - debug: - msg: '{{enable_remote_status}}' - - - assert: - that: - - enable_remote_status.data.disable_remote_status_page == True - - - name: Test status pages are mutually exclusive when on - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkCombined - enable_my_meraki: yes - enable_remote_status_page: no - delegate_to: localhost - register: status_exclusivity - ignore_errors: yes - - - assert: - that: - - '"must be true when setting" in status_exclusivity.msg' - - - name: Create network with one tag - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkTag - type: switch - timezone: America/Chicago - tags: first_tag - delegate_to: localhost - register: create_net_tag - - - name: Create network with two tags - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkTags - type: switch - timezone: America/Chicago - tags: - - first_tag - - second_tag - delegate_to: localhost - register: create_net_tags - - - set_fact: - tag_net_id: '{{create_net_tags.data.id}}' - - - name: Modify network by net_id - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_id: '{{tag_net_id}}' - type: switch - timezone: America/Chicago - tags: - - first_tag - - second_tag - - third_tag - delegate_to: localhost - register: create_net_modified - - - name: Modify network with idempotency - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetworkTags - type: switch - timezone: America/Chicago - tags: - - first_tag - - second_tag - - third_tag - delegate_to: localhost - register: create_net_modified_idempotent - - - assert: - that: - - create_net_modified_idempotent.data is defined - - - name: Present assertions - assert: - that: - - create_net_combined.data.type == 'combined' - - create_net_combined.data.disable_my_meraki_com == True - - enable_meraki_com.data.disable_my_meraki_com == False - - '"org_name or org_id parameters are required" in create_net_no_org.msg' - - '"IntTestNetworkAppliance" in create_net_appliance_no_tz.data.name' - - create_net_appliance_no_tz.changed == True - - '"IntTestNetworkSwitch" in create_net_switch.data.name' - - '"IntTestNetworkSwitchOrgID" in create_net_switch_org_id.data.name' - - '"IntTestNetworkWireless" in create_net_wireless.data.name' - - create_net_wireless.data.disable_my_meraki_com == True - - create_net_wireless_idempotent.changed == False - - create_net_wireless_idempotent.data is defined - - '"first_tag" in create_net_tag.data.tags' - - '"second_tag" in create_net_tags.data.tags' - - '"third_tag" in create_net_modified.data.tags' - - create_net_modified.changed == True - - create_net_modified_idempotent.changed == False - - create_net_modified_idempotent.data is defined - - - name: Query all networks - meraki_network: - auth_key: '{{ auth_key }}' - state: query - org_name: '{{test_org_name}}' - delegate_to: localhost - register: net_query_all - - - name: Query a configuration template - meraki_network: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: '{{test_template_name}}' - delegate_to: localhost - register: query_config_template - - - name: Query one network - meraki_network: - auth_key: '{{ auth_key }}' - state: query - org_name: '{{test_org_name}}' - net_name: IntTestNetworkSwitch - delegate_to: localhost - register: net_query_one - - - name: Query assertions - assert: - that: - - 'net_query_one.data.name == "IntTestNetworkSwitch"' - - 'query_config_template.data.name == "{{ test_template_name }}"' - -############################################################################# -# Tear down starts here -############################################################################# - always: - - name: Delete network without org - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - net_name: IntTestNetworkSwitch - delegate_to: localhost - register: delete_all_no_org - ignore_errors: yes - - - name: Delete network by org ID - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - org_id: '{{test_org_id}}' - net_name: IntTestNetworkSwitchOrgID - delegate_to: localhost - register: delete_net_org_id - - - name: Query after delete with org ID - meraki_network: - auth_key: '{{ auth_key }}' - state: query - org_name: '{{test_org_name}}' - delegate_to: localhost - register: query_deleted_org_id - - - name: Delete all networks - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{ item }}' - delegate_to: localhost - register: delete_all - ignore_errors: yes - loop: - - IntTestNetworkSwitch - - IntTestNetworkWireless - - IntTestNetworkAppliance - - IntTestNetworkCombined - - IntTestNetworkTag - - IntTestNetworkTags - - - assert: - that: - - 'delete_all_no_org.msg == "org_name or org_id parameters are required"' diff --git a/test/integration/targets/meraki_organization/aliases b/test/integration/targets/meraki_organization/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_organization/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_organization/tasks/main.yml b/test/integration/targets/meraki_organization/tasks/main.yml deleted file mode 100644 index e7ad65b8115..00000000000 --- a/test/integration/targets/meraki_organization/tasks/main.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- name: Run test cases - include: tests.yml ansible_connection=local - \ No newline at end of file diff --git a/test/integration/targets/meraki_organization/tasks/tests.yml b/test/integration/targets/meraki_organization/tasks/tests.yml deleted file mode 100644 index 75ba93c6b91..00000000000 --- a/test/integration/targets/meraki_organization/tasks/tests.yml +++ /dev/null @@ -1,127 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create a new organization named IntTestOrg - meraki_organization: - auth_key: '{{ auth_key }}' - org_name: IntTestOrg - state: present - output_level: debug - register: new_org - - - debug: - msg: '{{new_org}}' - - - name: Clone IntTestOrg - meraki_organization: - auth_key: '{{ auth_key }}' - clone: IntTestOrg - org_name: IntTestOrgCloned - state: present - register: cloned_org - - - debug: - msg: '{{cloned_org}}' - - - name: Rename IntTestOrg - meraki_organization: - auth_key: '{{ auth_key }}' - org_name: IntTestOrgRenamed - org_id: '{{ new_org.data.id }}' - state: present - register: modify_org - - - debug: - msg: '{{ modify_org }}' - - - set_fact: - renamed_org_id: '{{modify_org.data.id}}' - - - name: Rename IntTestOrg idempotent - meraki_organization: - auth_key: '{{ auth_key }}' - org_name: IntTestOrgRenamed - org_id: '{{ new_org.data.id }}' - state: present - register: modify_org_idempotent - - - name: Present assertions - assert: - that: - - '"https" in new_org.url' - - new_org.changed == True - - new_org.data.id is defined - - cloned_org.changed == True - - cloned_org.data.id is defined - - modify_org.changed == True - - 'modify_org.data.name == "IntTestOrgRenamed"' - - modify_org_idempotent.changed == False - - modify_org_idempotent.data is defined - - - name: List all organizations - meraki_organization: - auth_key: '{{ auth_key }}' - state: query - register: query_all - - - name: Query information about a single organization named IntTestOrg - meraki_organization: - auth_key: '{{ auth_key }}' - org_name: IntTestOrgRenamed - state: query - register: query_org - - - name: Query information about IntTestOrg by organization ID - meraki_organization: - auth_key: '{{ auth_key }}' - org_id: '{{ query_org.data.id }}' - state: query - register: query_org_id - - - name: Query assertions - assert: - that: - - query_org.data.id is defined - - query_all.changed == False - - query_all.data | length >= 1 - - 'query_org.data.name == "IntTestOrgRenamed"' - - 'query_org_id.data.id == query_org.data.id' - - always: - - name: Delete cloned organizations with check mode - meraki_organization: - auth_key: '{{ auth_key }}' - state: absent - org_name: IntTestOrgCloned - register: deleted_org_check - check_mode: yes - - - assert: - that: - - deleted_org_check is changed - - - name: Delete cloned organizations - meraki_organization: - auth_key: '{{ auth_key }}' - state: absent - org_name: IntTestOrgCloned - register: deleted_org - - - name: Delete renamed organization by id - meraki_organization: - auth_key: '{{ auth_key }}' - state: absent - org_id: '{{renamed_org_id}}' - register: deleted_org_id - - - assert: - that: - - deleted_org_id is changed diff --git a/test/integration/targets/meraki_snmp/aliases b/test/integration/targets/meraki_snmp/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_snmp/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_snmp/tasks/main.yml b/test/integration/targets/meraki_snmp/tasks/main.yml deleted file mode 100644 index d914dd0f646..00000000000 --- a/test/integration/targets/meraki_snmp/tasks/main.yml +++ /dev/null @@ -1,306 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create SNMP network - meraki_network: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - type: appliance - delegate_to: localhost - register: new_net - - - set_fact: - net_id: new_net.data.id - - - name: Query all SNMP settings - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: query - delegate_to: localhost - register: snmp_query - - - debug: - msg: '{{snmp_query}}' - - - name: Enable SNMPv2c - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v2c_enabled: true - delegate_to: localhost - register: snmp_v2_enable - - - debug: - msg: '{{snmp_v2_enable}}' - - - assert: - that: - - snmp_v2_enable.data.v2_community_string is defined - - snmp_v2_enable.data.v2c_enabled == true - - - name: Disable SNMPv2c - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v2c_enabled: False - delegate_to: localhost - register: snmp_v2_disable - - - assert: - that: - - snmp_v2_disable.data.v2_community_string is not defined - - snmp_v2_disable.data.v2c_enabled == False - - - name: Enable SNMPv2c with org_id - meraki_snmp: - auth_key: '{{auth_key}}' - org_id: '{{test_org_id}}' - state: present - v2c_enabled: true - delegate_to: localhost - register: snmp_v2_enable_id - - - debug: - msg: '{{snmp_v2_enable_id}}' - - - assert: - that: - - snmp_v2_enable_id.data.v2_community_string is defined - - snmp_v2_enable_id.data.v2c_enabled == true - - - name: Disable SNMPv2c with org_id - meraki_snmp: - auth_key: '{{auth_key}}' - org_id: '{{test_org_id}}' - state: present - v2c_enabled: False - delegate_to: localhost - register: snmp_v2_disable_id - - - assert: - that: - - snmp_v2_disable_id.data.v2_community_string is not defined - - snmp_v2_disable_id.data.v2c_enabled == False - - - name: Enable SNMPv3 with check mode - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v3_enabled: true - v3_auth_mode: SHA - v3_auth_pass: ansiblepass - v3_priv_mode: AES128 - v3_priv_pass: ansiblepass - delegate_to: localhost - check_mode: yes - register: snmp_v3_enable_check - - - assert: - that: - - snmp_v3_enable_check.data.v3_enabled == True - - snmp_v3_enable_check.changed == True - - - name: Enable SNMPv3 - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v3_enabled: true - v3_auth_mode: SHA - v3_auth_pass: ansiblepass - v3_priv_mode: AES128 - v3_priv_pass: ansiblepass - delegate_to: localhost - register: snmp_v3_enable - - - assert: - that: - - snmp_v3_enable.data.v3_enabled == True - - snmp_v3_enable.changed == True - - - name: Check for idempotency - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v3_enabled: true - v3_auth_mode: SHA - v3_auth_pass: ansiblepass - v3_priv_mode: AES128 - v3_priv_pass: ansiblepass - delegate_to: localhost - register: snmp_idempotent - - - debug: - msg: '{{snmp_idempotent}}' - - - assert: - that: - - snmp_idempotent.changed == False - - snmp_idempotent.data is defined - - - name: Add peer IPs - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v3_enabled: true - v3_auth_mode: SHA - v3_auth_pass: ansiblepass - v3_priv_mode: AES128 - v3_priv_pass: ansiblepass - peer_ips: 1.1.1.1;2.2.2.2 - delegate_to: localhost - register: peers - - - debug: - msg: '{{peers}}' - - - assert: - that: - - peers.data.peer_ips is defined - - - name: Add invalid peer IPs - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - peer_ips: 1.1.1.1 2.2.2.2 - delegate_to: localhost - register: invalid_peers - ignore_errors: yes - - - assert: - that: - '"Peer IP addresses are semi-colon delimited." in invalid_peers.msg' - - - name: Set short password - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v3_enabled: true - v3_auth_mode: SHA - v3_auth_pass: ansible - v3_priv_mode: AES128 - v3_priv_pass: ansible - peer_ips: 1.1.1.1;2.2.2.2 - delegate_to: localhost - register: short_password - ignore_errors: yes - - - debug: - msg: '{{short_password}}' - - - assert: - that: - - '"at least 8" in short_password.msg' - - - name: Set network access type to community string - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - access: community - community_string: abc123 - delegate_to: localhost - register: set_net_community - - - debug: - var: set_net_community - - - assert: - that: - - set_net_community is changed - - set_net_community.data is defined - - - name: Set network access type to username - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - access: users - users: - - username: ansibleuser - passphrase: ansiblepass - delegate_to: localhost - register: set_net_user - - - debug: - var: set_net_user - - - assert: - that: - - set_net_user is changed - - set_net_user.data is defined - - - name: Set network access type to none - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - access: none - delegate_to: localhost - register: set_net_none - - - debug: - var: set_net_none - - - assert: - that: - - set_net_none is changed - - set_net_none.data is defined - - - name: Query network SNMP settings - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - delegate_to: localhost - register: get_net - - - debug: - var: get_net - - - assert: - that: - - get_net.data is defined - - always: - - name: Disable SNMPv3 - meraki_snmp: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - state: present - v3_enabled: no - v3_auth_mode: SHA - v3_auth_pass: ansiblepass - v3_priv_mode: AES128 - v3_priv_pass: ansiblepass - delegate_to: localhost - - - name: Delete SNMP network - meraki_network: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: absent - delegate_to: localhost diff --git a/test/integration/targets/meraki_ssid/aliases b/test/integration/targets/meraki_ssid/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_ssid/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_ssid/tasks/main.yml b/test/integration/targets/meraki_ssid/tasks/main.yml deleted file mode 100644 index 66291766cf5..00000000000 --- a/test/integration/targets/meraki_ssid/tasks/main.yml +++ /dev/null @@ -1,408 +0,0 @@ -# Test code for the Meraki SSID module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create test network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - type: wireless - register: test_net - - - debug: - msg: '{{test_net}}' - - - name: Query all SSIDs - meraki_ssid: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: TestNetSSID - delegate_to: localhost - register: query_all - - - name: Enable and name SSID - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - enabled: true - delegate_to: localhost - register: enable_name_ssid - - - debug: - msg: '{{ enable_name_ssid }}' - - - assert: - that: - - query_all.data | length == 15 - - query_all.data.0.name == 'TestNetSSID WiFi' - - enable_name_ssid.data.name == 'AnsibleSSID' - - - name: Check for idempotency - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - enabled: true - delegate_to: localhost - register: enable_name_ssid_idempotent - - - debug: - msg: '{{ enable_name_ssid_idempotent }}' - - - assert: - that: - - enable_name_ssid_idempotent.changed == False - - enable_name_ssid_idempotent.data is defined - - - name: Query one SSIDs - meraki_ssid: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - delegate_to: localhost - register: query_one - - - debug: - msg: '{{query_one}}' - - - assert: - that: - - query_one.data.name == 'AnsibleSSID' - - - name: Query one SSID with number - meraki_ssid: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: TestNetSSID - number: 1 - delegate_to: localhost - register: query_one_number - - - debug: - msg: '{{query_one_number}}' - - - assert: - that: - - query_one_number.data.name == 'AnsibleSSID' - - - name: Disable SSID without specifying number - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - enabled: false - delegate_to: localhost - register: disable_ssid - - - debug: - msg: '{{ disable_ssid.data.enabled }}' - - - assert: - that: - - disable_ssid.data.enabled == False - - - name: Enable SSID with number - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - number: 1 - enabled: true - delegate_to: localhost - register: enable_ssid_number - - - debug: - msg: '{{ enable_ssid_number.data.enabled }}' - - - assert: - that: - - enable_ssid_number.data.enabled == True - - - name: Set VLAN arg spec - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - number: 1 - use_vlan_tagging: yes - ip_assignment_mode: Bridge mode - default_vlan_id: 1 - ap_tags_vlan_ids: - - tags: wifi - vlan_id: 2 - delegate_to: localhost - register: set_vlan_arg - - - debug: - var: set_vlan_arg - - - assert: - that: set_vlan_arg is changed - - - name: Set VLAN arg spec - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - number: 1 - use_vlan_tagging: yes - ip_assignment_mode: Bridge mode - default_vlan_id: 1 - ap_tags_vlan_ids: - - tags: wifi - vlan_id: 2 - delegate_to: localhost - register: set_vlan_arg_idempotent - - - debug: - var: set_vlan_arg_idempotent - - - assert: - that: set_vlan_arg_idempotent is not changed - - - - name: Set PSK - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: psk - psk: abc1234567890 - encryption_mode: wpa - delegate_to: localhost - register: psk - - - debug: - msg: '{{ psk }}' - - - assert: - that: - - psk.data.auth_mode == 'psk' - - psk.data.encryption_mode == 'wpa' - - psk.data.wpa_encryption_mode == 'WPA2 only' - - - name: Set PSK with idempotency - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: psk - psk: abc1234567890 - encryption_mode: wpa - delegate_to: localhost - register: psk_idempotent - - - debug: - msg: '{{ psk_idempotent }}' - - - assert: - that: - - psk_idempotent is not changed - - - name: Enable click-through splash page - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - splash_page: Click-through splash page - delegate_to: localhost - register: splash_click - - - debug: - msg: '{{ splash_click }}' - - - assert: - that: - - splash_click.data.splash_page == 'Click-through splash page' - - - name: Configure RADIUS servers - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: open-with-radius - radius_servers: - - host: 192.0.1.200 - port: 1234 - secret: abc98765 - delegate_to: localhost - register: set_radius_server - - - debug: - msg: '{{ set_radius_server }}' - - - assert: - that: - - set_radius_server.data.radius_servers.0.host == '192.0.1.200' - - - name: Configure RADIUS servers with idempotency - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: open-with-radius - radius_servers: - - host: 192.0.1.200 - port: 1234 - secret: abc98765 - delegate_to: localhost - register: set_radius_server_idempotent - - - debug: - var: set_radius_server_idempotent - - - assert: - that: - - set_radius_server_idempotent is not changed - - ################# - # Error testing # - ################# - - name: Set PSK with wrong mode - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: open - psk: abc1234 - delegate_to: localhost - register: psk_invalid - ignore_errors: yes - - - debug: - msg: '{{ psk_invalid }}' - - - assert: - that: - - psk_invalid.msg == 'PSK is only allowed when auth_mode is set to psk' - - - name: Set PSK with invalid encryption mode - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: psk - psk: abc1234 - encryption_mode: eap - delegate_to: localhost - register: psk_invalid_mode - ignore_errors: yes - - - debug: - msg: '{{ psk_invalid_mode }}' - - - assert: - that: - - psk_invalid_mode.msg == 'PSK requires encryption_mode be set to wpa' - - - name: Error for PSK and RADIUS servers - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - auth_mode: psk - radius_servers: - - host: 192.0.1.200 - port: 1234 - secret: abc98765 - delegate_to: localhost - register: err_radius_server_psk - ignore_errors: yes - - - debug: - var: err_radius_server_psk - - - assert: - that: - - 'err_radius_server_psk.msg == "radius_servers requires auth_mode to be open-with-radius or 8021x-radius"' - - - name: Set VLAN arg without default VLAN error - meraki_ssid: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: TestNetSSID - number: 1 - use_vlan_tagging: yes - ip_assignment_mode: Bridge mode - ap_tags_vlan_ids: - - tags: wifi - vlan_id: 2 - delegate_to: localhost - register: set_vlan_arg_err - ignore_errors: yes - - - debug: - var: set_vlan_arg_err - - - assert: - that: - - 'set_vlan_arg_err.msg == "default_vlan_id is required when use_vlan_tagging is True"' - - always: - - name: Delete SSID - meraki_ssid: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: TestNetSSID - name: AnsibleSSID - delegate_to: localhost - register: delete_ssid - - - debug: - msg: '{{ delete_ssid }}' - - - assert: - that: - - delete_ssid.data.name == 'Unconfigured SSID 2' - - - name: Delete test network - meraki_network: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: TestNetSSID - register: delete_net - - - debug: - msg: '{{delete_net}}' diff --git a/test/integration/targets/meraki_static_route/aliases b/test/integration/targets/meraki_static_route/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_static_route/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_static_route/tasks/main.yml b/test/integration/targets/meraki_static_route/tasks/main.yml deleted file mode 100644 index 10ba31eab97..00000000000 --- a/test/integration/targets/meraki_static_route/tasks/main.yml +++ /dev/null @@ -1,170 +0,0 @@ -# Test code for the Meraki modules -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Create appliance network - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - timezone: America/Chicago - type: appliance - delegate_to: localhost - register: net - - - set_fact: - net_id: '{{net.data.id}}' - - - name: Initialize static route id list - set_fact: - route_ids: [] - - - name: Create static_route - meraki_static_route: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - name: Test Route - subnet: 192.0.1.0/24 - gateway_ip: 192.168.128.1 - delegate_to: localhost - register: create_route - - - set_fact: - route_ids: "{{ route_ids + [create_route.data.id] }}" - - - name: Create second static_route - meraki_static_route: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - name: Test Route 2 - subnet: 192.0.2.0/24 - gateway_ip: 192.168.128.1 - delegate_to: localhost - register: second_create - - - set_fact: - route_ids: "{{ route_ids + [second_create.data.id] }}" - - - assert: - that: - - create_route.changed == True - - create_route.data.id is defined - - - name: Update static route - meraki_static_route: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - route_id: '{{create_route.data.id}}' - subnet: 192.0.3.0/24 - enabled: yes - delegate_to: localhost - register: update - - - assert: - that: - - update.data.subnet == "192.0.3.0/24" - - - name: Query static routes - meraki_static_route: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - delegate_to: localhost - register: query_all - - - debug: - var: query_all - - - assert: - that: - - query_all.data | length >= 2 - - - name: Update static route with idempotency - meraki_static_route: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - route_id: '{{create_route.data.id}}' - name: Test Route - gateway_ip: 192.168.128.1 - subnet: 192.0.3.0/24 - enabled: yes - delegate_to: localhost - register: update_idempotent - - - assert: - that: - - update_idempotent.changed == False - - update_idempotent.data is defined - - - name: Update static route with fixed IP assignment and reservation - meraki_static_route: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - route_id: '{{create_route.data.id}}' - fixed_ip_assignments: - - mac: aa:bb:cc:dd:ee:ff - ip: 192.0.3.11 - name: WebServer - reserved_ip_ranges: - - start: 192.168.3.2 - end: 192.168.3.10 - comment: Printers - delegate_to: localhost - register: fixed_ip - - - debug: - var: fixed_ip - - - assert: - that: - - fixed_ip.data.fixedIpAssignments | length == 1 - - fixed_ip.data.reservedIpRanges | length == 1 - - - - name: Query single static route - meraki_static_route: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - route_id: '{{create_route.data.id}}' - delegate_to: localhost - register: query_one - - - assert: - that: - - query_one.data.name == "Test Route" - - - name: Delete static routes - meraki_static_route: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - route_id: '{{item}}' - delegate_to: localhost - loop: '{{route_ids}}' - register: delete_all - - always: - - name: Delete appliance network - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - org_name: '{{test_org_name}}' - net_name: IntTestNetwork - delegate_to: localhost diff --git a/test/integration/targets/meraki_switchport/aliases b/test/integration/targets/meraki_switchport/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_switchport/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_switchport/tasks/main.yml b/test/integration/targets/meraki_switchport/tasks/main.yml deleted file mode 100644 index 8146f2845cc..00000000000 --- a/test/integration/targets/meraki_switchport/tasks/main.yml +++ /dev/null @@ -1,297 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - -- name: Query all switchports - meraki_switchport: - auth_key: '{{auth_key}}' - state: query - serial: Q2HP-2C6E-GTLD - delegate_to: localhost - register: query_all - -- debug: - msg: '{{query_all}}' - -- name: Query one switchport - meraki_switchport: - auth_key: '{{auth_key}}' - state: query - serial: Q2HP-2C6E-GTLD - number: 1 - delegate_to: localhost - register: query_one - -- debug: - msg: '{{query_one}}' - -- name: Enable switchport - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - delegate_to: localhost - register: update_port_true - -- debug: - msg: '{{update_port_true}}' - -- assert: - that: - - update_port_true.data.enabled == True - -- name: Disable switchport - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: false - delegate_to: localhost - register: update_port_false - -- debug: - msg: '{{update_port_false}}' - -- assert: - that: - - update_port_false.data.enabled == False - - -- name: Name switchport - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - name: Test Port - delegate_to: localhost - register: update_port_name - -- debug: - msg: '{{update_port_name}}' - -- assert: - that: - - update_port_name.data.name == 'Test Port' - -- name: Configure access port - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Test Port - tags: desktop - type: access - vlan: 10 - delegate_to: localhost - register: update_access_port - -- debug: - msg: '{{update_access_port}}' - -- assert: - that: - - update_access_port.data.vlan == 10 - -- name: Configure port as trunk - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 8 - enabled: true - name: Test Port - type: trunk - vlan: 10 - allowed_vlans: 10, 100, 200 - delegate_to: localhost - -- name: Convert trunk port to access - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 8 - enabled: true - name: Test Port - type: access - vlan: 10 - delegate_to: localhost - -- name: Test converted port for idempotency - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 8 - enabled: true - name: Test Port - type: access - vlan: 10 - delegate_to: localhost - register: convert_idempotent - -- assert: - that: - - convert_idempotent.changed == False - -- name: Configure access port with voice VLAN - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Test Port - tags: desktop - type: access - vlan: 10 - voice_vlan: 11 - delegate_to: localhost - register: update_port_vvlan - -- debug: - msg: '{{update_port_vvlan}}' - -- assert: - that: - - update_port_vvlan.data.voice_vlan == 11 - - update_port_vvlan.changed == True - -- name: Check access port for idempotenty - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Test Port - tags: desktop - type: access - vlan: 10 - voice_vlan: 11 - delegate_to: localhost - register: update_port_access_idempotent - -- debug: - msg: '{{update_port_access_idempotent}}' - -- assert: - that: - - update_port_access_idempotent.changed == False - - update_port_access_idempotent.data is defined - -- name: Configure trunk port - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Server port - tags: server - type: trunk - allowed_vlans: all - vlan: 8 - delegate_to: localhost - register: update_trunk - -- debug: - msg: '{{update_trunk}}' - -- assert: - that: - - update_trunk.data.tags == 'server' - - update_trunk.data.type == 'trunk' - - update_trunk.data.allowed_vlans == 'all' - -- name: Configure trunk port with specific VLANs - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Server port - tags: server - type: trunk - vlan: 8 - allowed_vlans: - - 10 - - 15 - - 20 - delegate_to: localhost - register: update_trunk - -- debug: - msg: '{{update_trunk}}' - -- assert: - that: - - update_trunk.data.tags == 'server' - - update_trunk.data.type == 'trunk' - - update_trunk.data.allowed_vlans == '8,10,15,20' - -- name: Configure trunk port with specific VLANs and native VLAN - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Server port - tags: server - type: trunk - vlan: 2 - allowed_vlans: - - 10 - - 15 - - 20 - delegate_to: localhost - register: update_trunk - -- debug: - msg: '{{update_trunk}}' - -- assert: - that: - - update_trunk.data.tags == 'server' - - update_trunk.data.type == 'trunk' - - update_trunk.data.allowed_vlans == '2,10,15,20' - -- name: Check for idempotency on trunk port - meraki_switchport: - auth_key: '{{auth_key}}' - state: present - serial: Q2HP-2C6E-GTLD - number: 7 - enabled: true - name: Server port - tags: server - type: trunk - vlan: 2 - allowed_vlans: - - 10 - - 15 - - 20 - delegate_to: localhost - register: update_trunk_idempotent - -- debug: - msg: '{{update_trunk_idempotent}}' - -- assert: - that: - - update_trunk_idempotent.changed == False - - update_trunk_idempotent.data is defined diff --git a/test/integration/targets/meraki_syslog/tasks/main.yml b/test/integration/targets/meraki_syslog/tasks/main.yml deleted file mode 100644 index e2fdd6c8dbe..00000000000 --- a/test/integration/targets/meraki_syslog/tasks/main.yml +++ /dev/null @@ -1,169 +0,0 @@ -# Test code for the Meraki Organization module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - set_fact: - syslog_test_net_name: 'syslog_{{test_net_name}}' - - - name: Create network with type appliance and no timezone - meraki_network: - auth_key: '{{ auth_key }}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - type: appliance - delegate_to: localhost - register: new_net - - - set_fact: - net_id: '{{new_net.data.id}}' - - - name: Query syslog settings - meraki_syslog: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - delegate_to: localhost - register: query_all - - - debug: - msg: '{{query_all}}' - - - name: Set syslog server - meraki_syslog: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - servers: - - host: 192.0.1.2 - port: 514 - roles: - - Appliance event log - delegate_to: localhost - register: create_server - - - debug: - msg: '{{create_server.data}}' - - - assert: - that: - - create_server['data'][0]['host'] == "192.0.1.2" - - - name: Set syslog server with idempotency - meraki_syslog: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - servers: - - host: 192.0.1.2 - port: 514 - roles: - - Appliance event log - delegate_to: localhost - register: create_server_idempotency - - - debug: - msg: '{{create_server_idempotency}}' - - - assert: - that: - - create_server_idempotency.changed == False - - create_server_idempotency.data is defined - - - name: Set multiple syslog servers - meraki_syslog: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_id: '{{net_id}}' - state: present - servers: - - host: 192.0.1.3 - port: 514 - roles: - - Appliance event log - - host: 192.0.1.4 - port: 514 - roles: - - Appliance Event log - - Flows - - host: 192.0.1.5 - port: 514 - roles: - - Flows - delegate_to: localhost - register: create_multiple_servers - - - debug: - msg: '{{create_multiple_servers}}' - - - assert: - that: - - create_multiple_servers['data'][0]['host'] == "192.0.1.3" - - create_multiple_servers['data'][1]['host'] == "192.0.1.4" - - create_multiple_servers['data'][2]['host'] == "192.0.1.5" - - create_multiple_servers['data'] | length == 3 - - - name: Create syslog server with bad name - meraki_syslog: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - servers: - - host: 192.0.1.6 - port: 514 - roles: - - Invalid role - delegate_to: localhost - register: invalid_role - ignore_errors: yes - - # - debug: - # msg: '{{invalid_role.body.errors.0}}' - - - assert: - that: - - '"Please select at least one valid role" in invalid_role.body.errors.0' - - - name: Add role to existing syslog server # Adding doesn't work, just creation - meraki_syslog: - auth_key: '{{auth_key}}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: present - servers: - - host: 192.0.1.2 - port: 514 - roles: - - flows - delegate_to: localhost - register: add_role - - - debug: - msg: '{{add_role.data.0.roles}}' - - - assert: - that: - - add_role.data.0.roles.0 == 'Flows' - # - add_role.data.0.roles | length == 2 - - always: - - name: Delete syslog test network - meraki_network: - auth_key: '{{ auth_key }}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - delegate_to: localhost - register: delete_all - ignore_errors: yes diff --git a/test/integration/targets/meraki_vlan/aliases b/test/integration/targets/meraki_vlan/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_vlan/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_vlan/tasks/main.yml b/test/integration/targets/meraki_vlan/tasks/main.yml deleted file mode 100644 index 0f3cd233a83..00000000000 --- a/test/integration/targets/meraki_vlan/tasks/main.yml +++ /dev/null @@ -1,412 +0,0 @@ -# Test code for the Meraki VLAN module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Test play without auth_key - meraki_network: - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - type: appliance - delegate_to: localhost - ignore_errors: yes - register: no_key - - - assert: - that: - - '"missing required arguments" in no_key.msg' - - - name: Create test network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - type: appliance - delegate_to: localhost - - - name: Enable VLANs on network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - enable_vlans: yes - delegate_to: localhost - - - name: Create VLAN in check mode - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.1 - delegate_to: localhost - register: create_vlan_check - check_mode: yes - - - debug: - var: create_vlan_check - - - assert: - that: - - create_vlan_check is changed - - - name: Create VLAN - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.1 - delegate_to: localhost - register: create_vlan - environment: - ANSIBLE_MERAKI_FORMAT: camelcase - - - debug: - msg: '{{create_vlan}}' - - - assert: - that: - - create_vlan.data.id == 2 - - create_vlan.changed == True - - create_vlan.data.networkId is defined - - - name: Update VLAN with check mode - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan_check - check_mode: yes - - - debug: - var: update_vlan_check - - - assert: - that: - - update_vlan_check is changed - - - name: Update VLAN - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan - - - debug: - msg: '{{update_vlan}}' - - - assert: - that: - - update_vlan.data.appliance_ip == '192.168.250.2' - - update_vlan.changed == True - - - name: Update VLAN with idempotency and check mode - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan_idempotent_check - check_mode: yes - - - debug: - var: update_vlan_idempotent_check - - - assert: - that: - - update_vlan_idempotent_check is not changed - - - name: Update VLAN with idempotency - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan_idempotent - - - debug: - msg: '{{update_vlan_idempotent}}' - - - assert: - that: - - update_vlan_idempotent.changed == False - - update_vlan_idempotent.data is defined - - - name: Add IP assignments and reserved IP ranges - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - - mac: "12:34:56:78:90:12" - ip: 192.168.250.11 - name: another_fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - - start: 192.168.250.100 - end: 192.168.250.120 - comment: reserved_range_high - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan_add_ip - - - debug: - msg: '{{update_vlan_add_ip}}' - - - assert: - that: - - update_vlan_add_ip.changed == True - - update_vlan_add_ip.data.fixed_ip_assignments | length == 2 - - update_vlan_add_ip.data.reserved_ip_ranges | length == 2 - - - name: Remove IP assignments and reserved IP ranges - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan_remove_ip - - - debug: - msg: '{{update_vlan_remove_ip}}' - - - assert: - that: - - update_vlan_remove_ip.changed == True - - update_vlan_remove_ip.data.fixed_ip_assignments | length == 1 - - update_vlan_remove_ip.data.reserved_ip_ranges | length == 1 - - - name: Update VLAN with idempotency - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: opendns - delegate_to: localhost - register: update_vlan_idempotent - - - debug: - msg: '{{update_vlan_idempotent}}' - - - assert: - that: - - update_vlan_idempotent.changed == False - - update_vlan_idempotent.data is defined - - - name: Update VLAN with list of DNS entries - meraki_vlan: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - name: TestVLAN - subnet: 192.168.250.0/24 - appliance_ip: 192.168.250.2 - fixed_ip_assignments: - - mac: "13:37:de:ad:be:ef" - ip: 192.168.250.10 - name: fixed_ip - reserved_ip_range: - - start: 192.168.250.10 - end: 192.168.250.20 - comment: reserved_range - dns_nameservers: 1.1.1.1;8.8.8.8 - delegate_to: localhost - register: update_vlan_dns_list - - - debug: - msg: '{{update_vlan_dns_list}}' - - - assert: - that: - - '"1.1.1.1" in update_vlan_dns_list.data.dns_nameservers' - - update_vlan_dns_list.changed == True - - - name: Query all VLANs in network - meraki_vlan: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - state: query - delegate_to: localhost - register: query_vlans - - - debug: - msg: '{{query_vlans}}' - - - assert: - that: - - query_vlans.data | length >= 2 - - query_vlans.data.1.id == 2 - - query_vlans.changed == False - - - name: Query single VLAN - meraki_vlan: - auth_key: '{{ auth_key }}' - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - state: query - output_level: debug - delegate_to: localhost - register: query_vlan - - - debug: - msg: '{{query_vlan}}' - - - assert: - that: - - query_vlan.data.id == 2 - - query_vlan.changed == False - - always: - ############################################################################# - # Tear down starts here - ############################################################################# - - name: Delete VLAN with check mode - meraki_vlan: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - delegate_to: localhost - register: delete_vlan_check - check_mode: yes - - - assert: - that: - delete_vlan_check is changed - - - name: Delete VLAN - meraki_vlan: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - vlan_id: 2 - delegate_to: localhost - register: delete_vlan - - - debug: - msg: '{{delete_vlan}}' - - - name: Delete test network - meraki_network: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - delegate_to: localhost diff --git a/test/integration/targets/meraki_webhook/aliases b/test/integration/targets/meraki_webhook/aliases deleted file mode 100644 index ad7ccf7ada2..00000000000 --- a/test/integration/targets/meraki_webhook/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/test/integration/targets/meraki_webhook/tasks/main.yml b/test/integration/targets/meraki_webhook/tasks/main.yml deleted file mode 100644 index f671fc92877..00000000000 --- a/test/integration/targets/meraki_webhook/tasks/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Test code for the Meraki Webhooks module -# Copyright: (c) 2018, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- name: Run test cases - include: tests.yml ansible_connection=local diff --git a/test/integration/targets/meraki_webhook/tasks/tests.yml b/test/integration/targets/meraki_webhook/tasks/tests.yml deleted file mode 100644 index c16caba0cc9..00000000000 --- a/test/integration/targets/meraki_webhook/tasks/tests.yml +++ /dev/null @@ -1,273 +0,0 @@ -# Test code for the Meraki Webhook module -# Copyright: (c) 2019, Kevin Breit (@kbreit) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) ---- -- block: - - name: Test an API key is provided - fail: - msg: Please define an API key - when: auth_key is not defined - - - name: Create test network - meraki_network: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - type: appliance - - - name: Create webhook with check mode - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - shared_secret: shhhdonttellanyone - check_mode: yes - register: create_one_check - - - debug: - var: create_one_check - - - assert: - that: - - create_one_check is changed - - create_one_check.data is defined - - - name: Create webhook - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - shared_secret: shhhdonttellanyone - register: create_one - - - debug: - var: create_one - - - assert: - that: - - create_one is changed - - create_one.data is defined - - - set_fact: - webhook_id: '{{create_one.data.id}}' - - - name: Query one webhook - meraki_webhook: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - register: query_one - - - debug: - var: query_one - - - assert: - that: - - query_one.data is defined - - - name: Query one webhook with id - meraki_webhook: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - webhook_id: '{{webhook_id}}' - register: query_one_id - - - debug: - var: query_one_id - - - assert: - that: - - query_one_id.data is defined - - - name: Update webhook with check mode - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - shared_secret: shhhdonttellanyonehere - check_mode: yes - register: update_check - - - assert: - that: - - update_check is changed - - update_check.data is defined - - - name: Update webhook - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - shared_secret: shhhdonttellanyonehere - register: update - - - debug: - var: update - - - assert: - that: - - update is changed - - update.data is defined - - - name: Update webhook with idempotency - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - shared_secret: shhhdonttellanyonehere - register: update_idempotent - - - debug: - var: update_idempotent - - - assert: - that: - - update_idempotent is not changed - - update_idempotent.data is defined - - - name: Update webhook with id - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - webhook_id: '{{webhook_id}}' - name: Test_Hook - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - shared_secret: shhhdonttellanyonehereid - register: update_id - - - debug: - var: update_id - - - assert: - that: - - update_id is changed - - update_id.data is defined - - - name: Test webhook - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - test: test - url: https://webhook.site/8eb5b76f-b167-4cb8-9fc4-42621b724244 - register: webhook_test - - - debug: - var: webhook_test - - - set_fact: - test_id: '{{webhook_test.data.id}}' - - - name: Get webhook status - meraki_webhook: - auth_key: '{{auth_key}}' - state: present - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - test: status - test_id: '{{test_id}}' - register: webhook_test_status - - - debug: - var: webhook_test_status - - - assert: - that: - - webhook_test_status.data is defined - - - name: Query all webhooks - meraki_webhook: - auth_key: '{{auth_key}}' - state: query - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - register: query_all - - - debug: - var: query_all - - - name: Delete webhook invalid webhook - meraki_webhook: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook_Invalid - check_mode: yes - register: delete_invalid - ignore_errors: yes - - - debug: - var: delete_invalid - - - assert: - that: - - 'delete_invalid.msg == "There is no webhook with the name Test_Hook_Invalid"' - - - name: Delete webhook in check mode - meraki_webhook: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - check_mode: yes - register: delete_check - - - debug: - var: delete_check - - - assert: - that: - - delete_check is changed - - - name: Delete webhook - meraki_webhook: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' - name: Test_Hook - register: delete - - - debug: - var: delete - - - assert: - that: - - delete is changed - - always: - ############################################################################# - # Tear down starts here - ############################################################################# - - name: Delete test network - meraki_network: - auth_key: '{{auth_key}}' - state: absent - org_name: '{{test_org_name}}' - net_name: '{{test_net_name}}' diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 3543cd0fb28..bec92ee02d1 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -100,8 +100,6 @@ lib/ansible/module_utils/network/junos/facts/legacy/base.py future-import-boiler lib/ansible/module_utils/network/junos/facts/legacy/base.py metaclass-boilerplate lib/ansible/module_utils/network/junos/junos.py future-import-boilerplate lib/ansible/module_utils/network/junos/junos.py metaclass-boilerplate -lib/ansible/module_utils/network/meraki/meraki.py future-import-boilerplate -lib/ansible/module_utils/network/meraki/meraki.py metaclass-boilerplate lib/ansible/module_utils/network/nxos/argspec/facts/facts.py future-import-boilerplate lib/ansible/module_utils/network/nxos/argspec/facts/facts.py metaclass-boilerplate lib/ansible/module_utils/network/nxos/facts/facts.py future-import-boilerplate @@ -1960,42 +1958,6 @@ lib/ansible/modules/network/junos/junos_vrf.py validate-modules:missing-suboptio lib/ansible/modules/network/junos/junos_vrf.py validate-modules:parameter-list-no-elements lib/ansible/modules/network/junos/junos_vrf.py validate-modules:parameter-type-not-in-doc lib/ansible/modules/network/junos/junos_vrf.py validate-modules:undocumented-parameter -lib/ansible/modules/network/meraki/meraki_admin.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_config_template.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_content_filtering.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_firewalled_services.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_malware.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_malware.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_mr_l3_firewall.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_mr_l3_firewall.py validate-modules:doc-type-does-not-match-spec -lib/ansible/modules/network/meraki/meraki_mx_l3_firewall.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_mx_l3_firewall.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py pylint:ansible-bad-function -lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py validate-modules:nonexistent-parameter-documented -lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_mx_l7_firewall.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_nat.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_nat.py validate-modules:invalid-ansiblemodule-schema -lib/ansible/modules/network/meraki/meraki_nat.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_network.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_network.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_organization.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_snmp.py validate-modules:invalid-ansiblemodule-schema -lib/ansible/modules/network/meraki/meraki_snmp.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_ssid.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_ssid.py validate-modules:doc-required-mismatch -lib/ansible/modules/network/meraki/meraki_ssid.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_static_route.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_switchport.py validate-modules:doc-required-mismatch -lib/ansible/modules/network/meraki/meraki_switchport.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_switchport.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_syslog.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_syslog.py validate-modules:parameter-list-no-elements -lib/ansible/modules/network/meraki/meraki_vlan.py validate-modules:doc-elements-mismatch -lib/ansible/modules/network/meraki/meraki_vlan.py validate-modules:missing-suboption-docs -lib/ansible/modules/network/meraki/meraki_vlan.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/network/meraki/meraki_vlan.py validate-modules:undocumented-parameter lib/ansible/modules/network/nxos/_nxos_interface.py validate-modules:doc-choices-do-not-match-spec lib/ansible/modules/network/nxos/_nxos_interface.py validate-modules:doc-default-does-not-match-spec lib/ansible/modules/network/nxos/_nxos_interface.py validate-modules:doc-default-incompatible-type @@ -2925,8 +2887,6 @@ lib/ansible/plugins/doc_fragments/inventory_cache.py future-import-boilerplate lib/ansible/plugins/doc_fragments/inventory_cache.py metaclass-boilerplate lib/ansible/plugins/doc_fragments/junos.py future-import-boilerplate lib/ansible/plugins/doc_fragments/junos.py metaclass-boilerplate -lib/ansible/plugins/doc_fragments/meraki.py future-import-boilerplate -lib/ansible/plugins/doc_fragments/meraki.py metaclass-boilerplate lib/ansible/plugins/doc_fragments/nxos.py future-import-boilerplate lib/ansible/plugins/doc_fragments/nxos.py metaclass-boilerplate lib/ansible/plugins/doc_fragments/openstack.py future-import-boilerplate diff --git a/test/units/module_utils/network/meraki/fixtures/orgs.json b/test/units/module_utils/network/meraki/fixtures/orgs.json deleted file mode 100644 index 087db0f244b..00000000000 --- a/test/units/module_utils/network/meraki/fixtures/orgs.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "id": 2930418, - "name": "My organization" - } -] \ No newline at end of file diff --git a/test/units/module_utils/network/meraki/test_meraki.py b/test/units/module_utils/network/meraki/test_meraki.py deleted file mode 100644 index 62d0d42fb33..00000000000 --- a/test/units/module_utils/network/meraki/test_meraki.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2019 Kevin Breit - -# This file is part of Ansible by Red Hat -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import json -import os -import pytest - -from units.compat import unittest, mock -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.meraki.meraki import MerakiModule, meraki_argument_spec, HTTPError, RateLimitException -from ansible.module_utils.six import PY2, PY3 -from ansible.module_utils._text import to_native, to_bytes -from units.modules.utils import set_module_args - -fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') -fixture_data = {} -testcase_data = { - "params": {'orgs': ['orgs.json'], - } -} - - -def load_fixture(name): - path = os.path.join(fixture_path, name) - - if path in fixture_data: - return fixture_data[path] - - with open(path) as f: - data = f.read() - - # try: - data = json.loads(data) - # except Exception: - # pass - - fixture_data[path] = data - return data - - -@pytest.fixture(scope="module") -def module(): - argument_spec = meraki_argument_spec() - set_module_args({'auth_key': 'abc123', - }) - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=False) - return MerakiModule(module) - - -def mocked_fetch_url(*args, **kwargs): - print(args) - if args[1] == 'https://api.meraki.com/api/v0/404': - info = {'status': 404, - 'msg': '404 - Page is missing', - 'url': 'https://api.meraki.com/api/v0/404', - } - info['body'] = '404' - elif args[1] == 'https://api.meraki.com/api/v0/429': - info = {'status': 429, - 'msg': '429 - Rate limit hit', - 'url': 'https://api.meraki.com/api/v0/429', - } - info['body'] = '429' - return (None, info) - - -def mocked_fetch_url_rate_success(module, *args, **kwargs): - if module.retry_count == 5: - info = {'status': 200, - 'url': 'https://api.meraki.com/api/organization', - } - resp = {'body': 'Succeeded'} - else: - info = {'status': 429, - 'msg': '429 - Rate limit hit', - 'url': 'https://api.meraki.com/api/v0/429', - } - info['body'] = '429' - return (resp, info) - - -def mocked_fail_json(*args, **kwargs): - pass - - -def mocked_sleep(*args, **kwargs): - pass - - -def test_fetch_url_404(module, mocker): - url = '404' - mocker.patch('ansible.module_utils.network.meraki.meraki.fetch_url', side_effect=mocked_fetch_url) - mocker.patch('ansible.module_utils.network.meraki.meraki.MerakiModule.fail_json', side_effect=mocked_fail_json) - with pytest.raises(HTTPError): - data = module.request(url, method='GET') - assert module.status == 404 - - -def test_fetch_url_429(module, mocker): - url = '429' - mocker.patch('ansible.module_utils.network.meraki.meraki.fetch_url', side_effect=mocked_fetch_url) - mocker.patch('ansible.module_utils.network.meraki.meraki.MerakiModule.fail_json', side_effect=mocked_fail_json) - mocker.patch('time.sleep', return_value=None) - with pytest.raises(RateLimitException): - data = module.request(url, method='GET') - assert module.status == 429 - - -def test_fetch_url_429_success(module, mocker): - url = '429' - mocker.patch('ansible.module_utils.network.meraki.meraki.fetch_url', side_effect=mocked_fetch_url_rate_success) - mocker.patch('ansible.module_utils.network.meraki.meraki.MerakiModule.fail_json', side_effect=mocked_fail_json) - mocker.patch('time.sleep', return_value=None) - # assert module.status == 200 - - -def test_define_protocol_https(module): - module.params['use_https'] = True - module.define_protocol() - testdata = module.params['protocol'] - assert testdata == 'https' - - -def test_define_protocol_http(module): - module.params['use_https'] = False - module.define_protocol() - testdata = module.params['protocol'] - assert testdata == 'http' - - -def test_is_org_valid_org_name(module): - data = load_fixture('orgs.json') - org_count = module.is_org_valid(data, org_name="My organization") - assert org_count == 1 - - -def test_is_org_valid_org_id(module): - data = load_fixture('orgs.json') - org_count = module.is_org_valid(data, org_id=2930418) - assert org_count == 1