diff --git a/.github/workflows/check_label.yaml b/.github/workflows/check_label.yaml new file mode 100644 index 0000000..5d7849d --- /dev/null +++ b/.github/workflows/check_label.yaml @@ -0,0 +1,11 @@ +--- +name: "Check label" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true +on: + pull_request_target: + types: [opened, labeled, unlabeled, synchronize] +jobs: + check_label: + uses: ansible/ansible-content-actions/.github/workflows/check_label.yaml@main diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..7e0436b --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,33 @@ +--- +name: "CI" + +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +on: + pull_request: + branches: [main] + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + +jobs: + changelog: + uses: ansible/ansible-content-actions/.github/workflows/changelog.yaml@main + if: github.event_name == 'pull_request' + ansible-lint: + uses: ansible/ansible-content-actions/.github/workflows/ansible_lint.yaml@main + all_green: + if: ${{ always() }} + needs: + - changelog + - ansible-lint + runs-on: ubuntu-latest + steps: + - run: >- + python -c "assert 'failure' not in + set([ + '${{ needs.changelog.result }}', + '${{ needs.ansible-lint.result }}' + ])" diff --git a/.github/workflows/draft_release.yaml b/.github/workflows/draft_release.yaml new file mode 100644 index 0000000..c1c0d6a --- /dev/null +++ b/.github/workflows/draft_release.yaml @@ -0,0 +1,18 @@ +--- +name: "Draft release" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true +on: + workflow_dispatch: +env: + NAMESPACE: ${{ github.repository_owner }} + COLLECTION_NAME: meraki + ANSIBLE_COLLECTIONS_PATHS: ./ +jobs: + update_release_draft: + uses: ansible/ansible-content-actions/.github/workflows/draft_release.yaml@main + with: + repo: ${{ github.event.pull_request.head.repo.full_name }} + secrets: + BOT_PAT: ${{ secrets.BOT_PAT }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..439fbd6 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,13 @@ +--- +name: "Release collection on Galaxy" +on: + release: + types: [published] + +jobs: + release_ansible_galaxy: + uses: ansible/ansible-content-actions/.github/workflows/release_galaxy.yaml@main + with: + environment: release + secrets: + ah_token: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} diff --git a/.gitignore b/.gitignore index cf2befe..7b46599 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,5 @@ scratch/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +changelogs/.plugin_cache \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f01d44..6330900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,18 @@ -# CHANGELOG +# wwt\.meraki Release Notes -## 1.0.0 (2023-05-26) +**Topics** -* 🎉 first release! +- v1\.1\.0 + - New Plugins + - Lookup -## 1.0.1 (2023-06-04) + +## v1\.1\.0 -* Added role metadata \ No newline at end of file + +### New Plugins + + +#### Lookup + +* wwt\.meraki\.fetch \- Fetch data from the Meraki API\. diff --git a/assets/configure_meraki_mr.svg b/assets/configure_meraki_mr.svg index e4bf56c..3393fd1 100644 --- a/assets/configure_meraki_mr.svg +++ b/assets/configure_meraki_mr.svg @@ -1,4 +1,4 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Argument Spec + Argument Spec - + - - |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) -|- auth_key: Meraki API Auth Key (Type: str, Required: True) -|- meraki_mr_configuration:  (Type: dict, Required: True) -    |- access_points: Access Point Configuration (Type: list, Required: True) -        |- name: Name of MX Appliance (Type: str, Required: True) -        |- organization: Meraki Organization (Type: str, Required: True) -        |- network: Meraki Network Name (Type: str, Required: True) -        |- rf_profile_name: RF Profile Name (Type: str, Required: False) -        |- general_settings: General MR Settings (Type: dict, Required: False) -            |- ipv6_bridge_enabled: Enable Wireless IPv6 Bridging (Type: bool, Required: False) -            |- led_lights_on: Enable LED lights on Access Points (Type: bool, Required: False) -            |- location_analytics_enabled: Enable Location Analytics (Type: bool, Required: False) -            |- meshing_enabled: Enable Wireless Mesh (Type: bool, Required: False) -            |- upgrade_strategy: Firmware Upgrade Strategy (Type: str, Required: False) -Available Choices -                - minimize_upgrade_time -                - minimize_client_downtime -        |- bluetooth_settings: MR Bluetooth Settings (Type: dict, Required: False) -            |- scanning_enabled: BLE Scanning Enabled (Type: bool, Required: False) -            |- beaconing_enabled: Enable BLE Beaconing (Type: bool, Required: False) -            |- uuid: Bluetooth UUID (Type: str, Required: False) -            |- major_minor_assignment_mode: The way major and minor number should be assigned (Type: str, Required: False) -Available Choices -                - Unique -                - Non-unique -            |- major: Major number in beacon identifier - only valid in non-unique mode (Type: int, Required: False) -            |- minor: Minor number in beacon identifier - only valid in non-unique mode (Type: int, Required: False) -        |- rf_profiles: RF Profile Configuration (Type: list, Required: False) -            |- name: Name of RF Profile (Type: str, Required: False) -            |- state: State of Profile (Type: str, Required: False) -Available Choices -                - present -                - absent -            |- band_selection_type: Band Selection assigned per AP or SSID (Type: str, Required: False) -Available Choices -                - ap -                - ssid -            |- client_balancing_enabled: Steer Client to best available AP (Type: bool, Required: False) -            |- ap_band_settings: Settings if band_selection_type is 'ap'(Type: dict, Required: False) -                |- mode: RF band the AP will support (Type: str, Required: False) -Available Choices -                    - 2.4ghz -                    - 5ghz -                    - dual -                |- band_steering_enabled: Steers client to most open band (Type: bool, Required: False) -            |- five_ghz_settings: 5Ghz band settings (Type: dict, Required: False) -                |- max_power: Max power in dBm of 5Ghz band (Type: int, Required: False) -Available Choices -                    - 8 -                    - 9 -                    - 10 -                    - 11 -                    - 12 -                    - 13 -                    - 14 -                    - 15 -                    - 16 -                    - 17 -                    - 18 -                    - 19 -                    - 20 -                    - 21 -                    - 22 -                    - 23 -                    - 24 -                    - 25 -                    - 26 -                    - 27 -                    - 28 -                    - 29 -                    - 30 -                |- min_bitrate: Minimum bitrate of 5Ghz band (Type: int, Required: False) -Available Choices -                    - 6 -                    - 9 -                    - 12 -                    - 18 -                    - 24 -                    - 36 -                    - 48 -                    - 54 -                |- min_power: Minimum power in dBm of 5Ghz band (Type: int, Required: False) -Available Choices -                    - 8 -                    - 9 -                    - 10 -                    - 11 -                    - 12 -                    - 13 -                    - 14 -                    - 15 -                    - 16 -                    - 17 -                    - 18 -                    - 19 -                    - 20 -                    - 21 -                    - 22 -                    - 23 -                    - 24 -                    - 25 -                    - 26 -                    - 27 -                    - 28 -                    - 29 -                    - 30 -                |- rxsop: controls the sensitivity of the radio - range -65 to -95(Type: int, Required: False) -                |- channel_width: Channel width for 5Ghz band (Type: str, Required: False) -Available Choices -                    - auto -                    - 20 -                    - 40 -                    - 80 -                |- valid_auto_channels: Valid auto channels for 5ghz band (Type: list, Required: False) -Available Choices -                    - 36 -                    - 40 -                    - 44 -                    - 48 -                    - 52 -                    - 56 -                    - 60 -                    - 64 -                    - 100 -                    - 104 -                    - 108 -                    - 112 -                    - 116 -                    - 120 -                    - 124 -                    - 128 -                    - 132 -                    - 136 -                    - 140 -                    - 144 -                    - 149 -                    - 153 -                    - 157 -                    - 161 -                    - 165 -            |- two_four_ghz_settings2.4Ghz band settings (Type: dict, Required: False) -                |- max_power: Max power in dBm of 2.4Ghz band (Type: int, Required: False) -Available Choices -                    - 5 -                    - 6 -                    - 7 -                    - 8 -                    - 9 -                    - 10 -                    - 11 -                    - 12 -                    - 13 -                    - 14 -                    - 15 -                    - 16 -                    - 17 -                    - 18 -                    - 19 -                    - 20 -                    - 21 -                    - 22 -                    - 23 -                    - 24 -                    - 25 -                    - 26 -                    - 27 -                    - 28 -                    - 29 -                    - 30 -                |- min_bitrate: Minimum bitrate of 2.4Ghz band (Type: int, Required: False) -Available Choices -                    - 1.0 -                    - 2.0 -                    - 5.5 -                    - 6.0 -                    - 9.0 -                    - 11.0 -                    - 12.0 -                    - 18.0 -                    - 24.0 -                    - 36.0 -                    - 48.0 -                    - 54.0 -                |- min_power: Minimum power in dBm of 2.4Ghz band (Type: int, Required: False) -Available Choices -                    - 5 -                    - 6 -                    - 7 -                    - 8 -                    - 9 -                    - 10 -                    - 11 -                    - 12 -                    - 13 -                    - 14 -                    - 15 -                    - 16 -                    - 17 -                    - 18 -                    - 19 -                    - 20 -                    - 21 -                    - 22 -                    - 23 -                    - 24 -                    - 25 -                    - 26 -                    - 27 -                    - 28 -                    - 29 -                    - 30 -                |- rxsop: controls the sensitivity of the radio - range -65 to -95(Type: int, Required: False) -                |- ax_enabled: Enable AX radio on 2.4Ghz band (Type: bool, Required: False) -                |- valid_auto_channels: Valid Auto Channels for 2.4(Type: list, Required: False) -Available Choices -                    - 1 -                    - 6 -                    - 11 -        |- ssids: SSID Configurations (Type: list, Required: False) -            |- name: Name of SSID (Type: str, Required: False) -            |- state: SSID state (Type: str, Required: False) -Available Choices -                - present -                - absent -            |- enabled: Enable SSID (Type: bool, Required: False) -            |- visible: Broadcast SSID (Type: bool, Required: False) -            |- available_on_all_aps: Enable SSID on all APs (Type: bool, Required: False) -            |- authentication: Authentication Configuration (Type: dict, Required: False) -                |- auth_mode: Auth mode of network (Type: str, Required: False) -Available Choices -                    - open -                    - open-enhanced -                    - psk -                    - open-with-radius -                    - open-with-nac -                    - 8021x-meraki -                    - 8021x-radius -                    - 8021x-google -                    - 8021x-localradius -                    - ipsk-with-radius -                    - ipsk-without-radius -                |- psk: Pre-Shared-Key (Type: str, Required: False) -                |- encryption_mode: Encryption Mode of Network (Type: str, Required: False) -Available Choices -                    - wpa -                    - eap -                    - wpa-eap -                |- wpa_encryption_mode: WPA Encryption Mode (Type: str, Required: False) -Available Choices -                    - WPA1 only -                    - WPA1 and WPA2 -                    - WPA2 only -                    - WPA3 Transition Mode -                    - WPA3 only -                    - WPA3 192-bit Security -            |- vlan: VLAN Configuration (Type: dict, Required: False) -                |- use_vlan_tagging: Use VLAN Tagging (Type: bool, Required: False) -                |- default_vlan_id: Default VLAN ID (Type: str, Required: False) -            |- ip_assignment_mode: IP Assignment mode (Type: str, Required: False) -Available Choices -                - NAT mode -                - Bridge mode -                - Layer 3 roaming -                - Layer 3 roaming with a concentrator -                - VPN -            |- lan_isolation_enabled: Layer 2 LAN Isolation (Type: bool, Required: False) -            |- splash_page: Enable Splash Page (Type: str, Required: False) -Available 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 -                - Cisco ISE - + + |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) +|- auth_key: Meraki API Auth Key (Type: str, Required: True) +|- meraki_mr_configuration:  (Type: dict, Required: True) +    |- network: Network Wide Settings for MX (Type: dict, Required: True) +        |- organization: Meraki Organization (Type: str, Required: True) +        |- name: Meraki Network Name (Type: str, Required: True) +    |- access_points: Access Point Configuration (Type: list, Required: True) +        |- name: Name of MX Appliance (Type: str, Required: True) +        |- rf_profile_name: RF Profile Name (Type: str, Required: False) +    |- general_settings: General MR Settings (Type: dict, Required: False) +        |- ipv6_bridge_enabled: Enable Wireless IPv6 Bridging (Type: bool, Required: False) +        |- led_lights_on: Enable LED lights on Access Points (Type: bool, Required: False) +        |- location_analytics_enabled: Enable Location Analytics (Type: bool, Required: False) +        |- meshing_enabled: Enable Wireless Mesh (Type: bool, Required: False) +        |- upgrade_strategy: Firmware Upgrade Strategy (Type: str, Required: False) +Available Choices +            - minimizeClientDowntime +            - minimizeUpgradeTime +        |- namedVlans: Named VLAN settings for wireless networks (Type: dict, Required: False) +            |- poolDhcpMonitoring: Named VLAN Pool DHCP Monitoring settings (Type: dict, Required: False) +                |- duration: The duration in minutes that devices will refrain from using dirty VLANs before adding them back to the pool (Type: int, Required: False) +                |- enabled: Enable or Disable poolDhcpMonitoring (Type: bool, Required: False) +    |- bluetooth_settings: MR Bluetooth Settings (Type: dict, Required: False) +        |- scanning_enabled: BLE Scanning Enabled (Type: bool, Required: False) +        |- beaconing_enabled: Enable BLE Beaconing (Type: bool, Required: False) +        |- uuid: Bluetooth UUID (Type: str, Required: False) +        |- major_minor_assignment_mode: The way major and minor number should be assigned (Type: str, Required: False) +Available Choices +            - Unique +            - Non-unique +        |- major: Major number in beacon identifier - only valid in non-unique mode (Type: int, Required: False) +        |- minor: Minor number in beacon identifier - only valid in non-unique mode (Type: int, Required: False) +    |- rfProfiles: RF Profile Configuration (Type: list, Required: False) +        |- name: Name of RF Profile (Type: str, Required: False) +        |- state: State of Profile (Type: str, Required: False) +Available Choices +            - present +            - absent +        |- bandSelectionType: Band Selection assigned per AP or SSID (Type: str, Required: False) +Available Choices +            - ap +            - ssid +        |- clientBalancingEnabled: Steer Client to best available AP (Type: bool, Required: False) +        |- apBandSettings: Settings if bandSelectionType is 'ap'(Type: dict, Required: False) +            |- bandOperationMode: RF band the AP will support (Type: str, Required: False) +Available Choices +                - 2.4ghz +                - 5ghz +                - 6ghz +                - dual +                - multi +            |- bandSteeringEnabled: Steers client to most open band (Type: bool, Required: False) +            |- bands: Settings related to all bands (Type: dict, Required: False) +                |- enabled:  (Type: list, Required: False) +Available Choices +                    - 2.4 +                    - 5 +                    - 6 +                    - disabled +        |- flexRadios: Flex radio settings (Type: dict, Required: False) +            |- byModel:  (Type: list, Required: False) +                |- model: AP Model Number (Type: str, Required: False) +                |- bands:  (Type: list, Required: False) +Available Choices +                    - 2.4 +                    - 5 +                    - 6 +                    - disabled +        |- fiveGhzSettings: 5Ghz band settings (Type: dict, Required: False) +            |- maxPower: Sets max power (dBm) of 5Ghz band. Can be integer between 2 and 30. Defaults to 30(Type: int, Required: False) +Available Choices +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 11 +                - 12 +                - 13 +                - 14 +                - 15 +                - 16 +                - 17 +                - 18 +                - 19 +                - 20 +                - 21 +                - 22 +                - 23 +                - 24 +                - 25 +                - 26 +                - 27 +                - 28 +                - 29 +                - 30 +            |- minBitrate: Minimum bitrate of 5Ghz band - defaults to 12(Type: int, Required: False) +Available Choices +                - 6 +                - 9 +                - 12 +                - 18 +                - 24 +                - 36 +                - 48 +                - 54 +            |- minPower: Minimum power in dBm of 5Ghz band - defaults to 8(Type: int, Required: False) +Available Choices +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 11 +                - 12 +                - 13 +                - 14 +                - 15 +                - 16 +                - 17 +                - 18 +                - 19 +                - 20 +                - 21 +                - 22 +                - 23 +                - 24 +                - 25 +                - 26 +                - 27 +                - 28 +                - 29 +                - 30 +            |- rxsop: controls the sensitivity of the radio - range -65 to -95(Type: int, Required: False) +            |- channelWidth: Channel width for 5Ghz band (Type: str, Required: False) +Available Choices +                - auto +                - 20 +                - 40 +                - 80 +            |- validAutoChannels: Valid auto channels for 5ghz band (Type: list, Required: False) +Available Choices +                - 36 +                - 40 +                - 44 +                - 48 +                - 52 +                - 56 +                - 60 +                - 64 +                - 100 +                - 104 +                - 108 +                - 112 +                - 116 +                - 120 +                - 124 +                - 128 +                - 132 +                - 136 +                - 140 +                - 144 +                - 149 +                - 153 +                - 157 +                - 161 +                - 165 +        |- sixGhzSettings: 6Ghz band settings (Type: dict, Required: False) +            |- maxPower: Sets max power (dBm) of 6Ghz band. Can be integer between 2 and 30. Defaults to 30(Type: int, Required: False) +Available Choices +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 11 +                - 12 +                - 13 +                - 14 +                - 15 +                - 16 +                - 17 +                - 18 +                - 19 +                - 20 +                - 21 +                - 22 +                - 23 +                - 24 +                - 25 +                - 26 +                - 27 +                - 28 +                - 29 +                - 30 +            |- minBitrate: Minimum bitrate of 6Ghz band - defaults to 12(Type: int, Required: False) +Available Choices +                - 6 +                - 9 +                - 12 +                - 18 +                - 24 +                - 36 +                - 48 +                - 54 +            |- minPower: Minimum power in dBm of 6Ghz band - defaults to 8(Type: int, Required: False) +Available Choices +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 11 +                - 12 +                - 13 +                - 14 +                - 15 +                - 16 +                - 17 +                - 18 +                - 19 +                - 20 +                - 21 +                - 22 +                - 23 +                - 24 +                - 25 +                - 26 +                - 27 +                - 28 +                - 29 +                - 30 +            |- rxsop: controls the sensitivity of the radio - range -65 to -95(Type: int, Required: False) +            |- channelWidth: Channel width for 6Ghz band (Type: str, Required: False) +Available Choices +                - auto +                - 20 +                - 40 +                - 80 +                - 160 +            |- validAutoChannels: Valid auto channels for 6ghz band (Type: list, Required: False) +Available Choices +                - 1 +                - 5 +                - 9 +                - 13 +                - 17 +                - 21 +                - 25 +                - 29 +                - 33 +                - 37 +                - 41 +                - 45 +                - 49 +                - 53 +                - 57 +                - 61 +                - 65 +                - 69 +                - 73 +                - 77 +                - 81 +                - 85 +                - 89 +                - 93 +                - 97 +                - 101 +                - 105 +                - 109 +                - 113 +                - 117 +                - 121 +                - 125 +                - 129 +                - 133 +                - 137 +                - 141 +                - 145 +                - 149 +                - 153 +                - 157 +                - 161 +                - 165 +                - 169 +                - 173 +                - 177 +                - 181 +                - 185 +                - 189 +                - 193 +                - 197 +                - 201 +                - 205 +                - 209 +                - 213 +                - 217 +                - 221 +                - 225 +                - 229 +        |- transmission: Settings related to radio transmission. (Type: dict, Required: False) +            |- enabled: Toggle for radio transmission.  When false, radios will not transmit at all. (Type: bool, Required: False) +        |- twoFourGhzSettings2.4Ghz band settings (Type: dict, Required: False) +            |- maxPower: Max power in dBm of 2.4Ghz band - defaults to 30(Type: int, Required: False) +Available Choices +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 11 +                - 12 +                - 13 +                - 14 +                - 15 +                - 16 +                - 17 +                - 18 +                - 19 +                - 20 +                - 21 +                - 22 +                - 23 +                - 24 +                - 25 +                - 26 +                - 27 +                - 28 +                - 29 +                - 30 +            |- minBitrate: Minimum bitrate of 2.4Ghz band - defaults to 11(Type: int, Required: False) +Available Choices +                - 1 +                - 2 +                - 5.5 +                - 6 +                - 9 +                - 11 +                - 12 +                - 18 +                - 24 +                - 36 +                - 48 +                - 54 +            |- minPower: Minimum power in dBm of 2.4Ghz band - defaults to 5(Type: int, Required: False) +Available Choices +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 11 +                - 12 +                - 13 +                - 14 +                - 15 +                - 16 +                - 17 +                - 18 +                - 19 +                - 20 +                - 21 +                - 22 +                - 23 +                - 24 +                - 25 +                - 26 +                - 27 +                - 28 +                - 29 +                - 30 +            |- rxsop: controls the sensitivity of the radio - range -65 to -95(Type: int, Required: False) +            |- axEnabled: Enable AX radio on 2.4Ghz band (Type: bool, Required: False) +            |- validAutoChannels: Valid Auto Channels for 2.4(Type: list, Required: False) +Available Choices +                - 1 +                - 6 +                - 11 +        |- perSsidSettings: Per-SID radio settings by number (Type: dict, Required: False) +            |- 0: Settings for SSID 0(Type: dict, Required: False) +                |- minBitrate: Minimum bitrate of this SSID (Type: int, Required: False) +Available Choices +                    - 1 +                    - 2 +                    - 5.5 +                    - 6 +                    - 9 +                    - 11 +                    - 12 +                    - 18 +                    - 24 +                    - 36 +                    - 48 +                    - 54 +                |- bandOperationMode: Band Operation Mode (Type: str, Required: False) +Available Choices +                    - dual +                    - 2.4ghz +                    - 5ghz +                    - 6ghz +                    - multi +                |- name: Name of SSID (Type: str, Required: False) +                |- bandSteeringEnabled: Steers client to most open band between 2.4 GHz and 5 GHz. (Type: bool, Required: False) +                |- bands: Settings related to all bands (Type: dict, Required: False) +                    |- enabled: List of enabled bands (Type: list, Required: ) +Available Choices +                        - 2.4 +                        - 5 +                        - 6 +                        - disabled +    |- ssids: SSID Configurations (Type: list, Required: False) +        |- name: Name of SSID (Type: str, Required: False) +        |- number: Number of SSID (Type: int, Required: False) +Available Choices +            - 0 +            - 1 +            - 2 +            - 3 +            - 4 +            - 5 +            - 6 +            - 7 +            - 8 +            - 9 +            - 10 +            - 11 +            - 12 +            - 13 +            - 14 +        |- state: SSID state (Type: str, Required: False) +Available Choices +            - present +            - absent +        |- enabled: Enable SSID (Type: bool, Required: False) +        |- visible: Broadcast SSID (Type: bool, Required: False) +        |- availableOnAllAps: Enable SSID on all APs (Type: bool, Required: False) +        |- authentication: Authentication Configuration (Type: dict, Required: False) +            |- authMode: Auth mode of network (Type: str, Required: False) +Available Choices +                - open +                - open-enhanced +                - psk +                - open-with-radius +                - open-with-nac +                - 8021x-meraki +                - 8021x-nac +                - 8021x-radius +                - 8021x-google +                - 8021x-localradius +                - ipsk-with-radius +                - ipsk-without-radius +                - ipsk-with-nac +            |- psk: Pre-Shared-Key (Type: str, Required: False) +            |- encryptionMode: Encryption Mode of Network (Type: str, Required: False) +Available Choices +                - open +                - wpa +                - eap +                - wpa-eap +            |- wpaEncryptionMode: WPA Encryption Mode (Type: str, Required: False) +Available Choices +                - WPA1 only +                - WPA1 and WPA2 +                - WPA2 only +                - WPA3 Transition Mode +                - WPA3 only +                - WPA3 192-bit Security +        |- vlan: VLAN Configuration (Type: dict, Required: False) +            |- useVlanTagging: Use VLAN Tagging (Type: bool, Required: False) +            |- defaultVlanId: Default VLAN ID (Type: str, Required: False) +        |- ipAssignmentMode: IP Assignment mode (Type: str, Required: False) +Available Choices +            - NAT mode +            - Bridge mode +            - Layer 3 roaming +            - Layer 3 roaming with a concentrator +            - VPN +        |- lanIsolationEnabled: Layer 2 LAN Isolation (Type: bool, Required: False) +        |- splashPage: Enable Splash Page (Type: str, Required: False) +Available 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 +            - Cisco ISE + diff --git a/assets/configure_meraki_mt.svg b/assets/configure_meraki_mt.svg index 525a60b..8776e7f 100644 --- a/assets/configure_meraki_mt.svg +++ b/assets/configure_meraki_mt.svg @@ -1,4 +1,4 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + - Argument Spec + Argument Spec - + - - |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) -|- auth_key: Meraki API Auth Key (Type: str, Required: True) -|- meraki_mt_configuration:  (Type: list, Required: True) -    |- organization: Meraki Organization (Type: str, Required: True) -    |- network: Meraki Network (Type: str, Required: True) -    |- sensors: Sensor Configuration (Type: list, Required: True) -        |- name: Name of MT Sensor (Type: str, Required: True) -    |- mqtt_brokers: MQTT Broker Configuration (Type: list, Required: False) -        |- name: MQTT Broker Name (Type: str, Required: False) -        |- state: MQTT Broker State (Type: str, Required: False) -Available Choices -            - present -            - absent -        |- enabled: Enable Broker - Only ONE broker can be active at a time (Type: bool, Required: False) -        |- host: MQTT host (Type: str, Required: False) -        |- port: MQTT Server Port (Type: int, Required: False) -        |- authentication:  (Type: dict, Required: False) -            |- username: MQTT Username (Type: str, Required: False) -            |- password: MQTT Password (Type: str, Required: False) -        |- security:  (Type: dict, Required: False) -            |- mode: Security Mode (Type: str, Required: False) -Available Choices -                - none -                - tls -            |- cert_file: CA Certificate File Path (Type: str, Required: False) -            |- hostname_verification: Verify Hostnames (Type: bool, Required: False) -    |- automations: MT Sensor Automations (Type: list, Required: False) -        |- name: Automation Name (Type: str, Required: False) -        |- enabled: Automation Enabled (Type: bool, Required: False) -        |- icon: Automation Icon (Type: str, Required: False) -Available Choices -            - rocket -            - alarm -            - atom -            - barcode -            - briefcase -            - key -            - flask -            - sun -            - chalkboard -            - trophy -            - traffic -            - target -            - chat -            - shield -            - trend -            - warning -        |- conditions: Automation Conditions (Type: list, Required: False) -            |- metric: Metric Type (Type: str, Required: False) -Available Choices -                - button -            |- button: Button Settings (Type: dict, Required: False) -                |- press_type: Button Press Duration (Type: str, Required: False) -Available Choices -                    - short -                    - long -            |- serials: Sensor Serial Numbers (Type: list, Required: False) -        |- targets: Automation Targets (Type: list, Required: False) -            |- target: Target Type (Type: str, Required: False) -Available Choices -                - notification -                - snapshot -                - ssid -                - webhook -            |- notification: Email or SMS Notification (Type: dict, Required: False) -                |- recipient: Email Address or Phone Number (Type: str, Required: False) -                |- message: Message - 255 Character Max (Type: str, Required: False) -                |- notification_type: Notification Type (Type: str, Required: False) -Available Choices -                    - email -                    - phone -            |- snapshot: Camera Snapshot (Type: dict, Required: False) -                |- recipient: Email Address or Phone Number (Type: str, Required: False) -                |- camera: Camera Serial Number (Type: str, Required: False) -                |- notification_type: Notification Type (Type: str, Required: False) -Available Choices -                    - email -                    - phone -            |- webhook: Webhook Alert (Type: dict, Required: False) -                |- id: Meraki Webhook ID (Type: str, Required: False) -                |- message: Webhook Message - 255 Character Max (Type: str, Required: False) -            |- ssid: Toggle SSID (Type: dict, Required: False) -                |- id: Meraki SSID ID (Type: str, Required: False) -                |- action: SSID Toggle Action (Type: str, Required: False) -Available Choices -                    - disable -                    - enable -                    - toggle -    |- schedule: Sensor Schedule (Type: str, Required: False) - + + |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) +|- auth_key: Meraki API Auth Key (Type: str, Required: True) +|- meraki_mt_configuration:  (Type: dict, Required: True) +    |- network: Network Wide Settings for MX (Type: dict, Required: True) +        |- organization: Meraki Organization (Type: str, Required: True) +        |- name: Meraki Network Name (Type: str, Required: True) +    |- sensors: Sensor Configuration (Type: list, Required: True) +        |- name: Name of MT Sensor (Type: str, Required: True) +        |- state: Sensor State (Type: str, Required: ) +Available Choices +            - present +            - absent +    |- mqtt_brokers: MQTT Broker Configuration (Type: list, Required: False) +        |- name: MQTT Broker Name (Type: str, Required: False) +        |- state: MQTT Broker State (Type: str, Required: False) +Available Choices +            - present +            - absent +        |- enabled: Enable Broker - Only ONE broker can be active at a time (Type: bool, Required: False) +        |- host: MQTT host (Type: str, Required: False) +        |- port: MQTT Server Port (Type: int, Required: False) +        |- authentication:  (Type: dict, Required: False) +            |- username: MQTT Username (Type: str, Required: False) +            |- password: MQTT Password (Type: str, Required: False) +        |- security:  (Type: dict, Required: False) +            |- mode: Security Mode (Type: str, Required: False) +Available Choices +                - none +                - tls +            |- certFile: CA Certificate File Path (Type: str, Required: False) +            |- verifyHostnames: Verify Hostnames (Type: bool, Required: False) +    |- automations: MT Sensor Automations (Type: list, Required: False) +        |- name: Automation Name (Type: str, Required: False) +        |- enabled: Automation Enabled (Type: bool, Required: False) +        |- icon: Automation Icon (Type: str, Required: False) +Available Choices +            - rocket +            - alarm +            - atom +            - barcode +            - briefcase +            - key +            - flask +            - sun +            - chalkboard +            - trophy +            - traffic +            - target +            - chat +            - shield +            - trend +            - warning +        |- conditions: Automation Conditions (Type: list, Required: False) +            |- metric: Metric Type (Type: str, Required: False) +Available Choices +                - button +            |- button: Button Settings (Type: dict, Required: False) +                |- press_type: Button Press Duration (Type: str, Required: False) +Available Choices +                    - short +                    - long +            |- serials: Sensor Serial Numbers (Type: list, Required: False) +        |- targets: Automation Targets (Type: list, Required: False) +            |- target: Target Type (Type: str, Required: False) +Available Choices +                - notification +                - snapshot +                - ssid +                - webhook +            |- notification: Email or SMS Notification (Type: dict, Required: False) +                |- recipient: Email Address or Phone Number (Type: str, Required: False) +                |- message: Message - 255 Character Max (Type: str, Required: False) +                |- notification_type: Notification Type (Type: str, Required: False) +Available Choices +                    - email +                    - phone +            |- snapshot: Camera Snapshot (Type: dict, Required: False) +                |- recipient: Email Address or Phone Number (Type: str, Required: False) +                |- camera: Camera Serial Number (Type: str, Required: False) +                |- notification_type: Notification Type (Type: str, Required: False) +Available Choices +                    - email +                    - phone +            |- webhook: Webhook Alert (Type: dict, Required: False) +                |- id: Meraki Webhook ID (Type: str, Required: False) +                |- message: Webhook Message - 255 Character Max (Type: str, Required: False) +            |- ssid: Toggle SSID (Type: dict, Required: False) +                |- id: Meraki SSID ID (Type: str, Required: False) +                |- action: SSID Toggle Action (Type: str, Required: False) +Available Choices +                    - disable +                    - enable +                    - toggle +    |- schedule: Sensor Schedule (Type: str, Required: False) + diff --git a/assets/configure_meraki_mv.svg b/assets/configure_meraki_mv.svg index 6acdf9a..fe658cb 100644 --- a/assets/configure_meraki_mv.svg +++ b/assets/configure_meraki_mv.svg @@ -1,4 +1,4 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + - Argument Spec + Argument Spec - + - - |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) -|- auth_key: Meraki API Auth Key (Type: str, Required: True) -|- meraki_mv_configuration:  (Type: list, Required: True) -    |- organization: Meraki Organization (Type: str, Required: True) -    |- network: Meraki Network (Type: str, Required: True) -    |- camera_profiles: Camera Profile Configuration (Type: dict, Required: False) -        |- wireless: Wireless Profiles (Type: list, Required: False) -            |- name: Profile Name (Type: str, Required: False) -            |- state: Profile state (Type: str, Required: False) -Available Choices -                - present -                - absent -            |- auth_mode: SSID Auth Mode (Type: str, Required: False) -Available Choices -                - psk -                - 8021x-radius -            |- encryption_mode: Encryption Mode (Type: str, Required: False) -Available Choices -                - wpa -                - wpa-eap -            |- ssid: SSID (Type: str, Required: False) -            |- psk: Wireless PSK (Type: str, Required: False) -            |- username: Username when using 8021x-radius (Type: str, Required: False) -            |- password: Password when using 8021x-radius (Type: str, Required: False) -        |- quality_and_retention: Quality and Retention Profiles (Type: list, Required: False) -            |- name: Profile Name (Type: str, Required: False) -            |- state: Profile State (Type: str, Required: False) -Available Choices -                - present -                - absent -            |- cloud_archive: Enable Cloud Archive (Type: bool, Required: False) -            |- max_retention_days: Maximum Cloud Retention Days - Do not set a value to keep until storage is full (Type: int, Required: False) -Available Choices -                - 1 -                - 2 -                - 3 -                - 4 -                - 5 -                - 6 -                - 7 -                - 8 -                - 9 -                - 10 -                - 14 -                - 30 -                - 60 -                - 90 -            |- motion_based_retention: Delete footage older than 3 days in which no motion was detected.  Does not apply to MV2. (Type: bool, Required: False) -            |- motion_detector_version: Motion Detector Version (Type: int, Required: False) -Available Choices -                - 1 -                - 2 -            |- restricted_bandwidth_mode: Disable features that require additional bandwidth.  Does not apply to MV2. (Type: bool, Required: False) -            |- audio_recording: Enable Audio Recording (Type: bool, Required: False) -            |- schedule_name: Camera Recording Schedule Name (Type: bool, Required: False) -            |- video_settings: Camera Specific Video Settings (Type: dict, Required: False) -                |- MV12_MV22_MV72: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1280x720 -                        - 1920x1080 -                |- MV12WE: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1280x720 -                        - 1920x1080 -                |- MV13: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1080x1080 -                        - 2688x1512 -                |- MV21_MV71: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1280x720 -                |- MV22X_MVMV72X: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1280x720 -                        - 1920x1080 -                        - 2688x1512 -                |- MV32: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1080x1080 -                        - 2112x2112 -                |- MV33: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1080x1080 -                        - 2112x2112 -                |- MV52: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1280x720 -                        - 1920x1080 -                        - 2688x1512 -                        - 3840x2160 -                |- MV63: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1920x1080 -                        - 2688x1512 -                |- MV63X: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1920x1080 -                        - 2688x1512 -                        - 3840x2160 -                |- MV93: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1080x1080 -                        - 2112x2112 -                |- MV93X: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1080x1080 -                        - 2112x2112 -                        - 2880x2880 -                |- MV2: Model Specific Settings (Type: dict, Required: False) -                    |- quality: Quality Setting (Type: str, Required: False) -Available Choices -                        - standard -                        - enhanced -                        - high -                    |- resolution: Resolution Setting (Type: str, Required: False) -Available Choices -                        - 1280x720 -                        - 1920x1080 -    |- cameras: Camera Settings (Type: list, Required: False) -        |- name: Camera Name (Type: str, Required: False) -        |- state: Device State (Type: str, Required: False) -Available Choices -            - present -            - absent -        |- quality_and_retention: Quality and Retention Settings (Type: dict, Required: False) -            |- profile_name: Camera Retention Profile Name (Type: str, Required: False) -            |- motion_detector_version: Motion Detector Version (Type: int, Required: False) -Available Choices -                - 1 -                - 2 -            |- audio_recording: Enable Audio Recording (Type: bool, Required: False) -            |- video_resolution: Video Resolution (Type: str, Required: False) -Available Choices -                - 1280x720 -                - 1920x1080 -                - 1080x1080 -                - 2058x2058 -                - 2112x2112 -                - 2880x2880 -                - 2688x1512 -                - 3840x2160 -            |- video_quality: Video Quality (Type: str, Required: False) -Available Choices -                - standard -                - enhanced -                - high -            |- motion_based_retention: Delete footage older than 3 days in which no motion was detected.  Does not apply to MV2. (Type: bool, Required: False) -            |- restricted_bandwidth_mode: Disable features that require additional bandwidth.  Does not apply to MV2. (Type: bool, Required: False) -        |- wireless: Wireless Profiles (Type: dict, Required: False) -            |- profile_1: Primary Wireless Profile Name (Type: str, Required: False) -            |- profile_2: Secondary Wireless Profile Name (Type: str, Required: False) -            |- backup_profile: Backup Wireless Profile Name (Type: str, Required: False) -        |- sense: Enable Camera Sense (Type: dict, Required: False) -            |- enabled: Enable Meraki Sense (Type: bool, Required: False) -            |- audio_detection: Audio Detection Enabled (Type: bool, Required: False) -            |- mqtt_broker_name: MQTT Broker Name (Type: str, Required: False) - + + |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) +|- auth_key: Meraki API Auth Key (Type: str, Required: True) +|- meraki_mv_configuration:  (Type: dict, Required: True) +    |- network: Network Wide Settings for MX (Type: dict, Required: True) +        |- organization: Meraki Organization (Type: str, Required: True) +        |- name: Meraki Network Name (Type: str, Required: True) +    |- camera_profiles: Camera Profile Configuration (Type: dict, Required: True) +        |- wireless: Wireless Profiles (Type: list, Required: False) +            |- name: Profile Name (Type: str, Required: False) +            |- state: Profile state (Type: str, Required: False) +Available Choices +                - present +                - absent +            |- ssid: SSID configuration (Type: dict, Required: False) +                |- name: SSID Name (Type: str, Required: False) +                |- authMode: SSID Auth Mode (Type: str, Required: False) +Available Choices +                    - psk +                    - 8021x-radius +                |- encryptionMode: Encryption Mode (Type: str, Required: False) +Available Choices +                    - wpa +                    - wpa-eap +                |- psk: Wireless PSK (Type: str, Required: False) +            |- identity: Identity Configuration (Type: dict, Required: False) +                |- username: Username when using 8021x-radius (Type: str, Required: False) +                |- password: Password when using 8021x-radius (Type: str, Required: False) +        |- quality_and_retention: Quality and Retention Profiles (Type: list, Required: False) +            |- name: Profile Name (Type: str, Required: False) +            |- state: Profile State (Type: str, Required: False) +Available Choices +                - present +                - absent +            |- cloudArchiveEnabled: Enable Cloud Archive (Type: bool, Required: False) +            |- maxRetentionDays: Maximum Cloud Retention Days - Do not set a value to keep until storage is full (Type: int, Required: False) +Available Choices +                - 1 +                - 2 +                - 3 +                - 4 +                - 5 +                - 6 +                - 7 +                - 8 +                - 9 +                - 10 +                - 14 +                - 30 +                - 60 +                - 90 +            |- motionBasedRetentionEnabled: Delete footage older than 3 days in which no motion was detected.  Does not apply to MV2. (Type: bool, Required: False) +            |- motionDetectorVersion: Motion Detector Version - Defaults to v2 (Type: int, Required: False) +Available Choices +                - 1 +                - 2 +            |- restrictedBandwidthModeEnabled: Disable features that require additional bandwidth.  Does not apply to MV2. (Type: bool, Required: False) +            |- audioRecordingEnabled: Enable Audio Recording (Type: bool, Required: False) +            |- scheduleId: Camera Recording Schedule ID (Type: str, Required: False) +            |- videoSettings: Camera Specific Video Settings (Type: dict, Required: False) +                |- MV12_MV22_MV72: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1280x720 +                        - 1920x1080 +                |- MV12WE: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1280x720 +                        - 1920x1080 +                |- MV13: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1080x1080 +                        - 2688x1512 +                |- MV21_MV71: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1280x720 +                |- MV22X_MVMV72X: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1280x720 +                        - 1920x1080 +                        - 2688x1512 +                |- MV32: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1080x1080 +                        - 2112x2112 +                |- MV33: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1080x1080 +                        - 2112x2112 +                |- MV52: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1280x720 +                        - 1920x1080 +                        - 2688x1512 +                        - 3840x2160 +                |- MV63: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1920x1080 +                        - 2688x1512 +                |- MV63X: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1920x1080 +                        - 2688x1512 +                        - 3840x2160 +                |- MV93: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1080x1080 +                        - 2112x2112 +                |- MV93X: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1080x1080 +                        - 2112x2112 +                        - 2880x2880 +                |- MV2: Model Specific Settings (Type: dict, Required: False) +                    |- quality: Quality Setting (Type: str, Required: False) +Available Choices +                        - standard +                        - enhanced +                        - high +                    |- resolution: Resolution Setting (Type: str, Required: False) +Available Choices +                        - 1280x720 +                        - 1920x1080 +    |- cameras: Camera Settings (Type: list, Required: False) +        |- name: Camera Name (Type: str, Required: False) +        |- state: Device State (Type: str, Required: False) +Available Choices +            - present +            - absent +        |- camera_profiles: Camera Profile Assignment (Type: dict, Required: False) +            |- wireless: Wireless Profiles (Type: dict, Required: False) +                |- primary: Primary Wireless Profile Name (Type: str, Required: False) +                |- secondary: Secondary Wireless Profile Name (Type: str, Required: False) +                |- backup: Backup Wireless Profile Name (Type: str, Required: False) +            |- quality_and_retention: Quality and Retention Profile (Type: dict, Required: False) +                |- name: Quality and Retention Profile Name (Type: str, Required: False) +        |- quality_and_retention_settings: Manual Quality and Retention Settings - Use when not binding to a profile (Type: dict, Required: False) +            |- motionDetectorVersion: Motion Detector Version - Defaults to v2 (Type: int, Required: False) +Available Choices +                - 1 +                - 2 +            |- audioRecordingEnabled: Enable Audio Recording (Type: bool, Required: False) +            |- resolution: Video Resolution (Type: str, Required: False) +Available Choices +                - 1280x720 +                - 1920x1080 +                - 1080x1080 +                - 2058x2058 +                - 2112x2112 +                - 2880x2880 +                - 2688x1512 +                - 3840x2160 +            |- quality: Video Quality (Type: str, Required: False) +Available Choices +                - standard +                - enhanced +                - high +            |- motionBasedRetentionEnabled: Delete footage older than 3 days in which no motion was detected.  Does not apply to MV2. (Type: bool, Required: False) +            |- restrictedBandwidthMode: Disable features that require additional bandwidth.  Does not apply to MV2. (Type: bool, Required: False) +        |- sense: Enable Camera Sense (Type: dict, Required: False) +            |- senseEnabled: Enable Meraki Sense (Type: bool, Required: False) +            |- mqttBrokerName: MQTT Broker Name (Type: str, Required: False) +            |- audioDetection: Audio Detection Settings (Type: dict, Required: False) +                |- enabled: Audio Detection Enabled (Type: bool, Required: False) + diff --git a/assets/configure_meraki_mx.svg b/assets/configure_meraki_mx.svg index 244c159..b1b22b2 100644 --- a/assets/configure_meraki_mx.svg +++ b/assets/configure_meraki_mx.svg @@ -1,4 +1,4 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + - Argument Spec + Argument Spec - + - - |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) -|- auth_key: Meraki API Auth Key (Type: str, Required: True) -|- meraki_mx_configuration:  (Type: dict, Required: True) -    |- appliances: Meraki MX Appliances being Configured (Type: list, Required: True) -        |- name: Name of MX Appliance (Type: str, Required: True) -        |- organization: Meraki Organization (Type: str, Required: True) -        |- network: Meraki Network Name (Type: str, Required: True) -        |- deployment_settings:  (Type: dict, Required: True) -            |- deployment_mode: Appliance Deployment Mode (Type: str, Required: True) -Available Choices -                - routed -                - passthrough -            |- client_tracking: Meraki Client Tracking Method (Type: str, Required: True) -Available Choices -                - MAC address -                - IP address -                - Unique client identifier -            |- dynamic_dns:  (Type: dict, Required: True) -                |- prefix: Dynamic DNS Prefix (Type: str, Required: False) -                |- enabled: Dynamic DNS enabled (Type: bool, Required: False) -        |- wan_interfaces:  (Type: dict, Required: True) -            |- wan1: Configuration for WAN1 Uplink (Type: dict, Required: True) -                |- enabled: Port Enabled (Type: bool, Required: True) -                |- vlan_tagging:  (Type: dict, Required: False) -                    |- enabled: Enable VLAN Tagging on WAN1 (Type: bool, Required: False) -                    |- vlan_id: VLAN ID for WAN1 if enabled (Type: int, Required: False) -                |- svis:  (Type: dict, Required: False) -                    |- ipv4: IPV4 Configuration for WAN1 (Type: dict, Required: False) -                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) -Available Choices -                            - dynamic -                            - static -                        |- address: interface IP address (Type: str, Required: False) -                        |- gateway: interface default gateway (Type: str, Required: False) -                        |- nameservers: nameserver addresses (Type: list, Required: False) -                    |- ipv6: IPV6 Configuration for WAN1 (Type: dict, Required: False) -                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) -Available Choices -                            - dynamic -                            - static -                        |- address: interface IPv6 address (Type: str, Required: False) -                        |- gateway: interface IPv6 default gateway (Type: str, Required: False) -                        |- nameservers: IPv6 nameserver addresses (Type: list, Required: False) -                |- pppoe:  (Type: dict, Required: False) -                    |- enabled: PPPoE State (Type: bool, Required: True) -                    |- authentication:  (Type: dict, Required: False) -                        |- enabled: PPPoE Auth State (Type: bool, Required: False) -                        |- username: PPPoE Username (Type: str, Required: False) -                        |- password: PPPoE Password (Type: str, Required: False) -            |- wan2: Configuration for WAN1 Uplink (Type: dict, Required: True) -                |- enabled: Port Enabled (Type: bool, Required: True) -                |- vlan_tagging:  (Type: dict, Required: False) -                    |- enabled: Enable VLAN Tagging on WAN1 (Type: bool, Required: False) -                    |- vlan_id: VLAN ID for WAN1 if enabled (Type: int, Required: False) -                |- svis:  (Type: dict, Required: False) -                    |- ipv4: IPV4 Configuration for WAN1 (Type: dict, Required: False) -                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) -Available Choices -                            - dynamic -                            - static -                        |- address: interface IP address (Type: str, Required: False) -                        |- gateway: interface default gateway (Type: str, Required: False) -                        |- nameservers: nameserver addresses (Type: list, Required: False) -                    |- ipv6: IPV6 Configuration for WAN1 (Type: dict, Required: False) -                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) -Available Choices -                            - dynamic -                            - static -                        |- address: interface IPv6 address (Type: str, Required: False) -                        |- gateway: interface IPv6 default gateway (Type: str, Required: False) -                        |- nameservers: IPv6 nameserver addresses (Type: list, Required: False) -                |- pppoe:  (Type: dict, Required: False) -                    |- enabled: PPPoE State (Type: bool, Required: False) -                    |- authentication:  (Type: dict, Required: False) -                        |- enabled: PPPoE Auth State (Type: bool, Required: False) -                        |- username: PPPoE Username (Type: str, Required: False) -                        |- password: PPPoE Password (Type: str, Required: False) -        |- lan_settings:  (Type: dict, Required: True) -            |- enable_vlans: Enable VLAN Mode (Type: bool, Required: True) -        |- vlans:  (Type: list, Required: True) -            |- id: VLAN ID (Type: int, Required: True) -            |- state: VLAN State (Type: str, Required: True) -Available Choices -                - present -                - absent -            |- name: VLAN Name (Type: str, Required: False) -            |- subnet: Subnet for VLAN (Type: str, Required: False) -            |- appliance_ip: Default Gateway on MX (Type: str, Required: False) -            |- reserved_ip_range:  (Type: list, Required: False) -                |- start: Starting IP address (Type: str, Required: False) -                |- end: End IP Address (Type: str, Required: False) -                |- comment: DHCP Comment (Type: str, Required: False) -            |- fixed_ip_assignments:  (Type: list, Required: False) -                |- mac: Client MAC Address (Type: str, Required: False) -                |- ip: Client IP Address (Type: str, Required: False) -                |- name: Client Name (Type: str, Required: False) -            |- dns_nameservers: Semi-colon delimited list of DNS IP addresses or opendns, google_dns, upstream_dns (Type: str, Required: False) -        |- ports:  (Type: list, Required: True) -            |- id: Port ID (Type: int, Required: True) -            |- enabled:  (Type: bool, Required: True) -            |- drop_untagged_traffic: Drop Untagged Traffic - Can only be set if port type is trunk (Type: bool, Required: False) -            |- type: Port Type (Type: str, Required: False) -Available Choices -                - access -                - trunk -            |- vlan: Access VLAN or Trunk Native VLAN (Type: int, Required: False) -            |- allowed_vlans: Comma-separated list of VLAN IDs used with trunk ports (Type: str, Required: False) -            |- access_policy: Port Access Policy for access ports (Type: str, Required: False) -Available Choices -                - open -                - 8021x-radius -                - mac-radius -                - hybrid-radius -        |- threat_protection:  (Type: dict, Required: False) -            |- malware: Malware Settings (Type: dict, Required: False) -                |- mode: Enable or Disable AMP (Type: str, Required: False) -Available Choices -                    - enabled -                    - disabled -                |- allowed_urls: List of Whitelisted URLs (Type: list, Required: False) -                    |- url: Whitelisted URL (Type: str, Required: False) -                    |- comment: Comment for Whitelisted URL (Type: str, Required: False) -                |- allowed_files: List of Whitelisted Files (Type: list, Required: False) -                    |- sha256: SHA-256 hash of allowed file (Type: str, Required: False) -                    |- comment: Comment for Whitelisted File (Type: str, Required: False) -            |- intrusion: IDS/IPS Settings (Type: dict, Required: False) -                |- mode: Enable or Disable IDS/IPS (Type: str, Required: False) -Available Choices -                    - disabled -                    - detection -                    - prevention -                |- rulesets: IDS Rulesets (Type: str, Required: False) -Available Choices -                    - balanced -                    - connectivity -                    - security -                |- protected_networks: Protected Networks - only used in passthrough mode (Type: dict, Required: False) -                    |- use_default: Use special IPV4 Addresses (Type: bool, Required: False) -                    |- included_cidr: Included networks in CIDR format (Type: list, Required: False) -                    |- excluded_cidr: Excluded networks in CIDR format (Type: list, Required: False) -            |- firewall:  (Type: dict, Required: False) -                |- l3_rules:  (Type: list, Required: False) -                    |- comment: Rule Description (Type: str, Required: False) -                    |- src_cidr: Source CIDR Address or 'Any'(Type: str, Required: False) -                    |- src_port: Source Port (Type: str, Required: False) -                    |- dest_cidr: Destination CIDR Address or 'Any'(Type: str, Required: False) -                    |- dest_port: Destination Port (Type: str, Required: False) -                    |- protocol: Protocol (Type: str, Required: False) -Available Choices -                        - any -                        - icmp -                        - tcp -                        - udp -                    |- policy: Policy Action (Type: str, Required: False) -Available Choices -                        - allow -                        - deny -                |- l7_rules: Layer 7 Firewall Rules (Type: list, Required: False) -                    |- application: Application to filter (Type: dict, Required: False) -                        |- id: URI of application as defined by Meraki (Type: str, Required: False) -                        |- name: Name of application as defined by Meraki (Type: str, Required: False) -                    |- countries: List of countries - two leter ISO 3166-1 alpha-2(Type: list, Required: False) -                    |- host: FQDN of host to filter (Type: str, Required: False) -                    |- ip_range: CIDR range of IP, can append port with ":"(Type: str, Required: False) -                    |- policy: Policy to apply (Type: str, Required: False) -Available Choices -                        - deny -                    |- port: TCP or UDP port to filter (Type: str, Required: False) -                    |- type: Rule Type (Type: str, Required: False) -Available Choices -                        - application -                        - application_category -                        - blocked_countries -                        - host -                        - ip_range -                        - port -                        - allowed_countries - + + |- dashboard_base_url: Meraki Dashboard Base URL (Type: str, Required: True) +|- auth_key: Meraki API Auth Key (Type: str, Required: True) +|- meraki_mx_configuration:  (Type: dict, Required: True) +    |- network: Network Wide Settings for MX (Type: dict, Required: True) +        |- organization: Meraki Organization (Type: str, Required: True) +        |- name: Meraki Network Name (Type: str, Required: True) +        |- lan_settings: Network Wide LAN Settings for MX (Type: dict, Required: True) +            |- enable_vlans: Enable VLAN Mode (Type: bool, Required: True) +    |- appliances: Meraki MX Appliances being Configured (Type: list, Required: True) +        |- name: Name of MX Appliance (Type: str, Required: True) +        |- deployment_settings:  (Type: dict, Required: True) +            |- deployment_mode: Appliance Deployment Mode (Type: str, Required: True) +Available Choices +                - routed +                - passthrough +            |- client_tracking: Meraki Client Tracking Method (Type: str, Required: True) +Available Choices +                - MAC address +                - IP address +                - Unique client identifier +            |- dynamic_dns:  (Type: dict, Required: True) +                |- prefix: Dynamic DNS Prefix (Type: str, Required: False) +                |- enabled: Dynamic DNS enabled (Type: bool, Required: False) +        |- wan_interfaces:  (Type: dict, Required: True) +            |- wan1: Configuration for WAN1 Uplink (Type: dict, Required: True) +                |- enabled: Port Enabled (Type: bool, Required: True) +                |- vlan_tagging:  (Type: dict, Required: False) +                    |- enabled: Enable VLAN Tagging on WAN1 (Type: bool, Required: False) +                    |- vlan_id: VLAN ID for WAN1 if enabled (Type: int, Required: False) +                |- svis:  (Type: dict, Required: False) +                    |- ipv4: IPV4 Configuration for WAN1 (Type: dict, Required: False) +                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) +Available Choices +                            - dynamic +                            - static +                        |- address: interface IP address (Type: str, Required: False) +                        |- gateway: interface default gateway (Type: str, Required: False) +                        |- nameservers: nameserver addresses (Type: list, Required: False) +                    |- ipv6: IPV6 Configuration for WAN1 (Type: dict, Required: False) +                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) +Available Choices +                            - dynamic +                            - static +                        |- address: interface IPv6 address (Type: str, Required: False) +                        |- gateway: interface IPv6 default gateway (Type: str, Required: False) +                        |- nameservers: IPv6 nameserver addresses (Type: list, Required: False) +                |- pppoe:  (Type: dict, Required: False) +                    |- enabled: PPPoE State (Type: bool, Required: True) +                    |- authentication:  (Type: dict, Required: False) +                        |- enabled: PPPoE Auth State (Type: bool, Required: False) +                        |- username: PPPoE Username (Type: str, Required: False) +                        |- password: PPPoE Password (Type: str, Required: False) +            |- wan2: Configuration for WAN1 Uplink (Type: dict, Required: True) +                |- enabled: Port Enabled (Type: bool, Required: True) +                |- vlan_tagging:  (Type: dict, Required: False) +                    |- enabled: Enable VLAN Tagging on WAN1 (Type: bool, Required: False) +                    |- vlan_id: VLAN ID for WAN1 if enabled (Type: int, Required: False) +                |- svis:  (Type: dict, Required: False) +                    |- ipv4: IPV4 Configuration for WAN1 (Type: dict, Required: False) +                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) +Available Choices +                            - dynamic +                            - static +                        |- address: interface IP address (Type: str, Required: False) +                        |- gateway: interface default gateway (Type: str, Required: False) +                        |- nameservers: nameserver addresses (Type: list, Required: False) +                    |- ipv6: IPV6 Configuration for WAN1 (Type: dict, Required: False) +                        |- assignment_mode: Interface configuration mode (Type: str, Required: False) +Available Choices +                            - dynamic +                            - static +                        |- address: interface IPv6 address (Type: str, Required: False) +                        |- gateway: interface IPv6 default gateway (Type: str, Required: False) +                        |- nameservers: IPv6 nameserver addresses (Type: list, Required: False) +                |- pppoe:  (Type: dict, Required: False) +                    |- enabled: PPPoE State (Type: bool, Required: False) +                    |- authentication:  (Type: dict, Required: False) +                        |- enabled: PPPoE Auth State (Type: bool, Required: False) +                        |- username: PPPoE Username (Type: str, Required: False) +                        |- password: PPPoE Password (Type: str, Required: False) +        |- vlans:  (Type: list, Required: True) +            |- id: VLAN ID (Type: int, Required: True) +            |- state: VLAN State (Type: str, Required: True) +Available Choices +                - present +                - absent +            |- name: VLAN Name (Type: str, Required: False) +            |- subnet: Subnet for VLAN (Type: str, Required: False) +            |- appliance_ip: Default Gateway on MX (Type: str, Required: False) +            |- reserved_ip_range:  (Type: list, Required: False) +                |- start: Starting IP address (Type: str, Required: False) +                |- end: End IP Address (Type: str, Required: False) +                |- comment: DHCP Comment (Type: str, Required: False) +            |- fixed_ip_assignments:  (Type: list, Required: False) +                |- mac: Client MAC Address (Type: dict, Required: False) +                    |- ip: Client IP Address (Type: str, Required: False) +                    |- name: Client Name (Type: str, Required: False) +            |- dns_nameservers: Semi-colon delimited list of DNS IP addresses or opendns, google_dns, upstream_dns (Type: str, Required: False) +        |- ports:  (Type: list, Required: True) +            |- id: Port ID (Type: int, Required: True) +            |- enabled:  (Type: bool, Required: True) +            |- drop_untagged_traffic: Drop Untagged Traffic - Can only be set if port type is trunk (Type: bool, Required: False) +            |- type: Port Type (Type: str, Required: False) +Available Choices +                - access +                - trunk +            |- vlan: Access VLAN or Trunk Native VLAN (Type: int, Required: False) +            |- allowed_vlans: Comma-separated list of VLAN IDs used with trunk ports (Type: str, Required: False) +            |- access_policy: Port Access Policy for access ports (Type: str, Required: False) +Available Choices +                - open +                - 8021x-radius +                - mac-radius +                - hybrid-radius +        |- threat_protection:  (Type: dict, Required: False) +            |- malware: Malware Settings (Type: dict, Required: False) +                |- mode: Enable or Disable AMP (Type: str, Required: False) +Available Choices +                    - enabled +                    - disabled +                |- allowed_urls: List of Whitelisted URLs (Type: list, Required: False) +                    |- url: Whitelisted URL (Type: str, Required: False) +                    |- comment: Comment for Whitelisted URL (Type: str, Required: False) +                |- allowed_files: List of Whitelisted Files (Type: list, Required: False) +                    |- sha256: SHA-256 hash of allowed file (Type: str, Required: False) +                    |- comment: Comment for Whitelisted File (Type: str, Required: False) +            |- intrusion: IDS/IPS Settings (Type: dict, Required: False) +                |- mode: Enable or Disable IDS/IPS (Type: str, Required: False) +Available Choices +                    - disabled +                    - detection +                    - prevention +                |- rulesets: IDS Rulesets (Type: str, Required: False) +Available Choices +                    - balanced +                    - connectivity +                    - security +                |- protected_networks: Protected Networks - only used in passthrough mode (Type: dict, Required: False) +                    |- use_default: Use special IPV4 Addresses (Type: bool, Required: False) +                    |- included_cidr: Included networks in CIDR format (Type: list, Required: False) +                    |- excluded_cidr: Excluded networks in CIDR format (Type: list, Required: False) +            |- firewall:  (Type: dict, Required: False) +                |- l3_rules:  (Type: list, Required: False) +                    |- comment: Rule Description (Type: str, Required: False) +                    |- srcCidr: Source CIDR Address or 'Any'(Type: str, Required: False) +                    |- srcPort: Source Port (Type: str, Required: False) +                    |- destCidr: Destination CIDR Address or 'Any'(Type: str, Required: False) +                    |- destPort: Destination Port (Type: str, Required: False) +                    |- protocol: Protocol (Type: str, Required: False) +Available Choices +                        - any +                        - icmp +                        - tcp +                        - udp +                    |- policy: Policy Action (Type: str, Required: False) +Available Choices +                        - allow +                        - deny +                    |- syslogEnabled: Enable Syslog - only applicable if a syslog server has been configured (Type: bool, Required: False) +                    |- syslogDefaultRule: Log the special default rule (boolean value - enable only if you've configured a syslog server)(Type: bool, Required: False) +                |- l7_rules: Layer 7 Firewall Rules (Type: list, Required: False) +                    |- application: Application to filter (Type: dict, Required: False) +                        |- id: URI of application as defined by Meraki (Type: str, Required: False) +                        |- name: Name of application as defined by Meraki (Type: str, Required: False) +                    |- countries: List of countries - two leter ISO 3166-1 alpha-2(Type: list, Required: False) +                    |- host: FQDN of host to filter (Type: str, Required: False) +                    |- ipRange: CIDR range of IP, can append port with ":"(Type: str, Required: False) +                    |- policy: Policy to apply (Type: str, Required: False) +Available Choices +                        - deny +                    |- port: TCP or UDP port to filter (Type: str, Required: False) +                    |- type: Rule Type (Type: str, Required: False) +Available Choices +                        - application +                        - applicationCategory +                        - blockedCountries +                        - host +                        - ipRange +                        - port +                        - allowedCountries + diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml new file mode 100644 index 0000000..03fa4ee --- /dev/null +++ b/changelogs/changelog.yaml @@ -0,0 +1,11 @@ +ancestor: null +releases: + 1.1.0: + release_date: '2024-05-30' + changes: + release_summary: This release includes updates to support the certified cisco.meraki content collection. + plugins: + lookup: + - description: Fetch data from the Meraki API. + name: fetch + namespace: null diff --git a/changelogs/config.yaml b/changelogs/config.yaml new file mode 100644 index 0000000..d140612 --- /dev/null +++ b/changelogs/config.yaml @@ -0,0 +1,36 @@ +add_plugin_period: true +changelog_filename_template: ../CHANGELOG.md +changelog_filename_version_depth: 0 +changelog_nice_yaml: false +changes_file: changelog.yaml +changes_format: combined +ignore_other_fragment_extensions: true +keep_fragments: false +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +output_formats: + - md +prelude_section_name: release_summary +prelude_section_title: Release Summary +sanitize_changelog: true +sections: + - - major_changes + - Major Changes + - - minor_changes + - Minor Changes + - - breaking_changes + - Breaking Changes / Porting Guide + - - deprecated_features + - Deprecated Features + - - removed_features + - Removed Features (previously deprecated) + - - security_fixes + - Security Fixes + - - bugfixes + - Bugfixes + - - known_issues + - Known Issues +title: wwt.meraki +trivial_section_name: trivial +use_fqcn: true diff --git a/changelogs/fragments/1.1.0-update.yaml b/changelogs/fragments/1.1.0-update.yaml new file mode 100644 index 0000000..9bd371e --- /dev/null +++ b/changelogs/fragments/1.1.0-update.yaml @@ -0,0 +1,5 @@ +breaking_changes: + - configure_meraki_mx - Data model updated to support migration to latest cisco.meraki certified collection. + - configure_meraki_mr - Data model updated to support migration to latest cisco.meraki certified collection. + - configure_meraki_mt - Data model updated to support migration to latest cisco.meraki certified collection. + - configure_meraki_mv - Data model updated to support migration to latest cisco.meraki certified collection. diff --git a/galaxy.yml b/galaxy.yml index cd8c4ca..be41af3 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -9,7 +9,7 @@ namespace: wwt name: meraki # The version of the collection. Must be compatible with semantic versioning -version: 1.0.1 +version: 1.1.0 # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: README.md @@ -44,7 +44,7 @@ tags: # collection label 'namespace.name'. The value is a version range # L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version # range specifiers can be set and are separated by ',' -dependencies: { cisco.meraki: ">=2.15.1" } +dependencies: { cisco.meraki: ">=2.18.0" } # The URL of the originating SCM repository repository: https://github.com/wwt/meraki_collection diff --git a/meta/runtime.yml b/meta/runtime.yml index 84310b6..1e85b01 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,2 +1,2 @@ --- -requires_ansible: ">=2.11.0" +requires_ansible: ">=2.15.0" diff --git a/plugins/lookup/README.md b/plugins/lookup/README.md new file mode 100644 index 0000000..8dbbcd2 --- /dev/null +++ b/plugins/lookup/README.md @@ -0,0 +1,59 @@ +# Ansible Lookup Plugins + +## Description - wwt.meraki.fetch + +This plugin is used to query the Meraki Dashboard API for the requested information + +### Using this Plugin + +The plugin is used by passing a `term` which correlates to the method called to retreive information. + +#### Examples + +Use `wwt.meraki.fetch` to query the organizationId of a given Organization + +```yaml +--- +- name: Configure Meraki Network + cisco.meraki.networks: + meraki_api_key: "{{ auth_key }}" + state: "{{ network.state }}" + organizationId: "{{ lookup('wwt.meraki.fetch', 'org_id', org_name=network.organization, meraki_api_key=auth_key) }}" + name: "{{ network.name }}" + productTypes: "{{ network.type }}" + timeZone: "{{ network.timezone }}" + tags: "{{ network.tags }}" +``` + +Use `wwt.meraki.fetch` to query the networkId of a given Network Name and Organization + +```yaml +--- +- name: Claim Devices + cisco.meraki.networks_devices_claim: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ lookup('wwt.meraki.fetch', 'network_id', org_name=network.organization, meraki_api_key=auth_key, network_name=network.name) }}" + serials: "{{ add_present_devices }}" + when: add_present_devices is defined +``` + +Use `wwt.meraki.fetch` to query the device serial numbers belonging to a given network Name and Organization + +```yaml +--- + - name: Look for existing network devices + ansible.builtin.set_fact: + device_serials: "{{ query('wwt.meraki.fetch', 'network_devices', network_name=network.name, org_name=network.organization, meraki_api_key=auth_key) }}" +``` + +Use `wwt.meraki.fetch` to query for a specific device serial number belong to a given network Name and Organization + +```yaml +- name: Query Device Serial Number for {{ appliance.name }} + ansible.builtin.set_fact: + device_serial: "{{ lookup('wwt.meraki.fetch', 'network_devices', org_name=meraki_mx_configuration.network.organization, meraki_api_key=auth_key, network_name=meraki_mx_configuration.network.name, device_name=appliance.name) }}" +``` + +## Contributors + +Nick Thompson diff --git a/plugins/lookup/fetch.py b/plugins/lookup/fetch.py new file mode 100644 index 0000000..abfbc14 --- /dev/null +++ b/plugins/lookup/fetch.py @@ -0,0 +1,250 @@ +""" +Ansible lookup plugin to fetch data from the Meraki Dashboard + +Written by Nick Thompson (@nsthompson) +Copyright (C) 2024 World Wide Technology +All Rights Reserved +""" + +from __future__ import ( + absolute_import, + division, + print_function +) +from ansible.errors import AnsibleError +from ansible.plugins.lookup import LookupBase +from ansible.utils.display import Display +from ansible.module_utils.six import raise_from + +__metaclass__ = type # pylint: disable=C0103 + +DOCUMENTATION = r""" + name: fetch + author: Nick Thompson (@nsthompson) + version_added: "1.1.0" + short_description: Fetch data from the Meraki API + description: + - This lookup returns the requested data from the Meraki Dashboard API + options: + _terms: + description: + - Requested Data to be Fetched + type: string + required: True + meraki_api_key: + description: + - Meraki API Key + type: string + required: True + org_name: + description: + - Meraki Organization Name + type: string + required: True + network_name: + description: + - Meraki Network Name + type: string + required: False + device_name: + description: + - Meraki Device Name + type: string + required: False + notes: + - Returns fetched information +""" + + +try: + import meraki +except ImportError as import_exception: + MERAKI_IMPORT_EXCEPTION = import_exception +else: + MERAKI_IMPORT_EXCEPTION = None + +display = Display() + + +class Fetch(): + """ + Class to fetch data from the Meraki Dashboard API + """ + def __init__(self, **kwargs): + """ + __init__ looks up the meraki org ID as it is used + by all subsequent dashboard API calls + + Requires: + org_name + meraki_api_key + + Raises: + AnsibleError: Raises an error if the org is not found. + """ + self.kwargs = kwargs + + meraki_api_key = self.kwargs.get("meraki_api_key") + org_name = self.kwargs.get("org_name") + + if ((org_name is None) or (meraki_api_key is None)): + raise AnsibleError( + 'org_name and meraki_api_key are required.' + ) + self.dashboard = meraki.DashboardAPI(meraki_api_key, suppress_logging=True) + display.vvvv( + "Looking for available Meraki organizations..." + ) + organizations = self.dashboard.organizations.getOrganizations() + display.vvvv(f'Looking for Meraki Organization: {org_name}') + + organization_id = None + for org in organizations: + if org.get("name") == org_name: + organization_id = org.get("id") + break + + if organization_id is not None: + self.organization_id = organization_id + else: + raise AnsibleError( + f'organization with name "{org_name}" cannot be found.' + ) + + def org_id(self): + """Method to get Meraki Organization ID by Name + + Requires: + organization_id + + Returns: + list: List of Org IDs + """ + organization_id = self.organization_id + results = [organization_id] + return results + + def network_id(self): + """ + Method to get Meraki Network ID by Name + + Requires: + organization_id + network_name + + Returns: + list: List of Network IDs + """ + organization_id = self.organization_id + network_name = self.kwargs.get("network_name") + + results = [] + + if network_name is not None: + display.vvvv(f'Looking for Meraki Network: {network_name}') + networks = self.dashboard.organizations.getOrganizationNetworks( + organization_id, + total_pages='all' + ) + + for network in networks: + if network.get("name") == network_name: + network_id = network.get("id") + break + + if network_id is not None: + results.append(network_id) + else: + raise AnsibleError( + f'network with name "{network_name}" cannot be found.' + ) + else: + raise AnsibleError( + 'network name must be provided.' + ) + + return results + + def network_devices(self): + """ + Method to get Meraki Network Devices by Network Name + + Requires: + organization_id + network_name + + Returns: + list: List of Network Devices by SN + """ + organization_id = self.organization_id + network_name = self.kwargs.get("network_name") + device_name = self.kwargs.get("device_name") + + results = [] + + if network_name is not None: + display.vvvv(f'Looking for Meraki Network: {network_name}') + networks = self.dashboard.organizations.getOrganizationNetworks( + organization_id, + total_pages='all' + ) + + for network in networks: + if network.get("name") == network_name: + network_id = network.get("id") + break + + if network_id is not None: + display.vvvv( + f'Querying network devices on network ID: {network_id}' + ) + network_devices = self.dashboard.networks.getNetworkDevices( + network_id + ) + for device in network_devices: + # No Device Name Provided - Include All Serial Numbers + if device_name is None: + serial = device.get("serial") + if serial is not None: + results.append(serial) + else: + if device_name == device.get("name"): + serial = device.get("serial") + if serial is not None: + results.append(serial) + break + else: + raise AnsibleError( + f'network with name "{network_name}" cannot be found.' + ) + else: + raise AnsibleError( + 'network name must be provided.' + ) + + return results + + +class LookupModule(LookupBase): # pylint: disable=C0115 + + def run(self, terms, variables=None, **kwargs): + if MERAKI_IMPORT_EXCEPTION: + raise_from( + AnsibleError("meraki sdk must be installed to use this plugin"), + MERAKI_IMPORT_EXCEPTION + ) + + results = [] + + try: + # Connect to Meraki Dashboard API + fetch = Fetch(**kwargs) + + for term in terms: + func = getattr(fetch, term) + results = func() + + except Exception as e: + raise AnsibleError(e) from e + + return results diff --git a/roles/claim_meraki/tasks/main.yml b/roles/claim_meraki/tasks/main.yml index 9df311b..3fe0089 100644 --- a/roles/claim_meraki/tasks/main.yml +++ b/roles/claim_meraki/tasks/main.yml @@ -7,34 +7,22 @@ # # Written by: Nick Thompson (github/@nsthompson) # -- name: Get Meraki Org ID - cisco.meraki.meraki_organization: - auth_key: "{{ auth_key }}" - org_name: "{{ org_name }}" - state: query - delegate_to: localhost - register: org_results +- name: Get org_id of org_name + ansible.builtin.set_fact: + org_id: "{{ query('wwt.meraki.fetch', 'org_id', org_name=org_name, meraki_api_key=auth_key) }}" - name: Claim by Order Number ansible.builtin.import_tasks: order.yml - vars: - org_id: "{{ org_results.data.id }}" when: reg_type == "order" and order_ids is defined - name: Claim by License Key ansible.builtin.import_tasks: license_key.yml - vars: - org_id: "{{ org_results.data.id }}" when: reg_type == "license_key" and license_keys is defined - name: Claim License Renewal ansible.builtin.import_tasks: license_renewal.yml - vars: - org_id: "{{ org_results.data.id }}" when: reg_type == "license_renewal" and license_keys is defined - name: Claim by Serial Number ansible.builtin.import_tasks: device.yml - vars: - org_id: "{{ org_results.data.id }}" when: reg_type == "device" and serial_numbers is defined diff --git a/roles/configure_meraki_mr/meta/argument_specs.yml b/roles/configure_meraki_mr/meta/argument_specs.yml index 486bf5a..eeb1f45 100644 --- a/roles/configure_meraki_mr/meta/argument_specs.yml +++ b/roles/configure_meraki_mr/meta/argument_specs.yml @@ -17,6 +17,19 @@ argument_specs: type: dict required: true options: + network: + type: dict + required: true + description: Network Wide Settings for MX + options: + organization: + type: str + required: true + description: Meraki Organization + name: + type: str + required: true + description: Meraki Network Name access_points: type: list required: true @@ -27,457 +40,779 @@ argument_specs: type: str required: true description: Name of MX Appliance - organization: - type: str - required: true - description: Meraki Organization - network: - type: str - required: true - description: Meraki Network Name rf_profile_name: type: str required: false description: RF Profile Name - general_settings: + general_settings: + type: dict + required: false + description: General MR Settings + options: + ipv6_bridge_enabled: + type: bool + required: false + description: Enable Wireless IPv6 Bridging + led_lights_on: + type: bool + required: false + description: Enable LED lights on Access Points + location_analytics_enabled: + type: bool + required: false + description: Enable Location Analytics + meshing_enabled: + type: bool + required: false + description: Enable Wireless Mesh + upgrade_strategy: + type: str + required: false + description: Firmware Upgrade Strategy + choices: + - minimizeClientDowntime + - minimizeUpgradeTime + namedVlans: type: dict required: false - description: General MR Settings + description: Named VLAN settings for wireless networks options: - ipv6_bridge_enabled: - type: bool + poolDhcpMonitoring: + type: dict required: false - description: Enable Wireless IPv6 Bridging - led_lights_on: - type: bool + description: Named VLAN Pool DHCP Monitoring settings + options: + duration: + type: int + required: false + description: The duration in minutes that devices will refrain from using dirty VLANs before adding them back to the pool + enabled: + type: bool + required: false + description: Enable or Disable poolDhcpMonitoring + bluetooth_settings: + type: dict + required: false + description: MR Bluetooth Settings + options: + scanning_enabled: + type: bool + required: false + description: BLE Scanning Enabled + beaconing_enabled: + type: bool + required: false + description: Enable BLE Beaconing + uuid: + type: str + required: false + description: Bluetooth UUID + major_minor_assignment_mode: + type: str + required: false + description: The way major and minor number should be assigned + choices: + - Unique + - Non-unique + major: + type: int + required: false + description: Major number in beacon identifier - only valid in non-unique mode + minor: + type: int + required: false + description: Minor number in beacon identifier - only valid in non-unique mode + rfProfiles: + type: list + required: false + elements: dict + description: RF Profile Configuration + options: + name: + type: str + required: false + description: Name of RF Profile + state: + type: str + required: false + description: State of Profile + choices: + - present + - absent + bandSelectionType: + type: str + required: false + description: Band Selection assigned per AP or SSID + choices: + - ap + - ssid + clientBalancingEnabled: + type: bool + required: false + description: Steer Client to best available AP + apBandSettings: + type: dict + required: false + description: Settings if bandSelectionType is 'ap' + options: + bandOperationMode: + type: str required: false - description: Enable LED lights on Access Points - location_analytics_enabled: + description: RF band the AP will support + choices: + - 2.4ghz + - 5ghz + - 6ghz + - dual + - multi + bandSteeringEnabled: type: bool required: false - description: Enable Location Analytics - meshing_enabled: - type: bool + description: Steers client to most open band + bands: + type: dict required: false - description: Enable Wireless Mesh - upgrade_strategy: - type: str + description: Settings related to all bands + options: + enabled: + type: list + elements: str + required: false + choices: + - "2.4" + - "5" + - "6" + - disabled + flexRadios: + type: dict + required: false + description: Flex radio settings + options: + byModel: + type: list + elements: dict required: false - description: Firmware Upgrade Strategy - choices: - - minimize_upgrade_time - - minimize_client_downtime - bluetooth_settings: + options: + model: + type: str + required: false + description: AP Model Number + bands: + type: list + elements: str + required: false + choices: + - "2.4" + - "5" + - "6" + - "disabled" + fiveGhzSettings: type: dict required: false - description: MR Bluetooth Settings + description: 5Ghz band settings options: - scanning_enabled: - type: bool + maxPower: + type: int required: false - description: BLE Scanning Enabled - beaconing_enabled: - type: bool + description: Sets max power (dBm) of 5Ghz band. Can be integer between 2 and 30. Defaults to 30. + choices: + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + minBitrate: + type: int required: false - description: Enable BLE Beaconing - uuid: - type: str + description: Minimum bitrate of 5Ghz band - defaults to 12 + choices: + - 6 + - 9 + - 12 + - 18 + - 24 + - 36 + - 48 + - 54 + minPower: + type: int required: false - description: Bluetooth UUID - major_minor_assignment_mode: + description: Minimum power in dBm of 5Ghz band - defaults to 8 + choices: + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + rxsop: + type: int + required: false + description: controls the sensitivity of the radio - range -65 to -95 + channelWidth: type: str required: false - description: The way major and minor number should be assigned + description: Channel width for 5Ghz band choices: - - Unique - - Non-unique - major: + - auto + - "20" + - "40" + - "80" + validAutoChannels: + type: list + elements: int + required: false + description: Valid auto channels for 5ghz band + choices: + - 36 + - 40 + - 44 + - 48 + - 52 + - 56 + - 60 + - 64 + - 100 + - 104 + - 108 + - 112 + - 116 + - 120 + - 124 + - 128 + - 132 + - 136 + - 140 + - 144 + - 149 + - 153 + - 157 + - 161 + - 165 + sixGhzSettings: + type: dict + required: false + description: 6Ghz band settings + options: + maxPower: type: int required: false - description: Major number in beacon identifier - only valid in non-unique mode - minor: + description: Sets max power (dBm) of 6Ghz band. Can be integer between 2 and 30. Defaults to 30. + choices: + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + minBitrate: type: int required: false - description: Minor number in beacon identifier - only valid in non-unique mode - rf_profiles: - type: list + description: Minimum bitrate of 6Ghz band - defaults to 12 + choices: + - 6 + - 9 + - 12 + - 18 + - 24 + - 36 + - 48 + - 54 + minPower: + type: int + required: false + description: Minimum power in dBm of 6Ghz band - defaults to 8 + choices: + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + rxsop: + type: int + required: false + description: controls the sensitivity of the radio - range -65 to -95 + channelWidth: + type: str + required: false + description: Channel width for 6Ghz band + choices: + - auto + - "20" + - "40" + - "80" + - "160" + validAutoChannels: + type: list + elements: int + required: false + description: Valid auto channels for 6ghz band + choices: + - 1 + - 5 + - 9 + - 13 + - 17 + - 21 + - 25 + - 29 + - 33 + - 37 + - 41 + - 45 + - 49 + - 53 + - 57 + - 61 + - 65 + - 69 + - 73 + - 77 + - 81 + - 85 + - 89 + - 93 + - 97 + - 101 + - 105 + - 109 + - 113 + - 117 + - 121 + - 125 + - 129 + - 133 + - 137 + - 141 + - 145 + - 149 + - 153 + - 157 + - 161 + - 165 + - 169 + - 173 + - 177 + - 181 + - 185 + - 189 + - 193 + - 197 + - 201 + - 205 + - 209 + - 213 + - 217 + - 221 + - 225 + - 229 + transmission: + type: dict required: false - elements: dict - description: RF Profile Configuration + description: Settings related to radio transmission. options: - name: - type: str + enabled: + type: bool required: false - description: Name of RF Profile - state: - type: str + description: Toggle for radio transmission. When false, radios will not transmit at all. + twoFourGhzSettings: + type: dict + required: false + description: 2.4Ghz band settings + options: + maxPower: + type: int required: false - description: State of Profile + description: Max power in dBm of 2.4Ghz band - defaults to 30 choices: - - present - - absent - band_selection_type: - type: str + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + minBitrate: + type: int + required: false + description: Minimum bitrate of 2.4Ghz band - defaults to 11 + choices: + - 1 + - 2 + - 5.5 + - 6 + - 9 + - 11 + - 12 + - 18 + - 24 + - 36 + - 48 + - 54 + minPower: + type: int required: false - description: Band Selection assigned per AP or SSID + description: Minimum power in dBm of 2.4Ghz band - defaults to 5 choices: - - ap - - ssid - client_balancing_enabled: + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + rxsop: + type: int + required: false + description: controls the sensitivity of the radio - range -65 to -95 + axEnabled: type: bool required: false - description: Steer Client to best available AP - ap_band_settings: - type: dict + description: Enable AX radio on 2.4Ghz band + validAutoChannels: + type: list + elements: int required: false - description: Settings if band_selection_type is 'ap' - options: - mode: - type: str - required: false - description: RF band the AP will support - choices: - - 2.4ghz - - 5ghz - - dual - band_steering_enabled: - type: bool - required: false - description: Steers client to most open band - five_ghz_settings: + description: Valid Auto Channels for 2.4 + choices: + - 1 + - 6 + - 11 + perSsidSettings: + type: dict + required: false + description: Per-SID radio settings by number + options: + "0": type: dict required: false - description: 5Ghz band settings + description: Settings for SSID 0 options: - max_power: + minBitrate: type: int required: false - description: Max power in dBm of 5Ghz band - choices: - - 8 - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - - 15 - - 16 - - 17 - - 18 - - 19 - - 20 - - 21 - - 22 - - 23 - - 24 - - 25 - - 26 - - 27 - - 28 - - 29 - - 30 - min_bitrate: - type: int - required: false - description: Minimum bitrate of 5Ghz band + description: Minimum bitrate of this SSID choices: + - 1 + - 2 + - 5.5 - 6 - 9 + - 11 - 12 - 18 - 24 - 36 - 48 - 54 - min_power: - type: int - required: false - description: Minimum power in dBm of 5Ghz band - choices: - - 8 - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - - 15 - - 16 - - 17 - - 18 - - 19 - - 20 - - 21 - - 22 - - 23 - - 24 - - 25 - - 26 - - 27 - - 28 - - 29 - - 30 - rxsop: - type: int - required: false - description: controls the sensitivity of the radio - range -65 to -95 - channel_width: + bandOperationMode: type: str required: false - description: Channel width for 5Ghz band - choices: - - auto - - "20" - - "40" - - "80" - valid_auto_channels: - type: list - elements: int - required: false - description: Valid auto channels for 5ghz band - choices: - - 36 - - 40 - - 44 - - 48 - - 52 - - 56 - - 60 - - 64 - - 100 - - 104 - - 108 - - 112 - - 116 - - 120 - - 124 - - 128 - - 132 - - 136 - - 140 - - 144 - - 149 - - 153 - - 157 - - 161 - - 165 - two_four_ghz_settings: - type: dict - required: false - description: 2.4Ghz band settings - options: - max_power: - type: int - required: false - description: Max power in dBm of 2.4Ghz band + description: Band Operation Mode choices: - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - - 15 - - 16 - - 17 - - 18 - - 19 - - 20 - - 21 - - 22 - - 23 - - 24 - - 25 - - 26 - - 27 - - 28 - - 29 - - 30 - min_bitrate: - type: int - required: false - description: Minimum bitrate of 2.4Ghz band - choices: - - 1.0 - - 2.0 - - 5.5 - - 6.0 - - 9.0 - - 11.0 - - 12.0 - - 18.0 - - 24.0 - - 36.0 - - 48.0 - - 54.0 - min_power: - type: int - required: false - description: Minimum power in dBm of 2.4Ghz band - choices: - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - - 15 - - 16 - - 17 - - 18 - - 19 - - 20 - - 21 - - 22 - - 23 - - 24 - - 25 - - 26 - - 27 - - 28 - - 29 - - 30 - rxsop: - type: int + - dual + - 2.4ghz + - 5ghz + - 6ghz + - multi + name: + type: str required: false - description: controls the sensitivity of the radio - range -65 to -95 - ax_enabled: + description: Name of SSID + bandSteeringEnabled: type: bool required: false - description: Enable AX radio on 2.4Ghz band - valid_auto_channels: - type: list - elements: int + description: Steers client to most open band between 2.4 GHz and 5 GHz. + bands: + type: dict required: false - description: Valid Auto Channels for 2.4 - choices: - - 1 - - 6 - - 11 - ssids: - type: list - elements: dict + description: Settings related to all bands + options: + enabled: + type: list + elements: str + description: List of enabled bands + choices: + - "2.4" + - "5" + - "6" + - "disabled" + ssids: + type: list + elements: dict + required: false + description: SSID Configurations + options: + name: + type: str + required: false + description: Name of SSID + number: + type: int + required: false + description: Number of SSID + choices: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + state: + type: str required: false - description: SSID Configurations + description: SSID state + choices: + - present + - absent + enabled: + type: bool + required: false + description: Enable SSID + visible: + type: bool + required: false + description: Broadcast SSID + availableOnAllAps: + type: bool + required: false + description: Enable SSID on all APs + authentication: + type: dict + required: false + description: Authentication Configuration options: - name: - type: str - required: false - description: Name of SSID - state: + authMode: type: str required: false - description: SSID state + description: Auth mode of network choices: - - present - - absent - enabled: - type: bool - required: false - description: Enable SSID - visible: - type: bool - required: false - description: Broadcast SSID - available_on_all_aps: - type: bool - required: false - description: Enable SSID on all APs - authentication: - type: dict + - open + - open-enhanced + - psk + - open-with-radius + - open-with-nac + - 8021x-meraki + - 8021x-nac + - 8021x-radius + - 8021x-google + - 8021x-localradius + - ipsk-with-radius + - ipsk-without-radius + - ipsk-with-nac + psk: + type: str required: false - description: Authentication Configuration - options: - auth_mode: - type: str - required: false - description: Auth mode of network - choices: - - open - - open-enhanced - - psk - - open-with-radius - - open-with-nac - - 8021x-meraki - - 8021x-radius - - 8021x-google - - 8021x-localradius - - ipsk-with-radius - - ipsk-without-radius - psk: - type: str - required: false - description: Pre-Shared-Key - encryption_mode: - type: str - required: false - description: Encryption Mode of Network - choices: - - wpa - - eap - - wpa-eap - wpa_encryption_mode: - type: str - required: false - description: WPA Encryption Mode - choices: - - WPA1 only - - WPA1 and WPA2 - - WPA2 only - - WPA3 Transition Mode - - WPA3 only - - WPA3 192-bit Security - vlan: - type: dict + description: Pre-Shared-Key + encryptionMode: + type: str required: false - description: VLAN Configuration - options: - use_vlan_tagging: - type: bool - required: false - description: Use VLAN Tagging - default_vlan_id: - type: str - required: false - description: Default VLAN ID - ip_assignment_mode: + description: Encryption Mode of Network + choices: + - open + - wpa + - eap + - wpa-eap + wpaEncryptionMode: type: str required: false - description: IP Assignment mode + description: WPA Encryption Mode choices: - - NAT mode - - Bridge mode - - Layer 3 roaming - - Layer 3 roaming with a concentrator - - VPN - lan_isolation_enabled: + - WPA1 only + - WPA1 and WPA2 + - WPA2 only + - WPA3 Transition Mode + - WPA3 only + - WPA3 192-bit Security + vlan: + type: dict + required: false + description: VLAN Configuration + options: + useVlanTagging: type: bool required: false - description: Layer 2 LAN Isolation - splash_page: + description: Use VLAN Tagging + defaultVlanId: type: str required: false - description: Enable Splash Page - 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 - - Cisco ISE + description: Default VLAN ID + ipAssignmentMode: + type: str + required: false + description: IP Assignment mode + choices: + - NAT mode + - Bridge mode + - Layer 3 roaming + - Layer 3 roaming with a concentrator + - VPN + lanIsolationEnabled: + type: bool + required: false + description: Layer 2 LAN Isolation + splashPage: + type: str + required: false + description: Enable Splash Page + 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 + - Cisco ISE diff --git a/roles/configure_meraki_mr/meta/main.yml b/roles/configure_meraki_mr/meta/main.yml index 85dab54..734d23e 100644 --- a/roles/configure_meraki_mr/meta/main.yml +++ b/roles/configure_meraki_mr/meta/main.yml @@ -4,7 +4,7 @@ galaxy_info: description: Configure Meraki MR Access Points company: World Wide Technology license: GPL-3.0-or-later - min_ansible_version: ">=2.11.0" + min_ansible_version: ">=2.15.0" galaxy_tags: - networking - infrastructure diff --git a/roles/configure_meraki_mr/tasks/assign_rf_profiles.yml b/roles/configure_meraki_mr/tasks/assign_rf_profiles.yml index 9b5117c..1281fb7 100644 --- a/roles/configure_meraki_mr/tasks/assign_rf_profiles.yml +++ b/roles/configure_meraki_mr/tasks/assign_rf_profiles.yml @@ -1,18 +1,16 @@ --- - name: Query Device Serial Number for {{ ap.name }} - cisco.meraki.meraki_device: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - hostname: "{{ ap.name }}" - state: query - register: device_results + ansible.builtin.set_fact: + device_serial: "{{ lookup('wwt.meraki.fetch', + 'network_devices', + org_name=meraki_mr_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mr_configuration.network.name, + device_name=ap.name) }}" - name: Assign RF Profile for {{ ap.name }} - cisco.meraki.meraki_mr_radio: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - serial: "{{ device_results['data'][0]['serial'] }}" + cisco.meraki.devices_wireless_radio_settings: + meraki_api_key: "{{ auth_key }}" + rfProfileId: "{{ rf_profile_ids[ap.rf_profile_name].id }}" + serial: "{{ device_serial }}" state: present - rf_profile_id: "{{ rf_profile_ids[ap.rf_profile_name].rf_profile_id }}" diff --git a/roles/configure_meraki_mr/tasks/configure_bluetooth.yml b/roles/configure_meraki_mr/tasks/configure_bluetooth.yml index 5a25c3e..4c137b2 100644 --- a/roles/configure_meraki_mr/tasks/configure_bluetooth.yml +++ b/roles/configure_meraki_mr/tasks/configure_bluetooth.yml @@ -1,7 +1,7 @@ --- - name: Configure Meraki MR Bluetooth Settings block: - - name: Configure MR Bluetooth Settings for {{ ap.network }} + - name: Configure MR Bluetooth Settings for {{ meraki_mr_configuration.network.name }} ansible.builtin.uri: url: "{{ dashboard_base_url }}/networks/{{ network_id }}/wireless/bluetooth/settings" method: PUT @@ -11,18 +11,18 @@ X-Cisco-Meraki-API-Key: "{{ auth_key }}" body_format: json body: - scanningEnabled: "{{ ap.bluetooth_settings.scanning_enabled | default(omit) }}" - advertisingEnabled: "{{ ap.bluetooth_settings.beaconing_enabled | default(omit) }}" - uuid: "{{ ap.bluetooth_settings.uuid | default(omit) }}" - majorMinorAssignmentMode: "{{ ap.bluetooth_settings.major_minor_assignment_mode | default(omit) }}" - major: "{{ ap.bluetooth_settings.major | default(omit) }}" - minor: "{{ ap.bluetooth_settings.minor | default(omit) }}" + scanningEnabled: "{{ meraki_mr_configuration.bluetooth_settings.scanning_enabled | default(omit) }}" + advertisingEnabled: "{{ meraki_mr_configuration.bluetooth_settings.beaconing_enabled | default(omit) }}" + uuid: "{{ meraki_mr_configuration.bluetooth_settings.uuid | default(omit) }}" + majorMinorAssignmentMode: "{{ meraki_mr_configuration.bluetooth_settings.major_minor_assignment_mode | default(omit) }}" + major: "{{ meraki_mr_configuration.bluetooth_settings.major | default(omit) }}" + minor: "{{ meraki_mr_configuration.bluetooth_settings.minor | default(omit) }}" changed_when: api_result.status == 200 until: api_result.status != 429 delay: 5 retries: 3 register: api_result - when: ap.bluetooth_settings is defined + when: meraki_mr_configuration.bluetooth_settings is defined rescue: - name: Something went wrong... ansible.builtin.debug: diff --git a/roles/configure_meraki_mr/tasks/configure_general_settings.yml b/roles/configure_meraki_mr/tasks/configure_general_settings.yml index 5fd9cf6..29d503c 100644 --- a/roles/configure_meraki_mr/tasks/configure_general_settings.yml +++ b/roles/configure_meraki_mr/tasks/configure_general_settings.yml @@ -1,13 +1,17 @@ --- -- name: Configuring General Wireless Settings for {{ ap.network }} - cisco.meraki.meraki_mr_settings: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" +- name: Configuring General Wireless Settings for {{ meraki_mr_configuration.network.name }} + cisco.meraki.networks_wireless_settings: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ lookup('wwt.meraki.fetch', + 'network_id', + org_name=meraki_mr_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mr_configuration.network.name) }}" state: present - ipv6_bridge_enabled: "{{ ap.general_settings.ipv6_bridge_enabled | default(omit) }}" - led_lights_on: "{{ ap.general_settings.led_lights_on | default(omit) }}" - location_analytics_enabled: "{{ ap.general_settings.location_analytics_enabled | default(omit) }}" - meshing_enabled: "{{ ap.general_settings.meshing_enabled | default(omit) }}" - upgrade_strategy: "{{ ap.general_settings.upgrade_strategy | default(omit) }}" - when: ap.general_settings is defined + ipv6BridgeEnabled: "{{ meraki_mr_configuration.general_settings.ipv6_bridge_enabled | default(omit) }}" + ledLightsOn: "{{ meraki_mr_configuration.general_settings.led_lights_on | default(omit) }}" + locationAnalyticsEnabled: "{{ meraki_mr_configuration.general_settings.location_analytics_enabled | default(omit) }}" + meshingEnabled: "{{ meraki_mr_configuration.general_settings.meshing_enabled | default(omit) }}" + upgradeStrategy: "{{ meraki_mr_configuration.general_settings.upgrade_strategy | default(omit) }}" + poolDhcpMonitoring: "{{ meraki_mr_configuration.general_settings.poolDhcpMonitoring | default(omit) }}" + when: meraki_mr_configuration.general_settings is defined diff --git a/roles/configure_meraki_mr/tasks/configure_rf_profiles.yml b/roles/configure_meraki_mr/tasks/configure_rf_profiles.yml index 469f662..06a1a10 100644 --- a/roles/configure_meraki_mr/tasks/configure_rf_profiles.yml +++ b/roles/configure_meraki_mr/tasks/configure_rf_profiles.yml @@ -2,11 +2,9 @@ - name: Configure RF Profiles block: - name: Querying for existing RF Profiles - cisco.meraki.meraki_mr_rf_profile: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - state: query + cisco.meraki.networks_wireless_rf_profiles_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" register: profile_results rescue: - name: Something went wrong... @@ -19,28 +17,31 @@ {{ rf_profile_ids | default({}) | combine( { result.name: { - "rf_profile_id": result.id, + "id": result.id, } } ) }} - loop: "{{ profile_results.data }}" + loop: "{{ profile_results.meraki_response }}" loop_control: loop_var: result - when: profile_results.data is defined + when: profile_results.meraki_response is defined -- name: Configuring RF Profiles - cisco.meraki.meraki_mr_rf_profile: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" +- name: Creating RF Profiles + cisco.meraki.networks_wireless_rf_profiles: + meraki_api_key: "{{ auth_key }}" state: "{{ profile.state }}" name: "{{ profile.name }}" - band_selection_type: "{{ profile.band_selection_type | default(omit) }}" - client_balancing_enabled: "{{ profile.client_balancing_enabled | default(omit) }}" - ap_band_settings: "{{ profile.ap_band_settings | default(omit) }}" - five_ghz_settings: "{{ profile.five_ghz_settings | default(omit) }}" - two_four_ghz_settings: "{{ profile.two_four_ghz_settings | default(omit) }}" - loop: "{{ ap.rf_profiles }}" + networkId: "{{ network_id }}" + bandSelectionType: "{{ profile.bandSelectionType | default(omit) }}" + clientBalancingEnabled: "{{ profile.clientBalancingEnabled | default(omit) }}" + apBandSettings: "{{ profile.apBandSettings | default(omit) }}" + twoFourGhzSettings: "{{ profile.twoFourGhzSettings | default(omit) }}" + fiveGhzSettings: "{{ profile.fiveGhzSettings | default(omit) }}" + sixGhzSettings: "{{ profile.sixGhzSettings | default(omit) }}" + transmission: "{{ profile.transmission | default(omit) }}" + flexRadios: "{{ profile.flexRadios | default(omit) }}" + perSsidSettings: "{{ profile.perSsidSettings | default(omit) }}" + loop: "{{ meraki_mr_configuration.rfProfiles }}" loop_control: loop_var: profile when: rf_profile_ids[profile.name] is undefined and profile.state == "present" @@ -49,10 +50,10 @@ - name: Add newly created RF profile to dict ansible.builtin.set_fact: rf_profile_ids: >- - {{ rf_profile_ids|default({}) | combine( + {{ rf_profile_ids | default({}) | combine( { - result.data.name: { - "rf_profile_id": result.data.id, + result.meraki_response.name: { + "id": result.meraki_response.id, } } ) }} @@ -62,30 +63,33 @@ when: not rf_profile_output.skipped - name: Updating RF Profiles - cisco.meraki.meraki_mr_rf_profile: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" + cisco.meraki.networks_wireless_rf_profiles: + meraki_api_key: "{{ auth_key }}" state: "{{ profile.state }}" - profile_id: "{{ rf_profile_ids[profile.name].rf_profile_id }}" - band_selection_type: "{{ profile.band_selection_type | default(omit) }}" - client_balancing_enabled: "{{ profile.client_balancing_enabled | default(omit) }}" - ap_band_settings: "{{ profile.ap_band_settings | default(omit) }}" - five_ghz_settings: "{{ profile.five_ghz_settings | default(omit) }}" - two_four_ghz_settings: "{{ profile.two_four_ghz_settings | default(omit) }}" - loop: "{{ ap.rf_profiles }}" + name: "{{ profile.name }}" + networkId: "{{ network_id }}" + rfProfileId: "{{ rf_profile_ids[profile.name].id }}" + bandSelectionType: "{{ profile.bandSelectionType | default(omit) }}" + clientBalancingEnabled: "{{ profile.clientBalancingEnabled | default(omit) }}" + apBandSettings: "{{ profile.apBandSettings | default(omit) }}" + twoFourGhzSettings: "{{ profile.twoFourGhzSettings | default(omit) }}" + fiveGhzSettings: "{{ profile.fiveGhzSettings | default(omit) }}" + sixGhzSettings: "{{ profile.sixGhzSettings | default(omit) }}" + transmission: "{{ profile.transmission | default(omit) }}" + flexRadios: "{{ profile.flexRadios | default(omit) }}" + perSsidSettings: "{{ profile.perSsidSettings | default(omit) }}" + loop: "{{ meraki_mr_configuration.rfProfiles }}" loop_control: loop_var: profile when: rf_profile_ids[profile.name] is defined and profile.state == "present" - name: Removing RF Profiles - cisco.meraki.meraki_mr_rf_profile: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" + cisco.meraki.networks_wireless_rf_profiles: + meraki_api_key: "{{ auth_key }}" state: "{{ profile.state }}" - profile_id: "{{ rf_profile_ids[profile.name].rf_profile_id }}" - loop: "{{ ap.rf_profiles }}" + networkId: "{{ network_id }}" + rfProfileId: "{{ rf_profile_ids[profile.name].id }}" + loop: "{{ meraki_mr_configuration.rfProfiles }}" loop_control: loop_var: profile when: rf_profile_ids[profile.name] is defined and profile.state == "absent" diff --git a/roles/configure_meraki_mr/tasks/configure_ssids.yml b/roles/configure_meraki_mr/tasks/configure_ssids.yml index 9888647..1e7fd72 100644 --- a/roles/configure_meraki_mr/tasks/configure_ssids.yml +++ b/roles/configure_meraki_mr/tasks/configure_ssids.yml @@ -1,36 +1,24 @@ --- - name: Configuring Wireless SSIDs - cisco.meraki.meraki_mr_ssid: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" + cisco.meraki.networks_wireless_ssids: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" name: "{{ ssid.name }}" + number: "{{ ssid.number }}" state: "{{ ssid.state }}" enabled: "{{ ssid.enabled }}" visible: "{{ ssid.visible | default(omit) }}" - available_on_all_aps: "{{ ssid.available_on_all_aps | default(omit) }}" - auth_mode: "{{ ssid.authentication.auth_mode | default(omit) }}" + availableOnAllAps: "{{ ssid.availableOnAllAps | default(omit) }}" + authMode: "{{ ssid.authentication.authMode | default(omit) }}" psk: "{{ ssid.authentication.psk | default(omit) }}" - encryption_mode: "{{ ssid.authentication.encryption_mode | default(omit) }}" - wpa_encryption_mode: "{{ ssid.authentication.wpa_encryption_mode | default(omit) }}" - use_vlan_tagging: "{{ ssid.vlan.use_vlan_tagging | default(omit) }}" - default_vlan_id: "{{ ssid.vlan.default_vlan_id | default(omit) }}" - ip_assignment_mode: "{{ ssid.ip_assignment_mode | default(omit) }}" - lan_isolation_enabled: "{{ ssid.lan_isolation_enabled | default(omit) }}" - splash_page: "{{ ssid.splash_page | default(omit) }}" - loop: "{{ ap.ssids }}" + encryptionMode: "{{ ssid.authentication.encryptionMode | default(omit) }}" + wpaEncryptionMode: "{{ ssid.authentication.wpaEncryptionMode | default(omit) }}" + useVlanTagging: "{{ ssid.vlan.useVlanTagging | default(omit) }}" + defaultVlanId: "{{ ssid.vlan.defaultVlanId | default(omit) }}" + ipAssignmentMode: "{{ ssid.ipAssignmentMode | default(omit) }}" + lanIsolationEnabled: "{{ ssid.lanIsolationEnabled | default(omit) }}" + splashPage: "{{ ssid.splashPage | default(omit) }}" + loop: "{{ meraki_mr_configuration.ssids }}" loop_control: loop_var: ssid when: ssid.state == "present" - -- name: Remove Wireless SSIDs - cisco.meraki.meraki_mr_ssid: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - name: "{{ ssid.name }}" - state: "{{ ssid.state }}" - loop: "{{ ap.ssids }}" - loop_control: - loop_var: ssid - when: ssid.state == "absent" diff --git a/roles/configure_meraki_mr/tasks/main.yml b/roles/configure_meraki_mr/tasks/main.yml index 9469514..69214bc 100644 --- a/roles/configure_meraki_mr/tasks/main.yml +++ b/roles/configure_meraki_mr/tasks/main.yml @@ -7,58 +7,32 @@ # # Written by: Nick Thompson (github/@nsthompson) # -- name: Get Meraki Network IDs - cisco.meraki.meraki_network: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - state: query - loop: "{{ meraki_mr_configuration.access_points }}" - loop_control: - loop_var: ap - register: network_results +- name: Look Up Meraki MR Access Point Network ID + ansible.builtin.set_fact: + network_id: "{{ lookup('wwt.meraki.fetch', + 'network_id', + org_name=meraki_mr_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mr_configuration.network.name) }}" - name: Failure - Network DOES NOT exist ansible.builtin.fail: msg: Meraki Network is not provisioned - when: network_results.results[0].data.id is not defined - -- name: Build dict of Network Name to IDs - ansible.builtin.set_fact: - network_ids: >- - {{ network_ids | default({}) | combine( - { - result.data.name: { - "network_id": result.data.id, - } - } - ) }} - loop: "{{ network_results.results }}" - loop_control: - loop_var: result + when: network_id is not defined - name: Remove Default SSID ansible.builtin.include_tasks: remove_default_ssid.yml - loop: "{{ meraki_mr_configuration.access_points }}" - loop_control: - loop_var: ap tags: - wireless - ssid - name: Configure General Settings ansible.builtin.include_tasks: configure_general_settings.yml - loop: "{{ meraki_mr_configuration.access_points }}" - loop_control: - loop_var: ap tags: - wireless - name: Configure RF Profiles ansible.builtin.include_tasks: configure_rf_profiles.yml - loop: "{{ meraki_mr_configuration.access_points }}" - loop_control: - loop_var: ap tags: - wireless - rf_profiles @@ -74,20 +48,18 @@ - name: Configure SSIDs ansible.builtin.include_tasks: configure_ssids.yml - loop: "{{ meraki_mr_configuration.access_points }}" - loop_control: - loop_var: ap + tags: + - wireless + - ssid + +- name: Remove SSIDs + ansible.builtin.include_tasks: remove_ssids.yml tags: - wireless - ssid - name: Configure Bluetooth Settings ansible.builtin.include_tasks: configure_bluetooth.yml - vars: - network_id: "{{ network_ids[ap.network]['network_id'] }}" - loop: "{{ meraki_mr_configuration.access_points }}" - loop_control: - loop_var: ap tags: - wireless - bluetooth diff --git a/roles/configure_meraki_mr/tasks/remove_default_ssid.yml b/roles/configure_meraki_mr/tasks/remove_default_ssid.yml index bcf1bf8..ef5ee9b 100644 --- a/roles/configure_meraki_mr/tasks/remove_default_ssid.yml +++ b/roles/configure_meraki_mr/tasks/remove_default_ssid.yml @@ -1,24 +1,36 @@ --- -- name: Check for Default SSID - block: - - name: Check for default SSID - {{ ap.network + ' - wireless WiFi' }} - cisco.meraki.meraki_mr_ssid: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - name: "{{ ap.network }} - wireless WiFi" - state: query - register: ssid_result - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "SSID NOT FOUND - ERROR: {{ ssid_result.msg }}" +- name: Set default_ssid to {{ meraki_mr_configuration.network.name + ' - wireless WiFi' }} + ansible.builtin.set_fact: + default_ssid: "{{ meraki_mr_configuration.network.name + ' - wireless WiFi' }}" -- name: Remove default SSID - {{ ap.network + ' - wireless WiFi' }} - cisco.meraki.meraki_mr_ssid: - auth_key: "{{ auth_key }}" - org_name: "{{ ap.organization }}" - net_name: "{{ ap.network }}" - name: "{{ ap.network }} - wireless WiFi" - state: absent - when: ssid_result.status == 200 +- name: Check for Existing SSIDs + cisco.meraki.networks_wireless_ssids_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + register: ssid_results + +- name: Parse SSID Data + ansible.builtin.set_fact: + ssid_data: >- + {{ ssid_data | default({}) | combine( + { + response.name: { + "number": response.number, + "enabled": response.enabled + } + } + ) }} + loop: "{{ ssid_results.meraki_response }}" + loop_control: + loop_var: response + when: ssid_results.meraki_response is defined + +- name: Remove and Disable Default SSID + cisco.meraki.networks_wireless_ssids: + meraki_api_key: "{{ auth_key }}" + state: present + name: "{{ 'Unconfigured SSID ' + ((ssid_data[default_ssid].number | int + 1) | string) }}" + number: "{{ ssid_data[default_ssid]['number'] }}" + enabled: false + networkId: "{{ network_id }}" + when: ssid_data[default_ssid] is defined and ssid_data[default_ssid]['enabled'] is true diff --git a/roles/configure_meraki_mr/tasks/remove_ssids.yml b/roles/configure_meraki_mr/tasks/remove_ssids.yml new file mode 100644 index 0000000..842a914 --- /dev/null +++ b/roles/configure_meraki_mr/tasks/remove_ssids.yml @@ -0,0 +1,35 @@ +--- +- name: Check for Existing SSIDs + cisco.meraki.networks_wireless_ssids_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + register: ssid_results + +- name: Parse SSID Data + ansible.builtin.set_fact: + ssid_data: >- + {{ ssid_data | default({}) | combine( + { + response.name: { + "number": response.number, + "enabled": response.enabled + } + } + ) }} + loop: "{{ ssid_results.meraki_response }}" + loop_control: + loop_var: response + when: ssid_results.meraki_response is defined + +- name: Remove and Disable SSIDs + cisco.meraki.networks_wireless_ssids: + meraki_api_key: "{{ auth_key }}" + state: present + name: "{{ 'Unconfigured SSID ' + ((ssid_data[ssid.name].number | int + 1) | string) }}" + number: "{{ ssid.number }}" + enabled: false + networkId: "{{ network_id }}" + loop: "{{ meraki_mr_configuration.ssids }}" + loop_control: + loop_var: ssid + when: ssid.state == "absent" and ssid_data[ssid.name] is defined diff --git a/roles/configure_meraki_mt/meta/argument_specs.yml b/roles/configure_meraki_mt/meta/argument_specs.yml index fb2278d..0037316 100644 --- a/roles/configure_meraki_mt/meta/argument_specs.yml +++ b/roles/configure_meraki_mt/meta/argument_specs.yml @@ -14,18 +14,22 @@ argument_specs: required: true description: Meraki API Auth Key meraki_mt_configuration: - type: list - elements: dict + type: dict required: true options: - organization: - type: str - required: true - description: Meraki Organization network: - type: str + type: dict required: true - description: Meraki Network + description: Network Wide Settings for MX + options: + organization: + type: str + required: true + description: Meraki Organization + name: + type: str + required: true + description: Meraki Network Name sensors: type: list required: true @@ -36,6 +40,12 @@ argument_specs: type: str required: true description: Name of MT Sensor + state: + type: str + description: Sensor State + choices: + - present + - absent mqtt_brokers: type: list elements: dict @@ -88,11 +98,11 @@ argument_specs: choices: - none - tls - cert_file: + certFile: type: str required: false description: CA Certificate File Path - hostname_verification: + verifyHostnames: type: bool required: false description: Verify Hostnames diff --git a/roles/configure_meraki_mt/meta/main.yml b/roles/configure_meraki_mt/meta/main.yml index 94977ba..bb2558b 100644 --- a/roles/configure_meraki_mt/meta/main.yml +++ b/roles/configure_meraki_mt/meta/main.yml @@ -4,7 +4,7 @@ galaxy_info: description: Configure Meraki MT Sensors company: World Wide Technology license: GPL-3.0-or-later - min_ansible_version: ">=2.11.0" + min_ansible_version: ">=2.15.0" galaxy_tags: - networking - infrastructure diff --git a/roles/configure_meraki_mt/tasks/configure_mqtt.yml b/roles/configure_meraki_mt/tasks/configure_mqtt.yml index 67872df..dce2e60 100644 --- a/roles/configure_meraki_mt/tasks/configure_mqtt.yml +++ b/roles/configure_meraki_mt/tasks/configure_mqtt.yml @@ -1,7 +1,7 @@ --- - name: Query for existing MQTT brokers block: - - name: Query for existing MQTT brokers on Network {{ config.network }} + - name: Query for existing MQTT brokers on Network {{ meraki_mt_configuration.network.name }} ansible.builtin.uri: url: "{{ dashboard_base_url }}/networks/{{ network_id }}/mqttBrokers" method: GET @@ -14,7 +14,7 @@ delay: 5 retries: 3 register: broker_result - when: config.mqtt_brokers is defined + when: meraki_mt_configuration is defined rescue: - name: Something went wrong... ansible.builtin.debug: @@ -26,7 +26,7 @@ {{ mqtt_broker_ids | default({}) | combine( { result.name: { - "broker_id": result.id, + "id": result.id, } } ) }} @@ -35,53 +35,69 @@ loop_var: result when: broker_result.status == 200 -- name: Configure MQTT Broker - block: - - name: Configure MQTT Broker for Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/mqttBrokers" - method: POST - status_code: 201 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/mqtt_broker.j2') }}" - changed_when: create_broker_result.status == 201 - until: create_broker_result.status != 429 - delay: 5 - retries: 3 - register: create_broker_result - when: mqtt_broker_ids[broker.name] is undefined and broker.state == "present" - loop: "{{ config.mqtt_brokers }}" - loop_control: - loop_var: broker - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ create_broker_result }}" +- name: Configure MQTT Brokers + cisco.meraki.networks_mqtt_brokers: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + name: "{{ broker.name }}" + authentication: "{{ broker.authentication }}" + host: "{{ broker.host }}" + port: "{{ broker.port }}" + security: + mode: "{{ broker.security.mode }}" + tls: + caCertificate: "{{ lookup('ansible.builtin.file', broker.security.certFile) }}" + verifyHostnames: "{{ broker.security.verifyHostnames }}" + loop: "{{ meraki_mt_configuration.mqtt_brokers | list }}" + loop_control: + loop_var: broker + when: broker.state == "present" and mqtt_broker_ids[broker.name] is not defined + register: broker_result - name: Add newly created broker to dict ansible.builtin.set_fact: mqtt_broker_ids: >- {{ mqtt_broker_ids | default({}) | combine( { - result.json.name: { - "broker_id": result.json.id, + result.meraki_response.name: { + "id": result.meraki_response.id, } } ) }} - loop: "{{ create_broker_result.results }}" + loop: "{{ broker_result.results }}" loop_control: loop_var: result - when: result.skipped is not true and result.status == 201 + when: not result.skipped + +- name: Enable MQTT Brokers + cisco.meraki.networks_sensor_mqtt_brokers: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + state: "{{ broker.state }}" + enabled: "{{ broker.enabled }}" + mqttBrokerId: "{{ mqtt_broker_ids[broker.name].id }}" + loop: "{{ meraki_mt_configuration.mqtt_brokers | list }}" + loop_control: + loop_var: broker + when: broker.state == "present" and broker.enabled - name: Delete MQTT Broker block: - - name: Deleting MQTT Broker for Network {{ config.network }} + - name: Disable MQTT Broker before deletion + cisco.meraki.networks_sensor_mqtt_brokers: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + state: present + enabled: false + mqttBrokerId: "{{ mqtt_broker_ids[broker.name].id }}" + loop: "{{ meraki_mt_configuration.mqtt_brokers | list }}" + loop_control: + loop_var: broker + when: mqtt_broker_ids[broker.name] is defined and broker.state == "absent" + + - name: Deleting MQTT Broker for Network {{ meraki_mt_configuration.network.name }} ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/mqttBrokers/{{ mqtt_broker_ids[broker.name].broker_id }}" + url: "{{ dashboard_base_url }}/networks/{{ network_id }}/mqttBrokers/{{ mqtt_broker_ids[broker.name].id }}" method: DELETE status_code: 204 headers: @@ -94,37 +110,10 @@ retries: 3 register: delete_broker_result when: mqtt_broker_ids[broker.name] is defined and broker.state == "absent" - loop: "{{ config.mqtt_brokers }}" + loop: "{{ meraki_mt_configuration.mqtt_brokers }}" loop_control: loop_var: broker rescue: - name: Something went wrong... ansible.builtin.debug: msg: "ERROR: {{ delete_broker_result }}" - -- name: Enable MQTT Broker - block: - - name: Enabling MQTT Broker for Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/sensor/mqttBrokers/{{ mqtt_broker_ids[broker.name].broker_id }}" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: - enabled: "{{ broker.enabled }}" - changed_when: enable_broker_result.status == 200 - until: enable_broker_result.status != 429 - delay: 5 - retries: 3 - register: enable_broker_result - loop: "{{ config.mqtt_brokers }}" - loop_control: - loop_var: broker - when: mqtt_broker_ids[broker.name] is defined and broker.enabled - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ enable_broker_result }}" diff --git a/roles/configure_meraki_mt/tasks/main.yml b/roles/configure_meraki_mt/tasks/main.yml index dbcf638..e225086 100644 --- a/roles/configure_meraki_mt/tasks/main.yml +++ b/roles/configure_meraki_mt/tasks/main.yml @@ -7,43 +7,21 @@ # # Written by: Nick Thompson (github/@nsthompson) # -- name: Get Meraki Network IDs - cisco.meraki.meraki_network: - auth_key: "{{ auth_key }}" - org_name: "{{ config.organization }}" - net_name: "{{ config.network }}" - state: query - loop: "{{ meraki_mt_configuration }}" - loop_control: - loop_var: config - register: network_results +- name: Look Up Meraki MT Sensor Network ID + ansible.builtin.set_fact: + network_id: "{{ lookup('wwt.meraki.fetch', + 'network_id', + org_name=meraki_mt_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mt_configuration.network.name) }}" - name: Failure - Network DOES NOT exist ansible.builtin.fail: msg: Meraki Network is not provisioned - when: network_results.results[0].data.id is not defined - -- name: Build dict of Network Name to IDs - ansible.builtin.set_fact: - network_ids: >- - {{ network_ids | default({}) | combine( - { - result.data.name: { - "network_id": result.data.id, - } - } - ) }} - loop: "{{ network_results.results }}" - loop_control: - loop_var: result + when: network_id is not defined - name: Configure MQTT ansible.builtin.include_tasks: configure_mqtt.yml - vars: - network_id: "{{ network_ids[config.network]['network_id'] }}" - loop: "{{ meraki_mt_configuration }}" - loop_control: - loop_var: config # # Sensor Automation API Endpoint Is not published yet diff --git a/roles/configure_meraki_mt/templates/mqtt_broker.j2 b/roles/configure_meraki_mt/templates/mqtt_broker.j2 deleted file mode 100644 index 28c7c29..0000000 --- a/roles/configure_meraki_mt/templates/mqtt_broker.j2 +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "new", - "placeholderPassword": false, - "name": "{{ broker.name }}", - "host": "{{ broker.host }}", - "port": {{ broker.port }}, - {% if broker.security is defined %} - "caFileName": "{{ broker.security.cert_file.split('/')[1] }}", - {% endif %} - {% if broker.authentication is defined %} - "authentication": { - "username": "{{ broker.authentication.username }}", - "password": "{{ broker.authentication.password }}" - }, - {% endif %} - {% if broker.security is defined %} - "security": { - "mode": "{{ broker.security.mode }}", - "tls": { - {%- set cert_contents -%} - {% include broker.security.cert_file %} - {%- endset -%} - "caCertificate": "{{ cert_contents | replace('\n', '\\n') }}", - "hasCaCertificate": true, - "verifyHostnames": {{ broker.security.hostname_verification }} - } - } - {% endif %} -} \ No newline at end of file diff --git a/roles/configure_meraki_mv/meta/argument_specs.yml b/roles/configure_meraki_mv/meta/argument_specs.yml index 0edd9d4..584b571 100644 --- a/roles/configure_meraki_mv/meta/argument_specs.yml +++ b/roles/configure_meraki_mv/meta/argument_specs.yml @@ -14,21 +14,25 @@ argument_specs: required: true description: Meraki API Auth Key meraki_mv_configuration: - type: list - elements: dict + type: dict required: true options: - organization: - type: str - required: true - description: Meraki Organization network: - type: str + type: dict required: true - description: Meraki Network + description: Network Wide Settings for MX + options: + organization: + type: str + required: true + description: Meraki Organization + name: + type: str + required: true + description: Meraki Network Name camera_profiles: type: dict - required: false + required: true description: Camera Profile Configuration options: wireless: @@ -48,36 +52,46 @@ argument_specs: choices: - present - absent - auth_mode: - type: str - required: false - description: SSID Auth Mode - choices: - - psk - - 8021x-radius - encryption_mode: - type: str - required: false - description: Encryption Mode - choices: - - wpa - - wpa-eap ssid: - type: str - required: false - description: SSID - psk: - type: str - required: false - description: Wireless PSK - username: - type: str + type: dict required: false - description: Username when using 8021x-radius - password: - type: str + description: SSID configuration + options: + name: + type: str + required: false + description: SSID Name + authMode: + type: str + required: false + description: SSID Auth Mode + choices: + - psk + - 8021x-radius + encryptionMode: + type: str + required: false + description: Encryption Mode + choices: + - wpa + - wpa-eap + psk: + type: str + required: false + description: Wireless PSK + identity: + type: dict required: false - description: Password when using 8021x-radius + description: Identity Configuration + options: + username: + type: str + required: false + description: Username when using 8021x-radius + password: + type: str + required: false + description: Password when using 8021x-radius quality_and_retention: type: list elements: dict @@ -95,11 +109,11 @@ argument_specs: choices: - present - absent - cloud_archive: + cloudArchiveEnabled: type: bool required: false description: Enable Cloud Archive - max_retention_days: + maxRetentionDays: type: int required: false description: Maximum Cloud Retention Days - Do not set a value to keep until storage is full @@ -118,30 +132,30 @@ argument_specs: - 30 - 60 - 90 - motion_based_retention: + motionBasedRetentionEnabled: type: bool required: false description: Delete footage older than 3 days in which no motion was detected. Does not apply to MV2. - motion_detector_version: + motionDetectorVersion: type: int required: false - description: Motion Detector Version + description: Motion Detector Version - Defaults to v2 choices: - 1 - 2 - restricted_bandwidth_mode: + restrictedBandwidthModeEnabled: type: bool required: false description: Disable features that require additional bandwidth. Does not apply to MV2. - audio_recording: + audioRecordingEnabled: type: bool required: false description: Enable Audio Recording - schedule_name: - type: bool + scheduleId: + type: str required: false - description: Camera Recording Schedule Name - video_settings: + description: Camera Recording Schedule ID + videoSettings: type: dict required: false description: Camera Specific Video Settings @@ -427,27 +441,54 @@ argument_specs: choices: - present - absent - quality_and_retention: + camera_profiles: type: dict required: false - description: Quality and Retention Settings + description: Camera Profile Assignment options: - profile_name: - type: str + wireless: + type: dict + required: false + description: Wireless Profiles + options: + primary: + type: str + required: false + description: Primary Wireless Profile Name + secondary: + type: str + required: false + description: Secondary Wireless Profile Name + backup: + type: str + required: false + description: Backup Wireless Profile Name + quality_and_retention: + type: dict required: false - description: Camera Retention Profile Name - motion_detector_version: + description: Quality and Retention Profile + options: + name: + type: str + required: false + description: Quality and Retention Profile Name + quality_and_retention_settings: + type: dict + required: false + description: Manual Quality and Retention Settings - Use when not binding to a profile + options: + motionDetectorVersion: type: int required: false - description: Motion Detector Version + description: Motion Detector Version - Defaults to v2 choices: - 1 - 2 - audio_recording: + audioRecordingEnabled: type: bool required: false description: Enable Audio Recording - video_resolution: + resolution: type: str required: false description: Video Resolution @@ -460,7 +501,7 @@ argument_specs: - 2880x2880 - 2688x1512 - 3840x2160 - video_quality: + quality: type: str required: false description: Video Quality @@ -468,45 +509,33 @@ argument_specs: - standard - enhanced - high - motion_based_retention: + motionBasedRetentionEnabled: type: bool required: false description: Delete footage older than 3 days in which no motion was detected. Does not apply to MV2. - restricted_bandwidth_mode: + restrictedBandwidthMode: type: bool required: false description: Disable features that require additional bandwidth. Does not apply to MV2. - wireless: - type: dict - required: false - description: Wireless Profiles - options: - profile_1: - type: str - required: false - description: Primary Wireless Profile Name - profile_2: - type: str - required: false - description: Secondary Wireless Profile Name - backup_profile: - type: str - required: false - description: Backup Wireless Profile Name sense: type: dict required: false description: Enable Camera Sense options: - enabled: + senseEnabled: type: bool required: false description: Enable Meraki Sense - audio_detection: - type: bool - required: false - description: Audio Detection Enabled - mqtt_broker_name: + mqttBrokerName: type: str required: false description: MQTT Broker Name + audioDetection: + type: dict + required: false + description: Audio Detection Settings + options: + enabled: + type: bool + required: false + description: Audio Detection Enabled diff --git a/roles/configure_meraki_mv/meta/main.yml b/roles/configure_meraki_mv/meta/main.yml index 1681892..d7ae72c 100644 --- a/roles/configure_meraki_mv/meta/main.yml +++ b/roles/configure_meraki_mv/meta/main.yml @@ -4,7 +4,7 @@ galaxy_info: description: Configure Meraki MV Security Cameras company: World Wide Technology license: GPL-3.0-or-later - min_ansible_version: ">=2.11.0" + min_ansible_version: ">=2.15.0" galaxy_tags: - networking - infrastructure diff --git a/roles/configure_meraki_mv/tasks/configure_camera_settings.yml b/roles/configure_meraki_mv/tasks/configure_camera_settings.yml index cf3454d..804a262 100644 --- a/roles/configure_meraki_mv/tasks/configure_camera_settings.yml +++ b/roles/configure_meraki_mv/tasks/configure_camera_settings.yml @@ -1,166 +1,88 @@ --- -- name: Query Device Serial Number for Cameras - cisco.meraki.meraki_device: - auth_key: "{{ auth_key }}" - org_name: "{{ config.organization }}" - net_name: "{{ config.network }}" - hostname: "{{ camera.name }}" - state: query - register: device_results - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera - -- name: Add camera serial number information to dict +- name: Query Device Serial Number for {{ camera.name }} ansible.builtin.set_fact: - camera_data: >- - {{ camera_data | default({}) | combine( - { - result.data[0].name: { - "serial": result.data[0].serial, - } - } - ) }} - loop: "{{ device_results.results }}" - loop_control: - loop_var: result - when: result.data is defined + device_serial: "{{ lookup('wwt.meraki.fetch', + 'network_devices', + org_name=meraki_mv_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mv_configuration.network.name, + device_name=camera.name) }}" -- name: Query Quality and Retention Profile Names - block: - - name: Query Quality and Retention Profile Names - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/qualityRetentionProfiles" - method: GET - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - until: query_profile_result.status != 429 - delay: 5 - retries: 3 - register: query_profile_result - when: camera.quality_and_retention.profile_name is defined and camera.state == "present" - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ query_profile_result }}" +- name: Query for existing Camera Quality and Retention Profiles + cisco.meraki.networks_camera_quality_retention_profiles_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + register: profile_result + when: meraki_mv_configuration.camera_profiles.quality_and_retention is defined -- name: Add camera quality profile ID to dict +- name: Add discovered profiles to dict ansible.builtin.set_fact: - profile_data: >- - {{ profile_data | default({}) | combine( + quality_profile_ids: >- + {{ quality_profile_ids | default({}) | combine( { - result.json[0].name: { - "id": result.json[0].id, + result.name: { + "id": result.id, } } ) }} - loop: "{{ query_profile_result.results }}" + loop: "{{ profile_result.meraki_response }}" loop_control: loop_var: result - when: result.json is defined + when: profile_result is defined -- name: Configure Camera Quality and Retention Settings - block: - - name: Configure Camera Quality and Retention Settings - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/devices/{{ camera_data[camera.name]['serial'] }}/camera/qualityAndRetention" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/camera_quality_settings.j2') }}" - changed_when: update_profile_result.status == 200 - until: update_profile_result.status != 429 - delay: 5 - retries: 3 - register: update_profile_result - when: camera_data[camera.name] is defined and camera.state == "present" - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ update_profile_result.results[0].json.errors }}" +- name: Configure Camera Quality and Retention Settings for {{ camera.name }} + cisco.meraki.devices_camera_quality_and_retention: + meraki_api_key: "{{ auth_key }}" + state: "{{ camera.state }}" + serial: "{{ device_serial }}" + profileId: "{{ quality_profile_ids[camera.camera_profiles.quality_and_retention.name].id | default(omit) }}" + audioRecordingEnabled: "{{ camera.quality_and_retention_settings.audioRecordingEnabled | default(omit) }}" + motionBasedRetentionEnabled: "{{ camera.quality_and_retention_settings.motionBasedRetentionEnabled | default(omit) }}" + motionDetectorVersion: "{{ camera.quality_and_retention_settings.motionDetectorVersion | default(omit) }}" + restrictedBandwidthModeEnabled: "{{ camera.quality_and_retention_settings.restrictedBandwidthModeEnabled | default(omit) }}" + quality: "{{ camera.quality_and_retention_settings.quality | default(omit) }}" + resolution: "{{ camera.quality_and_retention_settings.resolution | default(omit) }}" + when: (camera.camera_profiles.quality_and_retention is defined) or (camera.quality_and_retention_settings is defined) -- name: Query Network Camera Wireless Profiles - block: - - name: Query Network Camera Wireless Profiles on {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/wirelessProfiles" - method: GET - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - until: query_wireless_profiles_result.status != 429 - delay: 5 - retries: 3 - register: query_wireless_profiles_result - when: camera.wireless is defined and camera.state == "present" - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ query_wireless_profiles_result }}" +- name: Query for existing Camera Wireless Profiles + cisco.meraki.networks_camera_wireless_profiles_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + register: profile_result + when: meraki_mv_configuration.camera_profiles.wireless is defined -- name: Add Wireless Profile ID to dict +- name: Add discovered profiles to dict ansible.builtin.set_fact: - wireless_profile_data: >- - {{ wireless_profile_data | default({}) | combine( + wireless_profile_ids: >- + {{ wireless_profile_ids | default({}) | combine( { result.name: { "id": result.id, } } ) }} - loop: "{{ query_wireless_profiles_result.results[0].json }}" + loop: "{{ profile_result.meraki_response }}" loop_control: loop_var: result - when: query_wireless_profiles_result.results[0].json is defined + when: profile_result is defined -- name: Configure Camera Wireless Profiles - block: - - name: Configure Camera Wireless Profiles - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/devices/{{ camera_data[camera.name]['serial'] }}/camera/wirelessProfiles" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/assign_wireless_profile.j2') }}" - changed_when: update_wireless_profile_result.status == 200 - until: update_wireless_profile_result.status != 429 - delay: 5 - retries: 3 - register: update_wireless_profile_result - when: camera.wireless is defined and camera.state == "present" - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ update_wireless_profile_result.results[0].json.error }}" +- name: Configure Camera Wireless Profiles for {{ camera.name }} + cisco.meraki.devices_camera_wireless_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ camera.state }}" + serial: "{{ device_serial }}" + ids: + primary: "{{ camera.camera_profiles.wireless['primary'] is defined + | ternary(wireless_profile_ids[camera.camera_profiles.wireless.get('primary')].id, omit) }}" + secondary: "{{ camera.camera_profiles.wireless['secondary'] is defined + | ternary(wireless_profile_ids[camera.camera_profiles.wireless.get('secondary')].id, omit) }}" + backup: "{{ camera.camera_profiles.wireless['backup'] is defined + | ternary(wireless_profile_ids[camera.camera_profiles.wireless.get('backup')].id, omit) }}" + when: camera.camera_profiles.wireless is defined -- name: Query MQTT Broker Names +- name: Query for existing MQTT brokers block: - - name: Query MQTT Broker Names + - name: Query for existing MQTT brokers on Network {{ meraki_mv_configuration.network.name }} ansible.builtin.uri: url: "{{ dashboard_base_url }}/networks/{{ network_id }}/mqttBrokers" method: GET @@ -169,57 +91,40 @@ Content-Type: application/json Accept: application/json X-Cisco-Meraki-API-Key: "{{ auth_key }}" - until: query_broker_result.status != 429 + until: broker_result.status != 429 delay: 5 retries: 3 - register: query_broker_result - when: camera.sense is defined and camera.sense.mqtt_broker_name is defined and camera.state == "present" - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera + register: broker_result + when: meraki_mt_configuration is defined rescue: - name: Something went wrong... ansible.builtin.debug: - msg: "ERROR: {{ query_broker_result }}" + msg: "ERROR: {{ broker_result }}" -- name: Add MQTT Broker ID to dict +- name: Add discovered brokers to dict ansible.builtin.set_fact: - broker_data: >- - {{ broker_data | default({}) | combine( + mqtt_broker_ids: >- + {{ mqtt_broker_ids | default({}) | combine( { - result.json[0].name: { - "id": result.json[0].id, + result.name: { + "id": result.id, } } ) }} - loop: "{{ query_broker_result.results }}" + loop: "{{ broker_result.json }}" loop_control: loop_var: result - when: result.json is defined + when: broker_result.status == 200 -- name: Configure Camera Sense Settings - block: - - name: Configure Camera Sense Settings - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/devices/{{ camera_data[camera.name]['serial'] }}/camera/sense" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/camera_sense.j2') }}" - changed_when: update_sense_result.status == 200 - until: update_sense_result.status != 429 - delay: 5 - retries: 3 - register: update_sense_result - when: camera.sense is defined and camera.sense.enabled and camera.state == "present" - loop: "{{ config.cameras }}" - loop_control: - loop_var: camera - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ update_sense_result.results[0].json.errors }}" +- name: Configure Camera Sense Settings for {{ camera.name }} + cisco.meraki.devices_camera_sense: + meraki_api_key: "{{ auth_key }}" + serial: "{{ device_serial }}" + state: "{{ camera.state }}" + senseEnabled: "{{ camera.sense.senseEnabled | default(omit) }}" + mqttBrokerId: "{{ mqtt_broker_ids[camera.sense.mqttBrokerName].id | default(omit) }}" + audioDetection: "{{ ((camera.sense.audioDetection is defined) + and (camera.sense.audioDetection.enabled) + and (camera.sense.senseEnabled)) + | ternary(camera.sense.audioDetection.enabled, omit) }}" + when: camera.sense.senseEnabled is defined and camera.state == "present" diff --git a/roles/configure_meraki_mv/tasks/configure_quality_profiles.yml b/roles/configure_meraki_mv/tasks/configure_quality_profiles.yml index 5af1d76..7a625cc 100644 --- a/roles/configure_meraki_mv/tasks/configure_quality_profiles.yml +++ b/roles/configure_meraki_mv/tasks/configure_quality_profiles.yml @@ -1,24 +1,10 @@ --- -- name: Query for existing Camera Quality Profiles - block: - - name: Query for existing Camera Quality Profiles on Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/qualityRetentionProfiles" - method: GET - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - until: profile_result.status != 429 - delay: 5 - retries: 3 - register: profile_result - when: config.camera_profiles is defined - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ profile_result }}" +- name: Query for existing Camera Quality and Retention Profiles + cisco.meraki.networks_camera_quality_retention_profiles_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + register: profile_result + when: meraki_mv_configuration.camera_profiles.quality_and_retention is defined - name: Add discovered profiles to dict ansible.builtin.set_fact: @@ -26,90 +12,61 @@ {{ quality_profile_ids | default({}) | combine( { result.name: { - "profile_id": result.id, + "id": result.id, } } ) }} - loop: "{{ profile_result.json }}" + loop: "{{ profile_result.meraki_response }}" loop_control: loop_var: result - when: profile_result.status == 200 + when: profile_result is defined -- name: Update Camera Quality Profiles - block: - - name: Update Camera Quality Profiles for Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/qualityRetentionProfiles/{{ quality_profile_ids[profile.name]['profile_id'] }}" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/camera_quality_profile.j2') }}" - changed_when: update_profile_result.status == 200 - until: update_profile_result.status != 429 - delay: 5 - retries: 3 - register: update_profile_result - when: quality_profile_ids[profile.name] is defined and profile.state == "present" - loop: "{{ config.camera_profiles.quality_and_retention }}" - loop_control: - loop_var: profile - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ update_profile_result }}" +- name: Create Camera Quality and Retention Profiles for Network {{ meraki_mv_configuration.network.name }} + cisco.meraki.networks_camera_quality_retention_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ profile.state }}" + name: "{{ profile.name }}" + networkId: "{{ network_id }}" + audioRecordingEnabled: "{{ profile.audioRecordingEnabled | default(omit) }}" + cloudArchiveEnabled: "{{ profile.cloudArchiveEnabled | default(omit) }}" + maxRetentionDays: "{{ profile.maxRetentionDays | default(omit) }}" + motionBasedRetentionEnabled: "{{ profile.motionBasedRetentionEnabled | default(omit) }}" + motionDetectorVersion: "{{ profile.motionDetectorVersion | default(omit) }}" + restrictedBandwidthModeEnabled: "{{ profile.restrictedBandwidthModeEnabled | default(omit) }}" + scheduleId: "{{ profile.scheduleId | default(omit) }}" + videoSettings: "{{ profile.videoSettings | default(omit) }}" + loop: "{{ meraki_mv_configuration.camera_profiles.quality_and_retention }}" + loop_control: + loop_var: profile + when: quality_profile_ids[profile.name] is not defined and profile.state == "present" -- name: Create Camera Quality Profiles - block: - - name: Create Camera Quality Profiles for Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/qualityRetentionProfiles" - method: POST - status_code: 201 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/camera_quality_profile.j2') }}" - changed_when: create_profile_result.status == 201 - until: create_profile_result.status != 429 - delay: 5 - retries: 3 - register: create_profile_result - when: quality_profile_ids[profile.name] is undefined and profile.state == "present" - loop: "{{ config.camera_profiles.quality_and_retention }}" - loop_control: - loop_var: profile - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ create_profile_result }}" +- name: Update Camera Quality and Retention Profiles for Network {{ meraki_mv_configuration.network.name }} + cisco.meraki.networks_camera_quality_retention_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ profile.state }}" + name: "{{ profile.name }}" + networkId: "{{ network_id }}" + qualityRetentionProfileId: "{{ quality_profile_ids[profile.name].id }}" + audioRecordingEnabled: "{{ profile.audioRecordingEnabled | default(omit) }}" + cloudArchiveEnabled: "{{ profile.cloudArchiveEnabled | default(omit) }}" + maxRetentionDays: "{{ profile.maxRetentionDays | default(omit) }}" + motionBasedRetentionEnabled: "{{ profile.motionBasedRetentionEnabled | default(omit) }}" + motionDetectorVersion: "{{ profile.motionDetectorVersion | default(omit) }}" + restrictedBandwidthModeEnabled: "{{ profile.restrictedBandwidthModeEnabled | default(omit) }}" + scheduleId: "{{ profile.scheduleId | default(omit) }}" + videoSettings: "{{ profile.videoSettings | default(omit) }}" + loop: "{{ meraki_mv_configuration.camera_profiles.quality_and_retention }}" + loop_control: + loop_var: profile + when: quality_profile_ids[profile.name] is defined and profile.state == "present" -- name: Delete Camera Wireless Profiles - block: - - name: Delete Camera Wireless Profile on Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/qualityRetentionProfiles/{{ quality_profile_ids[profile.name]['profile_id'] }}" - method: DELETE - status_code: 204 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - changed_when: delete_profile_result.status == 204 - until: delete_profile_result.status != 429 - delay: 5 - retries: 3 - register: delete_profile_result - when: quality_profile_ids[profile.name] is defined and profile.state == "absent" - loop: "{{ config.camera_profiles.quality_and_retention }}" - loop_control: - loop_var: profile - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ delete_profile_result }}" +- name: Update Camera Quality and Retention Profiles for Network {{ meraki_mv_configuration.network.name }} + cisco.meraki.networks_camera_quality_retention_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ profile.state }}" + networkId: "{{ network_id }}" + qualityRetentionProfileId: "{{ quality_profile_ids[profile.name].id }}" + loop: "{{ meraki_mv_configuration.camera_profiles.quality_and_retention }}" + loop_control: + loop_var: profile + when: quality_profile_ids[profile.name] is defined and profile.state == "absent" diff --git a/roles/configure_meraki_mv/tasks/configure_wireless_profiles.yml b/roles/configure_meraki_mv/tasks/configure_wireless_profiles.yml index b73f967..15e19af 100644 --- a/roles/configure_meraki_mv/tasks/configure_wireless_profiles.yml +++ b/roles/configure_meraki_mv/tasks/configure_wireless_profiles.yml @@ -1,24 +1,10 @@ --- - name: Query for existing Camera Wireless Profiles - block: - - name: Query for existing Camera Wireless Profiles on Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/wirelessProfiles" - method: GET - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - until: profile_result.status != 429 - delay: 5 - retries: 3 - register: profile_result - when: config.camera_profiles is defined - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ profile_result }}" + cisco.meraki.networks_camera_wireless_profiles_info: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + register: profile_result + when: meraki_mv_configuration.camera_profiles.wireless is defined - name: Add discovered profiles to dict ansible.builtin.set_fact: @@ -26,90 +12,49 @@ {{ wireless_profile_ids | default({}) | combine( { result.name: { - "profile_id": result.id, + "id": result.id, } } ) }} - loop: "{{ profile_result.json }}" + loop: "{{ profile_result.meraki_response }}" loop_control: loop_var: result - when: profile_result.status == 200 + when: profile_result is defined -- name: Update Camera Wireless Profiles - block: - - name: Update Camera Wireless Profiles for Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/wirelessProfiles/{{ wireless_profile_ids[profile.name]['profile_id'] }}" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/camera_wireless_profile.j2') }}" - changed_when: update_profile_result.status == 200 - until: update_profile_result.status != 429 - delay: 5 - retries: 3 - register: update_profile_result - when: wireless_profile_ids[profile.name] is defined and profile.state == "present" - loop: "{{ config.camera_profiles.wireless }}" - loop_control: - loop_var: profile - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ update_profile_result }}" +- name: Create Camera Wireless Profiles for Network {{ meraki_mv_configuration.network.name }} + cisco.meraki.networks_camera_wireless_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ profile.state }}" + name: "{{ profile.name }}" + networkId: "{{ network_id }}" + ssid: "{{ profile.ssid }}" + identity: "{{ profile.identity | default(omit) }}" + loop: "{{ meraki_mv_configuration.camera_profiles.wireless }}" + loop_control: + loop_var: profile + when: wireless_profile_ids[profile.name] is not defined and profile.state == "present" -- name: Create Camera Wireless Profiles - block: - - name: Create Camera Wireless Profiles for Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/wirelessProfiles" - method: POST - status_code: 201 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: "{{ lookup('template', 'templates/camera_wireless_profile.j2') }}" - changed_when: create_profile_result.status == 201 - until: create_profile_result.status != 429 - delay: 5 - retries: 3 - register: create_profile_result - when: wireless_profile_ids[profile.name] is undefined and profile.state == "present" - loop: "{{ config.camera_profiles.wireless }}" - loop_control: - loop_var: profile - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ create_profile_result }}" +- name: Update Camera Wireless Profiles for Network {{ meraki_mv_configuration.network.name }} + cisco.meraki.networks_camera_wireless_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ profile.state }}" + name: "{{ profile.name }}" + networkId: "{{ network_id }}" + ssid: "{{ profile.ssid }}" + identity: "{{ profile.identity | default(omit) }}" + wirelessProfileId: "{{ wireless_profile_ids[profile.name].id }}" + loop: "{{ meraki_mv_configuration.camera_profiles.wireless }}" + loop_control: + loop_var: profile + when: wireless_profile_ids[profile.name] is defined and profile.state == "present" -- name: Delete Camera Wireless Profiles - block: - - name: Delete Camera Wireless Profile on Network {{ config.network }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/camera/wirelessProfiles/{{ wireless_profile_ids[profile.name]['profile_id'] }}" - method: DELETE - status_code: 204 - headers: - Content-Type: application/json - Accept: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - changed_when: delete_profile_result.status == 204 - until: delete_profile_result.status != 429 - delay: 5 - retries: 3 - register: delete_profile_result - when: wireless_profile_ids[profile.name] is defined and profile.state == "absent" - loop: "{{ config.camera_profiles.wireless }}" - loop_control: - loop_var: profile - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ delete_profile_result }}" +- name: Delete Camera Wireless Profiles for Network {{ meraki_mv_configuration.network.name }} + cisco.meraki.networks_camera_wireless_profiles: + meraki_api_key: "{{ auth_key }}" + state: "{{ profile.state }}" + networkId: "{{ network_id }}" + wirelessProfileId: "{{ wireless_profile_ids[profile.name].id }}" + loop: "{{ meraki_mv_configuration.camera_profiles.wireless }}" + loop_control: + loop_var: profile + when: wireless_profile_ids[profile.name] is defined and profile.state == "absent" diff --git a/roles/configure_meraki_mv/tasks/main.yml b/roles/configure_meraki_mv/tasks/main.yml index 7f2a70e..f85c065 100644 --- a/roles/configure_meraki_mv/tasks/main.yml +++ b/roles/configure_meraki_mv/tasks/main.yml @@ -8,61 +8,27 @@ # Written by: Nick Thompson (github/@nsthompson) # -- name: Get Meraki Network IDs - cisco.meraki.meraki_network: - auth_key: "{{ auth_key }}" - org_name: "{{ config.organization }}" - net_name: "{{ config.network }}" - state: query - loop: "{{ meraki_mv_configuration }}" - loop_control: - loop_var: config - register: network_results +- name: Look Up Meraki MV Network ID + ansible.builtin.set_fact: + network_id: "{{ lookup('wwt.meraki.fetch', + 'network_id', + org_name=meraki_mv_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mv_configuration.network.name) }}" - name: Failure - Network DOES NOT exist ansible.builtin.fail: msg: Meraki Network is not provisioned - when: network_results.results[0].data.id is not defined - -- name: Build dict of Network Name to IDs - ansible.builtin.set_fact: - network_ids: >- - {{ network_ids | default({}) | combine( - { - result.data.name: { - "network_id": result.data.id, - } - } - ) }} - loop: "{{ network_results.results }}" - loop_control: - loop_var: result + when: network_id is not defined - name: Configure Camera Wireless Profiles ansible.builtin.include_tasks: configure_wireless_profiles.yml - vars: - network_id: "{{ network_ids[config.network]['network_id'] }}" - loop: "{{ meraki_mv_configuration }}" - loop_control: - loop_var: config -# -# -# QUALITY PROFILES CURRENTLY DO NOT WORK - OPENED TICKET WITH MERAKI -# -# -# - name: Configure Camera Quality and Retention Profiles -# ansible.builtin.include_tasks: configure_quality_profiles.yml -# vars: -# network_id: "{{ network_ids[config.network]['network_id'] }}" -# loop: "{{ meraki_mv_configuration }}" -# loop_control: -# loop_var: config +- name: Configure Camera Quality and Retention Profiles + ansible.builtin.include_tasks: configure_quality_profiles.yml - name: Configure Camera Settings ansible.builtin.include_tasks: configure_camera_settings.yml - vars: - network_id: "{{ network_ids[config.network]['network_id'] }}" - loop: "{{ meraki_mv_configuration }}" + loop: "{{ meraki_mv_configuration.cameras }}" loop_control: - loop_var: config + loop_var: camera diff --git a/roles/configure_meraki_mv/templates/assign_wireless_profile.j2 b/roles/configure_meraki_mv/templates/assign_wireless_profile.j2 deleted file mode 100644 index a540c4b..0000000 --- a/roles/configure_meraki_mv/templates/assign_wireless_profile.j2 +++ /dev/null @@ -1,22 +0,0 @@ -{ - "ids": { - {% if wireless_profile_data[camera.wireless.profile_1].id is defined %} - {% set camera_profile_1 = wireless_profile_data[camera.wireless.profile_1].id %} - {% endif %} - {% if camera_profile_1 is defined %} - "primary": "{{ camera_profile_1 }}", - {% endif %} - {% if wireless_profile_data[camera.wireless.profile_2].id is defined %} - {% set camera_profile_2 = wireless_profile_data[camera.wireless.profile_2].id %} - {% endif %} - {% if camera_profile_2 is defined %} - "secondary": "{{ camera_profile_2 }}", - {% endif %} - {% if camera.wireless.backup_profile is defined and wireless_profile_data[camera.wireless.backup_profile].id is defined %} - {% set camera_profile_backup = wireless_profile_data[camera.wireless.backup_profile].id %} - {% endif %} - {% if camera_profile_backup is defined %} - "backup": "{{ camera_profile_backup }}" - {% endif %} - } -} \ No newline at end of file diff --git a/roles/configure_meraki_mv/templates/camera_quality_profile.j2 b/roles/configure_meraki_mv/templates/camera_quality_profile.j2 deleted file mode 100644 index 6b88c7d..0000000 --- a/roles/configure_meraki_mv/templates/camera_quality_profile.j2 +++ /dev/null @@ -1,110 +0,0 @@ -{ - "name": "{{ profile.name }}", - {% if profile.cloud_archive is defined %} - "cloudArchiveEnabled": {{ profile.cloud_archive }}, - {% endif %} - {% if profile.max_retention_days is defined %} - "maxRetentionDays": {{ profile.max_retention_days }}, - {% else %} - "maxRetentionDays": null, - {% endif %} - {% if profile.motion_based_retention is defined %} - "motionBasedRetentionEnabled": "{{ profile.motion_based_retention }}", - {% endif %} - {% if profile.motion_detector_version is defined %} - "motionDetectorVersion": {{ profile.motion_detector_version }}, - {% endif %} - {% if profile.restricted_bandwidth_mode is defined %} - "restrictedBandwidthModeEnabled": {{ profile.restricted_bandwidth_mode }}, - {% endif %} - {% if profile.audio_recording is defined %} - "audioRecordingEnabled": {{ profile.audio_recording }}, - {% endif %} - {% if schedule_id is defined %} - "scheduleId": "{{ schedule_id }}", - {% else %} - "scheduleId": null, - {% endif %} - {% if profile.video_settings is defined %} - "videoSettings": { - {% if profile.video_settings.MV12_MV22_MV72 is defined %} - "MV12/MV22/MV72": { - "quality": "{{ profile.video_settings.MV12_MV22_MV72.quality }}", - "resolution": "{{ profile.video_settings.MV12_MV22_MV72.resolution }}", - }, - {% endif %} - {% if profile.video_settings.MV12WE is defined %} - "MV12WE": { - "quality": "{{ profile.video_settings.MV12WE.quality }}", - "resolution": "{{ profile.video_settings.MV12WE.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV13 is defined %} - "MV13": { - "quality": "{{ profile.video_settings.MV13.quality }}", - "resolution": "{{ profile.video_settings.MV13.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV21_MV71 is defined %} - "MV21/MV71": { - "quality": "{{ profile.video_settings.MV21_MV71.quality }}", - "resolution": "{{ profile.video_settings.MV21_MV71.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV22X_MV72X is defined %} - "MV22X/MV72X": { - "quality": "{{ profile.video_settings.MV22X_MV72X.quality }}", - "resolution": "{{ profile.video_settings.MV22X_MV72X.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV32 is defined %} - "MV32": { - "quality": "{{ profile.video_settings.MV32.quality }}", - "resolution": "{{ profile.video_settings.MV32.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV33 is defined %} - "MV33": { - "quality": "{{ profile.video_settings.MV33.quality }}", - "resolution": "{{ profile.video_settings.MV33.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV52 is defined %} - "MV52": { - "quality": "{{ profile.video_settings.MV52.quality }}", - "resolution": "{{ profile.video_settings.MV52.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV63 is defined %} - "MV63": { - "quality": "{{ profile.video_settings.MV63.quality }}", - "resolution": "{{ profile.video_settings.MV63.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV63X is defined %} - "MV63X": { - "quality": "{{ profile.video_settings.MV63X.quality }}", - "resolution": "{{ profile.video_settings.MV63X.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV93 is defined %} - "MV93": { - "quality": "{{ profile.video_settings.MV93.quality }}", - "resolution": "{{ profile.video_settings.MV93.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV93X is defined %} - "MV93X": { - "quality": "{{ profile.video_settings.MV93X.quality }}", - "resolution": "{{ profile.video_settings.MV93X.resolution }}" - }, - {% endif %} - {% if profile.video_settings.MV2 is defined %} - "MV2": { - "quality": "{{ profile.video_settings.MV2.quality }}", - "resolution": "{{ profile.video_settings.MV2.resolution }}" - } - {% endif %} - } - {% endif %} -} \ No newline at end of file diff --git a/roles/configure_meraki_mv/templates/camera_quality_settings.j2 b/roles/configure_meraki_mv/templates/camera_quality_settings.j2 deleted file mode 100644 index b7aa07c..0000000 --- a/roles/configure_meraki_mv/templates/camera_quality_settings.j2 +++ /dev/null @@ -1,26 +0,0 @@ -{ - {% if profile_data[camera.quality_and_retention.profile_name].id is defined %} - {% set quality_profile_id = profile_data[camera.quality_and_retention.profile_name].id %} - {% endif %} - {% if quality_profile_id is defined %} - "profileId": "{{ quality_profile_id }}", - {% endif %} - {% if camera.quality_and_retention.motion_detector_version is defined and quality_profile_id is not defined %} - "motionDetectorVersion": "{{ camera.quality_and_retention.motion_detector_version }}", - {% endif %} - {% if camera.quality_and_retention.video_quality is defined and quality_profile_id is not defined %} - "quality": "{{ camera.quality_and_retention.video_quality }}", - {% endif %} - {% if camera.quality_and_retention.video_resolution is defined and quality_profile_id is not defined %} - "resolution": "{{ camera.quality_and_retention.video_resolution }}", - {% endif %} - {% if camera.quality_and_retention.audio_recording is defined and quality_profile_id is not defined %} - "audioRecordingEnabled": {{ camera.quality_and_retention.audio_recording }}, - {% endif %} - {% if camera.quality_and_retention.motion_based_retention is defined and quality_profile_id is not defined %} - "motionBasedRetentionEnabled": {{ camera.quality_and_retention.motion_based_retention }}, - {% endif %} - {% if camera.quality_and_retention.restricted_bandwidth_mode is defined and quality_profile_id is not defined %} - "restrictedBandwidthModeEnabled": {{ camera.quality_and_retention.restricted_bandwidth_mode }} - {% endif %} -} \ No newline at end of file diff --git a/roles/configure_meraki_mv/templates/camera_sense.j2 b/roles/configure_meraki_mv/templates/camera_sense.j2 deleted file mode 100644 index b6dfd3b..0000000 --- a/roles/configure_meraki_mv/templates/camera_sense.j2 +++ /dev/null @@ -1,16 +0,0 @@ -{ - {% if camera.sense.enabled is defined %} - "senseEnabled": {{ camera.sense.enabled }}, - {% endif %} - {% if camera.sense.audio_detecton is defined %} - "audioDetection: { - "enabled": {{ camera.sense.audio_detection }} - }, - {% endif %} - {% if broker_data[camera.sense.mqtt_broker_name].id is defined %} - {% set mqtt_broker_id = broker_data[camera.sense.mqtt_broker_name].id %} - {% endif %} - {% if mqtt_broker_id is defined %} - "mqttBrokerId": "{{ mqtt_broker_id }}" - {% endif %} -} \ No newline at end of file diff --git a/roles/configure_meraki_mv/templates/camera_wireless_profile.j2 b/roles/configure_meraki_mv/templates/camera_wireless_profile.j2 deleted file mode 100644 index 986148d..0000000 --- a/roles/configure_meraki_mv/templates/camera_wireless_profile.j2 +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "{{ profile.name }}", - "ssid": { - "name": "{{ profile.ssid }}", - "authMode": "{{ profile.auth_mode }}", - "encryptionMode": "{{ profile.encryption_mode }}"{% if profile.auth_mode == "psk" %}, - "psk": "{{ profile.psk }}" - {% endif %} - }{% if profile.auth_mode == "8021x-radius" %}, - "identity": { - "username": "{{ profile.username }}", - "password": "{{ profile.password }}" - } - {% endif %} -} \ No newline at end of file diff --git a/roles/configure_meraki_mx/meta/argument_specs.yml b/roles/configure_meraki_mx/meta/argument_specs.yml index 06c5bbd..5841808 100644 --- a/roles/configure_meraki_mx/meta/argument_specs.yml +++ b/roles/configure_meraki_mx/meta/argument_specs.yml @@ -17,6 +17,28 @@ argument_specs: type: dict required: true options: + network: + type: dict + required: true + description: Network Wide Settings for MX + options: + organization: + type: str + required: true + description: Meraki Organization + name: + type: str + required: true + description: Meraki Network Name + lan_settings: + type: dict + required: true + description: Network Wide LAN Settings for MX + options: + enable_vlans: + type: bool + required: true + description: Enable VLAN Mode appliances: type: list required: true @@ -27,14 +49,6 @@ argument_specs: type: str required: true description: Name of MX Appliance - organization: - type: str - required: true - description: Meraki Organization - network: - type: str - required: true - description: Meraki Network Name deployment_settings: type: dict required: true @@ -268,14 +282,6 @@ argument_specs: type: str required: false description: PPPoE Password - lan_settings: - type: dict - required: true - options: - enable_vlans: - type: bool - required: true - description: Enable VLAN Mode vlans: type: list required: true @@ -327,17 +333,18 @@ argument_specs: elements: dict options: mac: - type: str + type: dict required: false description: Client MAC Address - ip: - type: str - required: false - description: Client IP Address - name: - type: str - required: false - description: Client Name + options: + ip: + type: str + required: false + description: Client IP Address + name: + type: str + required: false + description: Client Name dns_nameservers: type: str required: false @@ -477,19 +484,19 @@ argument_specs: type: str required: false description: Rule Description - src_cidr: + srcCidr: type: str required: false description: Source CIDR Address or 'Any' - src_port: + srcPort: type: str required: false description: Source Port - dest_cidr: + destCidr: type: str required: false description: Destination CIDR Address or 'Any' - dest_port: + destPort: type: str required: false description: Destination Port @@ -509,6 +516,14 @@ argument_specs: choices: - allow - deny + syslogEnabled: + type: bool + required: false + description: Enable Syslog - only applicable if a syslog server has been configured + syslogDefaultRule: + type: bool + required: false + description: Log the special default rule (boolean value - enable only if you've configured a syslog server) l7_rules: type: list required: false @@ -537,7 +552,7 @@ argument_specs: type: str required: false description: FQDN of host to filter - ip_range: + ipRange: type: str required: false description: CIDR range of IP, can append port with ":" @@ -557,9 +572,9 @@ argument_specs: description: Rule Type choices: - application - - application_category - - blocked_countries + - applicationCategory + - blockedCountries - host - - ip_range + - ipRange - port - - allowed_countries + - allowedCountries diff --git a/roles/configure_meraki_mx/meta/main.yml b/roles/configure_meraki_mx/meta/main.yml index 04de37b..8ec6f72 100644 --- a/roles/configure_meraki_mx/meta/main.yml +++ b/roles/configure_meraki_mx/meta/main.yml @@ -4,7 +4,7 @@ galaxy_info: description: Configure Meraki MX Security Appliances company: World Wide Technology license: GPL-3.0-or-later - min_ansible_version: ">=2.11.0" + min_ansible_version: ">=2.15.0" galaxy_tags: - networking - infrastructure diff --git a/roles/configure_meraki_mx/tasks/configure_deployment.yml b/roles/configure_meraki_mx/tasks/configure_deployment.yml index a25cd96..354089e 100644 --- a/roles/configure_meraki_mx/tasks/configure_deployment.yml +++ b/roles/configure_meraki_mx/tasks/configure_deployment.yml @@ -1,27 +1,11 @@ --- - name: Configure Meraki MX Deployment Settings - block: - - name: Configure MX Deployment Settings for {{ appliance.name }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/appliance/settings" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: - clientTrackingMethod: "{{ appliance.deployment_settings.client_tracking }}" - deploymentMode: "{{ appliance.deployment_settings.deployment_mode }}" - dynamicDns: - prefix: "{{ appliance.deployment_settings.dynamic_dns.prefix }}" - enabled: "{{ appliance.deployment_settings.dynamic_dns.enabled }}" - changed_when: api_result.status == 200 - until: api_result.status != 429 - delay: 5 - retries: 3 - register: api_result - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ api_result }}" + cisco.meraki.networks_appliance_settings: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + state: present + clientTrackingMethod: "{{ appliance.deployment_settings.client_tracking }}" + deploymentMode: "{{ appliance.deployment_settings.deployment_mode }}" + dynamicDns: + prefix: "{{ appliance.deployment_settings.dynamic_dns.prefix }}" + enabled: "{{ appliance.deployment_settings.dynamic_dns.enabled }}" diff --git a/roles/configure_meraki_mx/tasks/configure_l3_firewall.yml b/roles/configure_meraki_mx/tasks/configure_l3_firewall.yml index 3c06e60..b30431c 100644 --- a/roles/configure_meraki_mx/tasks/configure_l3_firewall.yml +++ b/roles/configure_meraki_mx/tasks/configure_l3_firewall.yml @@ -1,8 +1,7 @@ --- - name: Configure Meraki MX L3 Firewall for {{ appliance.name }} - cisco.meraki.meraki_mx_l3_firewall: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" + cisco.meraki.networks_appliance_firewall_l3_firewall_rules: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" state: present rules: "{{ appliance.threat_protection.firewall.l3_rules }}" diff --git a/roles/configure_meraki_mx/tasks/configure_l7_firewall.yml b/roles/configure_meraki_mx/tasks/configure_l7_firewall.yml index 79ef0ed..0373298 100644 --- a/roles/configure_meraki_mx/tasks/configure_l7_firewall.yml +++ b/roles/configure_meraki_mx/tasks/configure_l7_firewall.yml @@ -1,8 +1,7 @@ --- - name: Configure Meraki MX L7 Firewall for {{ appliance.name }} - cisco.meraki.meraki_mx_l7_firewall: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" + cisco.meraki.networks_appliance_firewall_l7_firewall_rules: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" state: present rules: "{{ appliance.threat_protection.firewall.l7_rules }}" diff --git a/roles/configure_meraki_mx/tasks/configure_ports.yml b/roles/configure_meraki_mx/tasks/configure_ports.yml index 6b2e064..bd4aca2 100644 --- a/roles/configure_meraki_mx/tasks/configure_ports.yml +++ b/roles/configure_meraki_mx/tasks/configure_ports.yml @@ -1,16 +1,15 @@ --- - name: Configure Meraki MX Ports for {{ appliance.name }} - cisco.meraki.meraki_mx_l2_interface: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" - number: "{{ port.id }}" + cisco.meraki.networks_appliance_ports: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + portId: "{{ port.id }}" enabled: "{{ port.enabled }}" - drop_untagged_traffic: "{{ port.drop_untagged_traffic | default(omit) }}" - port_type: "{{ port.type | default(omit) }}" + dropUntaggedTraffic: "{{ port.drop_untagged_traffic | default(omit) }}" + type: "{{ port.type | default(omit) }}" vlan: "{{ port.vlan | default(omit) }}" - allowed_vlans: "{{ port.allowed_vlans | default(omit) }}" - access_policy: "{{ port.access_policy | default(omit) }}" + allowedVlans: "{{ port.allowed_vlans | default(omit) }}" + accessPolicy: "{{ port.access_policy | default(omit) }}" loop: "{{ appliance.ports }}" loop_control: loop_var: port diff --git a/roles/configure_meraki_mx/tasks/configure_threat_protection.yml b/roles/configure_meraki_mx/tasks/configure_threat_protection.yml index e3405fe..08011d6 100644 --- a/roles/configure_meraki_mx/tasks/configure_threat_protection.yml +++ b/roles/configure_meraki_mx/tasks/configure_threat_protection.yml @@ -1,35 +1,17 @@ --- - name: Configure Meraki MX Advanced Malware Protection Settings - block: - - name: Configure MX Advanced Malware Protection Settings for {{ appliance.name }} - ansible.builtin.uri: - url: "{{ dashboard_base_url }}/networks/{{ network_id }}/appliance/security/malware" - method: PUT - status_code: 200 - headers: - Content-Type: application/json - X-Cisco-Meraki-API-Key: "{{ auth_key }}" - body_format: json - body: - mode: "{{ appliance.threat_protection.malware.mode }}" - allowedUrls: "{{ appliance.threat_protection.malware.allowed_urls }}" - allowedFiles: "{{ appliance.threat_protection.malware.allowed_files | default(omit) }}" - changed_when: api_result.status == 200 - until: api_result.status != 429 - delay: 5 - retries: 3 - register: api_result - rescue: - - name: Something went wrong... - ansible.builtin.debug: - msg: "ERROR: {{ api_result }}" + cisco.meraki.networks_appliance_security_malware: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" + mode: "{{ appliance.threat_protection.malware.mode }}" + allowedUrls: "{{ appliance.threat_protection.malware.allowed_urls }}" + allowedFiles: "{{ appliance.threat_protection.malware.allowed_files | default(omit) }}" - name: Configure Meraki MX Intrusion Detection and Prevention Settings for {{ appliance.name }} - cisco.meraki.meraki_mx_intrusion_prevention: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" + cisco.meraki.networks_appliance_security_intrusion: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" state: present mode: "{{ appliance.threat_protection.intrusion.mode }}" - ids_rulesets: "{{ appliance.threat_protection.intrusion.rulesets }}" - protected_networks: "{{ appliance.threat_protection.intrusion.protected_networks | default(omit) }}" + protectedNetworks: "{{ appliance.threat_protection.intrusion.protected_networks | default(omit) }}" + idsRulesets: "{{ appliance.threat_protection.intrusion.rulesets }}" diff --git a/roles/configure_meraki_mx/tasks/configure_vlans.yml b/roles/configure_meraki_mx/tasks/configure_vlans.yml index 4e9cf70..9f114e3 100644 --- a/roles/configure_meraki_mx/tasks/configure_vlans.yml +++ b/roles/configure_meraki_mx/tasks/configure_vlans.yml @@ -1,17 +1,32 @@ --- -- name: Configure MX VLANs for {{ appliance.name }} - cisco.meraki.meraki_mx_vlan: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" +- name: Initial Configuration of MX VLANs for {{ appliance.name }} + cisco.meraki.networks_appliance_vlans: + meraki_api_key: "{{ auth_key }}" state: "{{ vlan.state }}" - vlan_id: "{{ vlan.id }}" + networkId: "{{ network_id }}" + id: "{{ vlan.id }}" name: "{{ vlan.name | default(omit) }}" subnet: "{{ vlan.subnet | default(omit) }}" - appliance_ip: "{{ vlan.appliance_ip | default(omit) }}" - reserved_ip_range: "{{ vlan.reserved_ip_range | default(omit) }}" - fixed_ip_assignments: "{{ vlan.fixed_ip_assignments | default(omit) }}" - dns_nameservers: "{{ vlan.dns_nameservers | default(omit) }}" + applianceIp: "{{ vlan.appliance_ip | default(omit) }}" loop: "{{ appliance.vlans }}" loop_control: loop_var: vlan + +- name: Second Pass Configuration of MX VLANs for {{ appliance.name }} + cisco.meraki.networks_appliance_vlans: + meraki_api_key: "{{ auth_key }}" + state: "{{ vlan.state }}" + networkId: "{{ network_id }}" + id: "{{ vlan.id }}" + name: "{{ vlan.name | default(omit) }}" + reservedIpRanges: "{{ vlan.reserved_ip_range | default(omit) }}" + fixedIpAssignments: "{{ vlan.fixed_ip_assignments | default(omit) }}" + dnsNameservers: "{{ vlan.dns_nameservers | default(omit) }}" + loop: "{{ appliance.vlans }}" + loop_control: + loop_var: vlan + when: > + ((vlan.reserved_ip_range is defined) or + (vlan.fixed_ip_assignments is defined) or + (vlan.dns_nameservers is defined)) and + vlan.state == "present" diff --git a/roles/configure_meraki_mx/tasks/configure_wan_uplinks.yml b/roles/configure_meraki_mx/tasks/configure_wan_uplinks.yml index bbc0bd1..9929270 100644 --- a/roles/configure_meraki_mx/tasks/configure_wan_uplinks.yml +++ b/roles/configure_meraki_mx/tasks/configure_wan_uplinks.yml @@ -1,18 +1,18 @@ --- - name: Query Device Serial Number for {{ appliance.name }} - cisco.meraki.meraki_device: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" - hostname: "{{ appliance.name }}" - state: query - register: device_results + ansible.builtin.set_fact: + device_serial: "{{ lookup('wwt.meraki.fetch', + 'network_devices', + org_name=meraki_mx_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mx_configuration.network.name, + device_name=appliance.name) }}" - name: Configure Meraki MX WAN Uplinks block: - name: Configure MX WAN Uplinks for {{ appliance.name }} ansible.builtin.uri: - url: "{{ dashboard_base_url }}/devices/{{ device_results['data'][0]['serial'] }}/appliance/uplinks/settings" + url: "{{ dashboard_base_url }}/devices/{{ device_serial }}/appliance/uplinks/settings" method: PUT status_code: 200 headers: diff --git a/roles/configure_meraki_mx/tasks/main.yml b/roles/configure_meraki_mx/tasks/main.yml index 64f6866..0f3e65e 100644 --- a/roles/configure_meraki_mx/tasks/main.yml +++ b/roles/configure_meraki_mx/tasks/main.yml @@ -7,62 +7,37 @@ # # Written by: Nick Thompson (github/@nsthompson) # -- name: Get Meraki Network IDs - cisco.meraki.meraki_network: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" - state: query - loop: "{{ meraki_mx_configuration.appliances }}" - loop_control: - loop_var: appliance - register: network_results +- name: Look Up Meraki MX Appliance Network ID + ansible.builtin.set_fact: + network_id: "{{ lookup('wwt.meraki.fetch', + 'network_id', + org_name=meraki_mx_configuration.network.organization, + meraki_api_key=auth_key, + network_name=meraki_mx_configuration.network.name) }}" - name: Failure - Network DOES NOT exist ansible.builtin.fail: msg: Meraki Network is not provisioned - when: network_results.results[0].data.id is not defined - -- name: Build dict of Network Name to IDs - ansible.builtin.set_fact: - network_ids: >- - {{ network_ids | default({}) | combine( - { - result.data.name: { - "network_id": result.data.id, - } - } - ) }} - loop: "{{ network_results.results }}" - loop_control: - loop_var: result + when: network_id is not defined - name: Configure Meraki MX Deployment Settings ansible.builtin.include_tasks: configure_deployment.yml - vars: - network_id: "{{ network_ids[appliance.network]['network_id'] }}" loop: "{{ meraki_mx_configuration.appliances }}" loop_control: loop_var: appliance - name: Configure Meraki MX WAN Uplinks ansible.builtin.include_tasks: configure_wan_uplinks.yml - vars: - network_id: "{{ network_ids[appliance.network]['network_id'] }}" loop: "{{ meraki_mx_configuration.appliances }}" loop_control: loop_var: appliance - name: Configure Meraki MX Network VLAN Settings - cisco.meraki.meraki_mx_network_vlan_settings: - auth_key: "{{ auth_key }}" - org_name: "{{ appliance.organization }}" - net_name: "{{ appliance.network }}" - vlans_enabled: "{{ appliance.lan_settings.enable_vlans }}" + cisco.meraki.networks_appliance_vlans_settings: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ network_id }}" state: present - loop: "{{ meraki_mx_configuration.appliances }}" - loop_control: - loop_var: appliance + vlansEnabled: "{{ meraki_mx_configuration.network.lan_settings.enable_vlans }}" - name: Configure Meraki MX VLANs ansible.builtin.include_tasks: configure_vlans.yml @@ -78,8 +53,6 @@ - name: Configure Threat Protection ansible.builtin.include_tasks: configure_threat_protection.yml - vars: - network_id: "{{ network_ids[appliance.network]['network_id'] }}" loop: "{{ meraki_mx_configuration.appliances }}" loop_control: loop_var: appliance diff --git a/roles/manage_meraki_network/meta/main.yml b/roles/manage_meraki_network/meta/main.yml index 8da9cf0..141c743 100644 --- a/roles/manage_meraki_network/meta/main.yml +++ b/roles/manage_meraki_network/meta/main.yml @@ -4,7 +4,7 @@ galaxy_info: description: Create and Manage Meraki Networks company: World Wide Technology license: GPL-3.0-or-later - min_ansible_version: ">=2.11.0" + min_ansible_version: ">=2.15.0" galaxy_tags: - networking - infrastructure diff --git a/roles/manage_meraki_network/tasks/configure_network.yml b/roles/manage_meraki_network/tasks/configure_network.yml index 5248b6c..8c19206 100644 --- a/roles/manage_meraki_network/tasks/configure_network.yml +++ b/roles/manage_meraki_network/tasks/configure_network.yml @@ -1,11 +1,10 @@ --- - name: Configure Meraki Network - cisco.meraki.meraki_network: - auth_key: "{{ auth_key }}" + cisco.meraki.networks: + meraki_api_key: "{{ auth_key }}" state: "{{ network.state }}" - org_name: "{{ network.organization }}" - net_name: "{{ network.name }}" - type: "{{ network.type }}" - timezone: "{{ network.timezone }}" + organizationId: "{{ lookup('wwt.meraki.fetch', 'org_id', org_name=network.organization, meraki_api_key=auth_key) }}" + name: "{{ network.name }}" + productTypes: "{{ network.type }}" + timeZone: "{{ network.timezone }}" tags: "{{ network.tags }}" - enable_vlans: "{{ network.enable_vlans }}" diff --git a/roles/manage_meraki_network/tasks/manage_devices.yml b/roles/manage_meraki_network/tasks/manage_devices.yml index f72c0f1..dae305d 100644 --- a/roles/manage_meraki_network/tasks/manage_devices.yml +++ b/roles/manage_meraki_network/tasks/manage_devices.yml @@ -1,28 +1,73 @@ --- - name: Manage Network Devices - cisco.meraki.meraki_device: - auth_key: "{{ auth_key }}" - org_name: "{{ network.organization }}" - net_name: "{{ network.name }}" - serial: "{{ device.serial }}" - state: "{{ device.state }}" - loop: "{{ network.devices }}" + block: + - name: Look for existing network devices + ansible.builtin.set_fact: + device_serials: "{{ query('wwt.meraki.fetch', 'network_devices', network_name=network.name, org_name=network.organization, meraki_api_key=auth_key) }}" + + - name: Build List of Network Devices to Add + ansible.builtin.set_fact: + add_present_devices: "{{ (add_present_devices | default([])) + [device.serial] }}" + loop: "{{ network.devices }}" + loop_control: + loop_var: device + when: device.state == "present" and device.serial not in device_serials + + - name: Build List of Network Devices to Remove + ansible.builtin.set_fact: + remove_absent_devices: "{{ (remove_absent_devices | default([])) + [device.serial] }}" + loop: "{{ network.devices }}" + loop_control: + loop_var: device + when: device.state == "absent" and device.serial in device_serials + rescue: + - name: Device Query Failure + ansible.builtin.fail: + msg: "{{ ansible_failed_result }}" + +- name: Claim Devices + cisco.meraki.networks_devices_claim: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ lookup('wwt.meraki.fetch', 'network_id', org_name=network.organization, meraki_api_key=auth_key, network_name=network.name) }}" + serials: "{{ add_present_devices }}" + when: add_present_devices is defined + +- name: Remove Devices + cisco.meraki.networks_devices_remove: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ lookup('wwt.meraki.fetch', 'network_id', org_name=network.organization, meraki_api_key=auth_key, network_name=network.name) }}" + serial: "{{ device }}" + loop: "{{ remove_absent_devices }}" loop_control: loop_var: device + when: remove_absent_devices is defined # Meraki requires a second API call to update name and address information - name: Update Network Devices - cisco.meraki.meraki_device: - auth_key: "{{ auth_key }}" - org_name: "{{ network.organization }}" - net_name: "{{ network.name }}" - name: "{{ device.name }}" - serial: "{{ device.serial }}" - address: "{{ network.address | default(omit) }}" - move_map_marker: "{{ 'true' if network.address | default(omit) }}" - state: "{{ device.state }}" - loop: "{{ network.devices }}" - loop_control: - loop_var: device - when: device.state == "present" + block: + - name: Add Location Information to Network Devices + ansible.builtin.uri: + url: "{{ dashboard_base_url }}/devices/{{ device.serial }}" + method: PUT + status_code: 200 + headers: + Content-Type: application/json + X-Cisco-Meraki-API-Key: "{{ auth_key }}" + body_format: json + body: + address: "{{ network.address | default(omit) }}" + moveMapMarker: "{{ 'true' if network.address | default(omit) }}" + changed_when: api_result.status == 200 + until: api_result.status != 429 + delay: 5 + retries: 3 + register: api_result + loop: "{{ network.devices }}" + loop_control: + loop_var: device + when: device.state == "present" + rescue: + - name: Something went wrong... + ansible.builtin.fail: + msg: "ERROR: {{ api_result }}" diff --git a/roles/manage_meraki_network/tasks/remove_network.yml b/roles/manage_meraki_network/tasks/remove_network.yml index a9f2994..5b7c57d 100644 --- a/roles/manage_meraki_network/tasks/remove_network.yml +++ b/roles/manage_meraki_network/tasks/remove_network.yml @@ -1,19 +1,21 @@ --- -- name: Remove Devices from Meraki Network - cisco.meraki.meraki_device: - auth_key: "{{ auth_key }}" - org_name: "{{ network.organization }}" - net_name: "{{ network.name }}" - serial: "{{ device.serial }}" - state: absent - loop: "{{ network.devices }}" +- name: Look for existing network devices + ansible.builtin.set_fact: + device_serials: "{{ query('wwt.meraki.fetch', 'network_devices', network_name=network.name, org_name=network.organization, meraki_api_key=auth_key) }}" + +- name: Remove Devices + cisco.meraki.networks_devices_remove: + meraki_api_key: "{{ auth_key }}" + networkId: "{{ lookup('wwt.meraki.fetch', 'network_id', org_name=network.organization, meraki_api_key=auth_key, network_name=network.name) }}" + serial: "{{ device }}" + loop: "{{ device_serials }}" loop_control: loop_var: device + when: device_serials is defined - name: Remove Meraki Network - cisco.meraki.meraki_network: - auth_key: "{{ auth_key }}" + cisco.meraki.networks: + meraki_api_key: "{{ auth_key }}" state: "{{ network.state }}" - org_name: "{{ network.organization }}" - net_name: "{{ network.name }}" + networkId: "{{ lookup('wwt.meraki.fetch', 'network_id', org_name=network.organization, meraki_api_key=auth_key, network_name=network.name) }}" when: network.state == "absent"