diff --git a/.coverage b/.coverage
deleted file mode 100644
index 73bb5ae1..00000000
Binary files a/.coverage and /dev/null differ
diff --git a/.github/workflows/test-library.yml b/.github/workflows/test-library.yml
index be480310..0b5a0e97 100644
--- a/.github/workflows/test-library.yml
+++ b/.github/workflows/test-library.yml
@@ -24,10 +24,10 @@ jobs:
- name: Install dependencies
run: uv sync --python 3.13
- - name: Lint with flake8
+ - name: Lint with ruff
run: |
- uv run flake8 . --count --select=E9,F63,F7,F82 --ignore=F405,W391,W291,C901,E501,E303,W293 --exclude=examples,generator,.venv --show-source --statistics
- uv run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --exclude=examples,generator,.venv --statistics
+ uv run ruff check meraki/ tests/unit/ tests/integration/ tests/benchmarks/
+ uv run ruff format --check meraki/ tests/unit/ tests/integration/ tests/benchmarks/
unit-test:
runs-on: ubuntu-latest
@@ -127,3 +127,84 @@ jobs:
VAR_NAME="ORG_${PREFIX}_${INDEX}"
ORG_ID="${!VAR_NAME}"
uv run pytest tests/integration -v --tb=short --apikey ${{ secrets.TEST_ORG_API_KEY }} --o "$ORG_ID"
+
+ - name: Validate against baseline
+ env:
+ ORG_GA_0: ${{ secrets.TEST_ORG_GA_00_ID }}
+ ORG_GA_1: ${{ secrets.TEST_ORG_GA_01_ID }}
+ ORG_GA_2: ${{ secrets.TEST_ORG_GA_02_ID }}
+ ORG_GA_3: ${{ secrets.TEST_ORG_GA_03_ID }}
+ ORG_BETA_0: ${{ secrets.TEST_ORG_BETA_00_ID }}
+ ORG_BETA_1: ${{ secrets.TEST_ORG_BETA_01_ID }}
+ ORG_BETA_2: ${{ secrets.TEST_ORG_BETA_02_ID }}
+ ORG_BETA_3: ${{ secrets.TEST_ORG_BETA_03_ID }}
+ ORG_DEV_0: ${{ secrets.TEST_ORG_DEV_00_ID }}
+ ORG_DEV_1: ${{ secrets.TEST_ORG_DEV_01_ID }}
+ ORG_DEV_2: ${{ secrets.TEST_ORG_DEV_02_ID }}
+ ORG_DEV_3: ${{ secrets.TEST_ORG_DEV_03_ID }}
+ run: |
+ BRANCH="${{ github.head_ref || github.ref_name }}"
+ BASE="${{ github.base_ref }}"
+ case "$BRANCH" in
+ main|release) PREFIX="GA" ;;
+ beta|beta-release) PREFIX="BETA" ;;
+ httpx|httpx-release) PREFIX="DEV" ;;
+ *)
+ case "$BASE" in
+ main) PREFIX="GA" ;;
+ beta) PREFIX="BETA" ;;
+ httpx) PREFIX="DEV" ;;
+ *) echo "Unknown branch: $BRANCH (base: $BASE)" && exit 1 ;;
+ esac
+ ;;
+ esac
+ INDEX=$(echo '${{ needs.assign-orgs.outputs.assignments }}' | jq -r '.["${{ matrix.python-version }}"]')
+ VAR_NAME="ORG_${PREFIX}_${INDEX}"
+ ORG_ID="${!VAR_NAME}"
+ if [ -z "$ORG_ID" ]; then
+ echo "::error::No org id resolved for ${VAR_NAME}; cannot validate baseline"
+ exit 1
+ fi
+ EXPECTED_TOTAL=32
+ ACTUAL=$(uv run pytest tests/integration --co -q --apikey ${{ secrets.TEST_ORG_API_KEY }} --o "$ORG_ID" 2>/dev/null | grep -oP '^\d+(?= tests? collected)' | tail -1)
+ ACTUAL="${ACTUAL:-0}"
+ if ! [[ "$ACTUAL" =~ ^[0-9]+$ ]]; then
+ echo "::error::Could not parse collected test count (got '$ACTUAL')"
+ exit 1
+ fi
+ echo "Collected tests: $ACTUAL (baseline: $EXPECTED_TOTAL)"
+ if [ "$ACTUAL" -lt "$EXPECTED_TOTAL" ]; then
+ echo "::error::Regression: collected $ACTUAL tests, baseline expects $EXPECTED_TOTAL"
+ exit 1
+ fi
+
+ benchmark:
+ runs-on: ubuntu-latest
+ needs: [unit-test]
+ strategy:
+ fail-fast: true
+ matrix:
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Install uv
+ uses: astral-sh/setup-uv@v7
+ with:
+ enable-cache: true
+
+ - name: Set up Python ${{ matrix.python-version }}
+ run: uv python install ${{ matrix.python-version }}
+
+ - name: Install dependencies
+ run: uv sync --python ${{ matrix.python-version }}
+
+ - name: Run benchmarks
+ run: uv run pytest tests/benchmarks --benchmark-json=benchmark-${{ matrix.python-version }}.json
+
+ - name: Upload benchmark results
+ uses: actions/upload-artifact@v7
+ with:
+ name: benchmark-py${{ matrix.python-version }}
+ path: benchmark-${{ matrix.python-version }}.json
diff --git a/.gitignore b/.gitignore
index 261f6fac..9a530e89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ venv/
# Testing
.pytest_cache/
+.coverage
# IDEs
.idea/
diff --git a/.planning/MILESTONES.md b/.planning/MILESTONES.md
deleted file mode 100644
index 19f7ac17..00000000
--- a/.planning/MILESTONES.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Milestones
-
-## v1.0 OASv3 Generator (Shipped: 2026-04-30)
-
-**Phases completed:** 5 phases, 11 plans, 11 tasks
-
-**Key accomplishments:**
-
-- One-liner:
-- One-liner:
-- One-liner:
-- RED:
-- Commit:
-- Semantic diff script (scripts/semantic_diff_v2_v3.py):
-
----
diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md
deleted file mode 100644
index 101a74e5..00000000
--- a/.planning/PROJECT.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Meraki Dashboard API Python SDK
-
-## What This Is
-
-A Python SDK wrapping the Meraki Dashboard API, auto-generated from the OpenAPI spec. Provides both synchronous and async interfaces with pagination, retry logic, rate limiting, and batch action support.
-
-## Core Value
-
-Developers can interact with every Meraki Dashboard API endpoint through a well-typed, well-documented Python client that stays current with the live API spec.
-
-## Current Milestone: v1.1 Deprecation Cycle
-
-**Goal:** Promote v3 generator to default, deprecate and remove v2 generator and abandoned v3 attempt.
-
-**Target features:**
-- Rename v2 generator to `generate_library_oasv2.py` with deprecation warning
-- Promote v3 generator to `generate_library.py` (new default)
-- Remove abandoned `generate_library_oasv3.py`
-- Remove v2 generator after confirming no rollbacks needed
-
-## Previous State (v1.0)
-
-Modular OASv3 generator built and tested. Produces sync, async, and batch modules with explicit param construction, .pyi type stubs, and CI drift detection against live spec. 124 tests passing.
-
-## Requirements
-
-### Validated
-
-- Generator produces full SDK from OASv2 spec (production, working)
-- Sync and async interfaces with identical API surface
-- Pagination, retry, rate limiting, batch actions
-- kwarg validation with optional logging
-- ✓ OASv3 generator with modular architecture - v1.0
-- ✓ `$ref` resolution with cycle protection - v1.0
-- ✓ `requestBody` parsing (JSON, multipart, octet-stream) - v1.0
-- ✓ `oneOf` query param handling - v1.0
-- ✓ `nullable` type annotations - v1.0
-- ✓ Path-level parameter inheritance - v1.0
-- ✓ Replace `locals()` antipattern with explicit param construction - v1.0
-- ✓ Type stub generation (`.pyi` files) - v1.0
-- ✓ Golden-file test suite for v3 generator - v1.0
-- ✓ CI drift detection between v2 and v3 output - v1.0
-
-### Active
-
-- [ ] Rename v2 generator to `generate_library_oasv2.py` with deprecation warning
-- [ ] Promote v3 generator to `generate_library.py` (new default)
-- [ ] Remove abandoned `generate_library_oasv3.py`
-- [ ] Remove v2 generator after one minor version cycle
-
-### Out of Scope
-
-- Modifying the v2 generator internals (rename/remove is in scope for v1.1)
-- Changing the runtime SDK behavior (rest_session, pagination, etc.)
-- Supporting OpenAPI 3.1 (`type: [string, null]` syntax)
-- Rewriting Jinja2 templates from scratch (reuse existing, extend as needed)
-
-## Context
-
-- Live v3 spec at `https://api.meraki.com/api/v1/openapiSpec?version=3` (OpenAPI 3.0.1)
-- Existing v2 generator: `generator/generate_library.py` (production)
-- Abandoned v3 attempt: `generator/generate_library_oasv3.py` (monolithic, incomplete)
-- Shared utilities: `generator/common.py`, Jinja2 templates in `generator/`
-- v3 spec has features not in v2: `requestBody`, `$ref`, `oneOf` query params, `nullable`, `components/schemas`
-- 298 `x-batchable-actions` entries present in v3 spec
-
-## Constraints
-
-- **Compatibility**: Output must be structurally identical to v2, with enhanced features (like object query params) and docstrings from v3-only features
-- **Architecture**: Follow v2's modular structure; reuse `common.py` and templates
-- **Testing**: Golden-file tests must validate v3-specific output, not match v2 byte-for-byte
-- **Deprecation**: v2 generator retained until parity gate passes for 2+ consecutive API releases
-
-## Key Decisions
-
-| Decision | Rationale | Outcome |
-|----------|-----------|---------|
-| Replace abandoned oasv3 file entirely | Cleaner modular structure vs patching monolith | ✓ Good |
-| Resolve `$ref` at parse time with caching | Downstream code gets normalized dicts, no template changes | ✓ Good |
-| `oneOf` reported as "string or object" | Accurate type representation without lying | ✓ Good |
-| Thread `spec` through all functions | Needed for `$ref` resolution anywhere in tree | ✓ Good |
-| Explicit param construction over `locals()` | Type-safe, static-analysis friendly | ✓ Good |
-
-## Evolution
-
-This document evolves at phase transitions and milestone boundaries.
-
-**After each phase transition** (via `/gsd-transition`):
-1. Requirements invalidated? -> Move to Out of Scope with reason
-2. Requirements validated? -> Move to Validated with phase reference
-3. New requirements emerged? -> Add to Active
-4. Decisions to log? -> Add to Key Decisions
-5. "What This Is" still accurate? -> Update if drifted
-
-**After each milestone** (via `/gsd-complete-milestone`):
-1. Full review of all sections
-2. Core Value check, still the right priority?
-3. Audit Out of Scope, reasons still valid?
-4. Update Context with current state
-
----
-*Last updated: 2026-04-30 after v1.1 milestone start*
diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md
deleted file mode 100644
index c0709a8f..00000000
--- a/.planning/REQUIREMENTS.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Requirements: Meraki Dashboard API Python SDK
-
-**Defined:** 2026-04-30
-**Core Value:** Developers can interact with every Meraki Dashboard API endpoint through a well-typed, well-documented Python client that stays current with the live API spec.
-
-## v1.1 Requirements
-
-Requirements for Deprecation Cycle milestone. Promotes v3 generator to default, removes legacy code.
-
-### Deprecation
-
-- [ ] **DEP-01**: Rename v2 generator to `generate_library_oasv2.py` with deprecation warning on import
-- [ ] **DEP-02**: Promote v3 generator to `generate_library.py` (new default entry point)
-- [ ] **DEP-03**: Remove abandoned `generate_library_oasv3.py` (dead code cleanup)
-- [ ] **DEP-04**: Update all imports, CI workflows, and documentation referencing old filenames
-
-## Future Requirements
-
-None planned beyond this milestone.
-
-## Out of Scope
-
-| Feature | Reason |
-|---------|--------|
-| Changing runtime SDK behavior | rest_session, pagination, etc. are stable |
-| OpenAPI 3.1 support | Only 3.0.1 style supported |
-| Rewriting Jinja2 templates | Reuse existing, extend as needed |
-| Removing v2 generator immediately | One version cycle buffer required |
-
-## Traceability
-
-| Requirement | Phase | Status |
-|-------------|-------|--------|
-| DEP-01 | Phase 6 | Pending |
-| DEP-02 | Phase 6 | Pending |
-| DEP-03 | Phase 7 | Pending |
-| DEP-04 | Phase 7 | Pending |
-
-**Coverage:**
-- v1.1 requirements: 4 total
-- Mapped to phases: 4
-- Unmapped: 0
-
----
-*Requirements updated: 2026-04-30 (traceability mapped to phases 6-7)*
diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
deleted file mode 100644
index 435c096e..00000000
--- a/.planning/ROADMAP.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# Roadmap: Meraki Dashboard API Python SDK
-
-## Milestones
-
-- ✅ **v1.0 OASv3 Generator** — Phases 1-5 (shipped 2026-04-30)
-- 🚧 **v1.1 Deprecation Cycle** — Phases 6-7 (active)
-
-## Phases
-
-
-✅ v1.0 OASv3 Generator (Phases 1-5) — SHIPPED 2026-04-30
-
-- [x] Phase 1: Parser Foundation (2/2 plans) — completed 2026-04-30
-- [x] Phase 2: Unified Parameter Parser (2/2 plans) — completed 2026-04-30
-- [x] Phase 3: Generation Integration (2/2 plans) — completed 2026-04-30
-- [x] Phase 4: Type Stubs (2/2 plans) — completed 2026-04-30
-- [x] Phase 5: Testing & CI (3/3 plans) — completed 2026-04-30
-
-
-
-### v1.1 Deprecation Cycle (Phases 6-7)
-
-- [ ] **Phase 6: Generator Swap** - Rename v2 generator with deprecation warning, promote v3 to default
-- [ ] **Phase 7: Legacy Cleanup** - Remove abandoned v3 attempt, update all references
-
-## Phase Details
-
-### Phase 6: Generator Swap
-**Goal**: v3 generator becomes default entry point, v2 generator deprecated but retained
-**Depends on**: Nothing (first phase of milestone)
-**Requirements**: DEP-01, DEP-02
-**Success Criteria** (what must be TRUE):
- 1. `generate_library.py` imports and runs v3 generator code
- 2. `generate_library_oasv2.py` imports and runs v2 generator code with deprecation warning
- 3. Running `python generator/generate_library.py` produces SDK using v3 parser
- 4. Running `python generator/generate_library_oasv2.py` logs deprecation warning but works
-**Plans**: 1 plan
-
-Plans:
-- [x] 06-01-PLAN.md — Swap generator files, add deprecation warning, update test imports
-
-### Phase 7: Legacy Cleanup
-**Goal**: Abandoned v3 attempt removed, all imports and CI workflows updated
-**Depends on**: Phase 6
-**Requirements**: DEP-03, DEP-04
-**Success Criteria** (what must be TRUE):
- 1. `generate_library_oasv3.py` file no longer exists in repository
- 2. CI workflows reference `generate_library.py` (not old filenames)
- 3. Documentation references `generate_library.py` and `generate_library_oasv2.py` (deprecated)
- 4. All internal imports use correct generator filenames
-**Plans**: TBD
-
-## Progress
-
-| Phase | Milestone | Plans Complete | Status | Completed |
-|-------|-----------|----------------|--------|-----------|
-| 1. Parser Foundation | v1.0 | 2/2 | Complete | 2026-04-30 |
-| 2. Unified Parameter Parser | v1.0 | 2/2 | Complete | 2026-04-30 |
-| 3. Generation Integration | v1.0 | 2/2 | Complete | 2026-04-30 |
-| 4. Type Stubs | v1.0 | 2/2 | Complete | 2026-04-30 |
-| 5. Testing & CI | v1.0 | 3/3 | Complete | 2026-04-30 |
-| 6. Generator Swap | v1.1 | 0/1 | Not started | - |
-| 7. Legacy Cleanup | v1.1 | 0/0 | Not started | - |
-
----
-*Roadmap updated: 2026-04-30 (Phase 6 plan created)*
diff --git a/.planning/STATE.md b/.planning/STATE.md
deleted file mode 100644
index 661cf8d2..00000000
--- a/.planning/STATE.md
+++ /dev/null
@@ -1,55 +0,0 @@
----
-gsd_state_version: 1.0
-milestone: v1.1
-milestone_name: Deprecation Cycle
-status: executing
-last_updated: "2026-04-30T12:09:25.434Z"
-last_activity: 2026-04-30
-progress:
- total_phases: 2
- completed_phases: 1
- total_plans: 1
- completed_plans: 1
- percent: 100
----
-
-# Project State
-
-## Project Reference
-
-See: .planning/PROJECT.md (updated 2026-04-30)
-
-**Core value:** Developers can interact with every Meraki Dashboard API endpoint through a well-typed, well-documented Python client that stays current with the live API spec.
-**Current focus:** Phase 06 — generator-swap
-
-## Current Position
-
-Phase: 07
-Plan: Not started
-Status: Executing Phase 06
-Last activity: 2026-04-30
-
-```
-[░░░░░░░░░░░░░░░░░░░░] 0% (0/2 phases)
-```
-
-## Accumulated Context
-
-### Decisions
-
-- v1.0: All key decisions validated (see PROJECT.md Key Decisions table)
-- v1.1: Parity confirmed against live spec; ready to promote v3
-
-### Pending Todos
-
-None.
-
-### Blockers/Concerns
-
-None.
-
-### Quick Tasks Completed
-
-| # | Description | Date | Commit | Directory |
-|---|-------------|------|--------|-----------|
-| 260430-kti | Integration tests: pagination iterators, org-wide clients, API requests log | 2026-04-30 | 0311304 | [260430-kti-create-integration-tests-based-on-exampl](./quick/260430-kti-create-integration-tests-based-on-exampl/) |
diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md
deleted file mode 100644
index 72230347..00000000
--- a/.planning/codebase/ARCHITECTURE.md
+++ /dev/null
@@ -1,196 +0,0 @@
-# Architecture
-
-**Analysis Date:** 2026-04-29
-
-## Pattern Overview
-
-**Overall:** Multi-layer façade pattern wrapping the Meraki Dashboard API with configurable HTTP session management. The SDK provides both synchronous (requests-based) and asynchronous (aiohttp-based) interfaces, each exposing identical API scopes through separate entry points.
-
-**Key Characteristics:**
-- Code generated from OpenAPI specification v1 (auto-generated from Meraki OpenAPI spec)
-- Dual API access patterns (synchronous DashboardAPI and async AsyncDashboardAPI)
-- Centralized HTTP session handling with retry logic, pagination, and rate limiting
-- Scoped API endpoints organized by resource type (organizations, networks, devices, etc.)
-- Batch action support through separate Batch helper classes
-- Configurable logging, timeouts, retries, and kwarg validation
-
-## Layers
-
-**Entry Point Layer:**
-- Purpose: Public API initialization and scope access
-- Location: `meraki/__init__.py` (sync), `meraki/aio/__init__.py` (async)
-- Contains: DashboardAPI and AsyncDashboardAPI classes with scope properties
-- Depends on: RestSession/AsyncRestSession, all API scope classes
-- Used by: End users instantiating the client
-
-**Scope/Resource Layer:**
-- Purpose: Group operations by Meraki resource type (Organizations, Networks, Devices, etc.)
-- Location: `meraki/api/{scope}.py` (sync), `meraki/aio/api/{scope}.py` (async)
-- Contains: Classes like Organizations, Networks, Devices, Appliance, Camera, etc. (17 total scopes)
-- Depends on: RestSession.get/post/put/delete methods
-- Used by: Users calling operations like `dashboard.organizations.getOrganizations()`
-
-**Batch Helper Layer:**
-- Purpose: Specialized classes for batch operations (Action Batches)
-- Location: `meraki/api/batch/{scope}.py`
-- Contains: ActionBatchOrganizations, ActionBatchNetworks, etc.
-- Depends on: Batch class aggregation
-- Used by: Users batching multiple API calls for concurrent execution
-
-**HTTP Session Layer:**
-- Purpose: Handle all HTTP communication, retry logic, rate limiting, pagination
-- Location: `meraki/rest_session.py` (sync), `meraki/aio/rest_session.py` (async)
-- Contains: RestSession and AsyncRestSession classes
-- Depends on: requests (sync), aiohttp (async), response_handler, common utilities
-- Used by: All scope classes making actual API calls
-
-**Configuration Layer:**
-- Purpose: Define default constants and environment variable names
-- Location: `meraki/config.py`
-- Contains: API_KEY_ENVIRONMENT_VARIABLE, DEFAULT_BASE_URL, timeouts, retry policies, logging options
-- Depends on: Nothing (config only)
-- Used by: DashboardAPI, AsyncDashboardAPI, RestSession, AsyncRestSession initialization
-
-**Utility Layer:**
-- Purpose: Shared helpers for validation, logging, parameter encoding
-- Location: `meraki/common.py`, `meraki/response_handler.py`
-- Contains: Python version check, base URL validation, iterator logic, user agent formatting
-- Depends on: Nothing (utilities only)
-- Used by: RestSession, common initialization
-
-**Error Handling Layer:**
-- Purpose: Exception types for API and validation errors
-- Location: `meraki/exceptions.py`
-- Contains: APIKeyError, APIError, AsyncAPIError, PythonVersionError, SessionInputError
-- Depends on: Nothing (exceptions only)
-- Used by: RestSession, AsyncRestSession, DashboardAPI initialization
-
-## Data Flow
-
-**Synchronous Request Flow:**
-
-1. User calls `dashboard.organizations.getOrganizations()`
-2. Organizations instance method builds metadata dict with operation name and tags
-3. Method constructs resource path and extracts valid kwargs into params/payload dicts
-4. Organizations calls `self._session.get(metadata, resource, params)`
-5. RestSession.get() calls request() with metadata, resource, params
-6. request() performs retry loop with rate limit/4xx error handling
-7. requests library makes actual HTTP call with Bearer token auth header
-8. Response is logged and returned to Organizations method
-9. Organizations method returns data to caller
-
-**Asynchronous Request Flow:**
-
-1. User calls `await aiomeraki.organizations.getOrganizations()`
-2. Same scope method structure, but AsyncOrganizations calls `await self._session.get()`
-3. AsyncRestSession.get() calls request() coroutine with same parameters
-4. request() performs retry loop with rate limit/4xx error handling using aiohttp
-5. aiohttp client makes actual HTTP call
-6. Response awaited and returned through scope method
-7. Caller receives awaitable result
-
-**Pagination Flow:**
-
-1. User calls listOperation with total_pages parameter
-2. get_pages() is called (iterator or legacy mode)
-3. Iterator mode: returns generator yielding individual items across pages
-4. Legacy mode: yields complete page lists based on total_pages/perPage
-5. Handles startingAfter/endingBefore tokens in Link headers for pagination
-
-**State Management:**
-
-- Session state: Stored in RestSession/AsyncRestSession instance (headers, config, retry policy)
-- Per-request state: Metadata dict carries operation metadata for logging/error handling
-- User agent state: Dynamically constructed with caller identifier and SDK version
-- Pagination state: Tracked via response Link headers, not stored between calls
-
-## Key Abstractions
-
-**Session Abstraction (RestSession/AsyncRestSession):**
-- Purpose: Shields scope classes from HTTP implementation details
-- Examples: `meraki/rest_session.py`, `meraki/aio/rest_session.py`
-- Pattern: Both implement identical interface (get, post, put, delete, get_pages) with different transport
-- Allows scope code to be generated once, shared between sync/async via templates
-
-**Scope Operation Pattern:**
-- Purpose: Standardized method structure for all API operations
-- Examples: `meraki/api/organizations.py`, `meraki/api/networks.py`
-- Pattern: kwargs.update(locals()), metadata dict, resource path building, param extraction, session call
-- Allows generated code to consistently handle pagination, kwarg validation, URL encoding
-
-**Parameter Encoding Abstraction:**
-- Purpose: Support complex query parameter types (array of objects)
-- Examples: `meraki/rest_session.py` encode_params() monkey patch
-- Pattern: Custom requests library override for handling {"param": [{"key_1":"value_1"}]} => ?param[]key_1=value_1
-- Necessary for Meraki API's complex query parameter requirements
-
-**Batch Helper Pattern:**
-- Purpose: Provide staging for Action Batch requests without session dependency
-- Examples: `meraki/api/batch/organizations.py`
-- Pattern: Stateless helper objects building batch payloads, not executing requests
-- Separate from session because batches are composed then submitted separately
-
-**Metadata Dictionary:**
-- Purpose: Carry operation context through request lifecycle for logging/error reporting
-- Structure: {"tags": ["scope_name", "read/configure"], "operation": "operationName"}
-- Usage: Extracted from exception handlers and logged with requests for audit trail
-
-## Entry Points
-
-**DashboardAPI (Sync):**
-- Location: `meraki/__init__.py`
-- Triggers: `api_instance = meraki.DashboardAPI(api_key="...", ...)`
-- Responsibilities: Initialize RestSession with config, instantiate all scope properties, manage logger setup
-- Configuration: 17 parameters controlling auth, retries, logging, simulation, pagination mode
-
-**AsyncDashboardAPI (Async):**
-- Location: `meraki/aio/__init__.py`
-- Triggers: `async with meraki.aio.AsyncDashboardAPI() as api_instance:`
-- Responsibilities: Same as sync but with AsyncRestSession, manages async context manager for session cleanup
-- Configuration: Identical 17 parameters plus AIO_MAXIMUM_CONCURRENT_REQUESTS
-
-**Module import:**
-- Location: `meraki/__init__.py`
-- Triggers: `import meraki`
-- Responsibilities: Exports DashboardAPI, config constants, version string
-- No initialization required
-
-## Error Handling
-
-**Strategy:** Exceptions caught at session layer, re-raised with context as APIError/AsyncAPIError. User handles try/except at caller level.
-
-**Patterns:**
-
-- **Rate Limiting (429):** Caught in RestSession.request() retry loop, waits NGINX_429_RETRY_WAIT_TIME before retry
-- **4XX Errors:** Caught in handle_4xx_errors(), optionally retried if RETRY_4XX_ERROR is true
-- **5XX Errors:** Caught in request() retry loop, retried up to MAXIMUM_RETRIES times
-- **API Key Missing:** Caught in DashboardAPI.__init__() before session creation, raises APIKeyError
-- **Python Version:** Caught in RestSession.__init__(), raises PythonVersionError
-- **Invalid Configuration:** Caught in common validation functions, raises SessionInputError with doc link
-- **Response Parsing:** Caught in AsyncAPIError/APIError constructors, falls back to raw content if JSON parse fails
-
-## Cross-Cutting Concerns
-
-**Logging:**
-- Implementation: Standard logging module with file/console handlers configured in DashboardAPI.__init__()
-- Per-call: RestSession logs request params before each call, logs response status after
-- Redaction: API key masked to last 4 chars in log output
-- Control: suppress_logging=True disables all logging; inherit_logging_config=True uses external logger
-
-**Validation:**
-- User agent format: validate_user_agent() regex check on MERAKI_PYTHON_SDK_CALLER format
-- Base URL: reject_v0_base_url() prevents v0 API access, validate_base_url() whitelists domains
-- Python version: check_python_version() enforces Python 3.10+
-- Kwargs: Optional validate_kwargs mode logs warnings when unrecognized kwargs passed to operations
-
-**Authentication:**
-- Method: Bearer token in Authorization header, token from API_KEY_ENVIRONMENT_VARIABLE or parameter
-- Per-call: RestSession sets header once at init, reused for all requests
-- Security: Requires explicit API key provision or environment variable, fails fast if missing
-
-**Retry Policy:**
-- Rate limits: Waits NGINX_429_RETRY_WAIT_TIME (default 60s) before retry
-- Action batch conflicts: Waits ACTION_BATCH_RETRY_WAIT_TIME (default 60s) before retry
-- Network deletion conflicts: Waits NETWORK_DELETE_RETRY_WAIT_TIME (default 240s) before retry
-- Other 4XX: Optionally retried if RETRY_4XX_ERROR enabled, waits RETRY_4XX_ERROR_WAIT_TIME
-- 5XX: Retried up to MAXIMUM_RETRIES times with exponential backoff (implementation in RestSession.request())
diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md
deleted file mode 100644
index 5b92298f..00000000
--- a/.planning/codebase/CONCERNS.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# Codebase Concerns
-
-**Analysis Date:** 2026-04-29
-
-## Tech Debt
-
-**High Cyclomatic Complexity in Request Handlers:**
-- Issue: `AsyncRestSession._request()` has complexity of 42 (async mirror at `meraki/aio/rest_session.py:135`); sync version `RestSession.request()` at `meraki/rest_session.py:207` is somewhat lower but still elevated. The async method is monolithic with deeply nested status-code matching and error handling.
-- Files: `meraki/aio/rest_session.py:135`, `meraki/rest_session.py:207`
-- Impact: Difficult to test individual error paths, maintain, and add new status handlers. Makes async retry logic hard to follow.
-- Fix approach: Extract status-code handlers (429, 5xx, 4xx patterns) into discrete methods matching the sync version's `handle_4xx_errors` pattern already implemented in `meraki/rest_session.py:324`. Reduce nesting depth.
-
-**Pagination Logic Complexity:**
-- Issue: `_get_pages_legacy()` has complexity of 24 (sync at `meraki/rest_session.py:470`) and 19 (async at `meraki/aio/rest_session.py:392`). The method handles three unrelated result types (list, dict with "items", event log dict) in one monolithic function with operation-specific branching (getNetworkEvents special cases).
-- Files: `meraki/rest_session.py:470`, `meraki/aio/rest_session.py:392`
-- Impact: Adding new endpoint pagination logic requires modifying existing complex code. Event log handling is tightly coupled with generic pagination.
-- Fix approach: Extract event-log-specific pagination into a strategy or helper method. Split result-type handlers (lines 540-561 in sync version) into separate methods. Do this after Stream 1 complexity reduction.
-
-**Sync/Async Code Duplication:**
-- Issue: `rest_session.py` (601 lines) and `aio/rest_session.py` (495 lines) share ~80% identical logic. Both manage retries, rate limiting, error handling, pagination with nearly identical structure but incompatible async/await syntax.
-- Files: `meraki/rest_session.py`, `meraki/aio/rest_session.py`
-- Impact: Bug fixes and feature additions must be applied twice. Inconsistencies can accumulate (already exists: e.g., async uses `response.reason if response.reason else None` while sync uses `response.reason if response.reason else ""`). Maintenance burden increases with each version.
-- Fix approach: Consider shared base class or code-generation approach. The generator already exists (`generator/generate_library.py` and upcoming OASv3 generator). Defer until after complexity reduction (Stream 1) so clean code is deduplicated, not spaghetti. Alternatively, migrate to `httpx` (breaking change for next major version) which provides both sync and async from one client.
-
-**No Type Annotations in Core Modules:**
-- Issue: `rest_session.py`, `aio/rest_session.py`, `__init__.py`, `exceptions.py` contain zero type hints. Functions accept `**kwargs` with no indication of expected structure.
-- Files: `meraki/rest_session.py`, `meraki/aio/rest_session.py`, `meraki/__init__.py`, `meraki/exceptions.py`
-- Impact: IDE autocompletion is limited. Downstream type-checking (mypy --strict, pyright) not possible. Consumers can't validate API usage at development time.
-- Fix approach: Add type annotations to all public and internal methods. Add `py.typed` marker in package root after annotations exist. Enable `mypy --strict` or `pyright` in CI.
-
----
-
-## Known Bugs
-
-**Event Log Pagination Edge Case:**
-- Symptoms: `getNetworkEvents` pagination in `_get_pages_legacy()` has special reverse-sorting logic and time-window boundary detection (lines 502-522 in sync, similar in async). If `pageStartAt` or `pageEndAt` is missing from response JSON, a `KeyError` is caught and logged at line 551-552 (`rest_session.py`) but execution continues, potentially merging incomplete results.
-- Files: `meraki/rest_session.py:547-561`, `meraki/aio/rest_session.py:443-457` (approx)
-- Trigger: Call `get_pages()` with high page count on `getNetworkEvents` endpoint; if Meraki API returns a response missing `pageStartAt` key, the warning logs but continues with incomplete data.
-- Workaround: None; bug is silent except for log entry. Downstream code receives truncated event sequence without indication of loss.
-
-**Bare `except Exception` in Async Request Handler:**
-- Symptoms: Line 187 in `meraki/aio/rest_session.py` catches all exceptions with bare `except Exception`, including `asyncio.CancelledError` and `KeyboardInterrupt` subclasses (in Python 3.8+ these inherit from BaseException, but other unexpected exceptions may be masked).
-- Files: `meraki/aio/rest_session.py:187`
-- Trigger: Any unexpected exception in the request (connection error, DNS failure, etc.) is logged generically and retried without distinguishing between retryable and non-retryable errors.
-- Workaround: Catch only `aiohttp` exceptions explicitly (as done in line 206-208 for JSON parse errors). Sync version (`rest_session.py:240`) is more specific (`requests.exceptions.RequestException`).
-
----
-
-## Security Considerations
-
-**Certificate Path Validation:**
-- Risk: `certificate_path` parameter (line 23 in `meraki/aio/rest_session.py`) is passed to `ssl.create_default_context()` and `load_verify_locations()` without existence check. If path is invalid, SSL context creation fails but error is raised at request time (first async call), not at session init.
-- Files: `meraki/aio/rest_session.py:97-98`, `meraki/rest_session.py` (similar pattern ~line 180)
-- Current mitigation: File must exist for SSL to work; error is caught and propagated.
-- Recommendations: Validate certificate path at session init time and raise early. Document that invalid cert paths will be caught during first request.
-
-**Proxy Configuration:**
-- Risk: `requests_proxy` parameter accepts raw URL string. No validation of proxy format or TLS verification for proxy connection. If proxy is HTTP (not HTTPS), man-in-the-middle attacks on proxy itself are possible.
-- Files: `meraki/rest_session.py:321`, `meraki/aio/rest_session.py:143`
-- Current mitigation: None explicit; relies on underlying libraries (requests, aiohttp) to handle proxy security.
-- Recommendations: Document proxy security considerations. Warn users to use HTTPS proxies in production. Consider adding proxy URL validation.
-
----
-
-## Performance Bottlenecks
-
-**Pagination Buffer in Memory:**
-- Problem: `_get_pages_legacy()` collects all pages into memory before returning. For endpoints with thousands of pages (e.g., large device event logs), this consumes unbounded memory.
-- Files: `meraki/rest_session.py:470`, `meraki/aio/rest_session.py:392`
-- Cause: Results are appended to a single list/dict in a while loop (lines 540-561 in `rest_session.py`). No streaming or generator pattern.
-- Improvement path: Implement generator-based pagination (`_get_pages_iterator` at `meraki/rest_session.py:390` and async version already exist but are not default; `use_iterator_for_get_pages` property controls switch). Document iterator approach as best practice for large result sets. Make iterator the default in next major version.
-
----
-
-## Fragile Areas
-
-**Event Log Pagination State Machine:**
-- Files: `meraki/rest_session.py:502-522`, `meraki/aio/rest_session.py:398-418` (approx)
-- Why fragile: The logic depends on timestamp ordering and specific response structure (pageStartAt, pageEndAt, events array). If Meraki API changes timestamp format or pagination cursor format, code breaks silently. Current time comparison assumes UTC; timezone handling is implicit.
-- Safe modification: Test against live API before deploying changes. Add explicit timezone checks. Verify pagination cursor format is documented in spec. Consider adding integration tests against real API (currently integration tests use mocked responses).
-- Test coverage: Event log pagination is tested in `tests/unit/test_rest_session.py` and `tests/integration/` but mocked. Live API testing is not part of CI (would require API key, rate limits, etc.).
-
-**Response JSON Validation:**
-- Files: `meraki/rest_session.py:273-285`, `meraki/aio/rest_session.py:201-211`
-- Why fragile: Code assumes `response.json()` or `response.content.strip()` will work for all 2xx responses. For GET requests with 204 (No Content), `response.content.strip()` is empty, bypassing JSON parse. If a 2xx endpoint returns empty body unexpectedly, code raises `JSONDecodeError` and retries (which may mask real issues like endpoint returning wrong format).
-- Safe modification: Check Content-Type header before attempting JSON parse. For 204, return None rather than attempting parse.
-- Test coverage: 204 handling is tested explicitly for `getOrganizationClientSearch` (line 496 in `rest_session.py`). Other 2xx no-content responses not explicitly covered.
-
-**Generated API Module Dependencies:**
-- Files: All 60+ files in `meraki/api/`, `meraki/aio/api/`, `meraki/api/batch/`
-- Why fragile: Generated code depends on `rest_session.py` and `aio/rest_session.py` internals. If core request/pagination logic changes, all generated methods can break. Generated methods have no defensive checks.
-- Safe modification: When changing core request logic, regenerate library using `generator/generate_library.py`. Ensure golden tests in `tests/generator/test_generate_library_golden.py` pass before commit.
-- Test coverage: Generator tests compare output against golden files; any signature or template changes are caught.
-
----
-
-## Scaling Limits
-
-**Concurrent Request Semaphore (Async Only):**
-- Current capacity: `AIO_MAXIMUM_CONCURRENT_REQUESTS = 10` (default, defined in `meraki/config.py`)
-- Limit: Hardcoded to 10. For large-scale deployments processing thousands of devices/networks, this is a bottleneck.
-- Files: `meraki/aio/rest_session.py:79` (semaphore init)
-- Scaling path: Make `maximum_concurrent_requests` a user-configurable parameter in `AsyncDashboardAPI` constructor (already is at line 58 of `meraki/aio/__init__.py`). Document recommended values for typical workloads. Consider adaptive tuning based on API response times (not implemented).
-
-**Pagination Window for Event Logs:**
-- Current capacity: Time-based pagination can fetch up to all events matching a time range, but no per-request limit on page count.
-- Limit: If `total_pages` is -1 (fetch all), and endpoint returns many pages, request completes but memory usage grows unbounded. Default behavior in `_get_pages_legacy()` without explicit page limit.
-- Files: `meraki/rest_session.py:470-490`
-- Scaling path: Implement auto-scaling page limit based on available memory. Or enforce hard ceiling on pages per request (e.g., max 100 pages). Document memory usage expectations for large result sets. Recommend iterator-based approach for production workloads.
-
-**Test Suite Growth:**
-- Current capacity: 211 unit tests + integration tests. Test suite runs in ~30 seconds locally.
-- Limit: As generator output and API surface grow, test suite will grow linearly. No known limit yet.
-- Scaling path: Pytest parallelization (use `pytest-xdist`) to reduce wall-clock time. CI already runs tests; no changes needed if runtime stays <2 minutes.
-
----
-
-## Dependencies at Risk
-
-**OASv3 Migration In Progress:**
-- Risk: `OASV3-MIGRATION.md` documents upcoming migration from OASv2 generator to OASv3. Current generator is OASv2-only. OASv3 spec has new features (requestBody, $ref, oneOf parameters) not handled by current generator.
-- Impact: If OASv3 migration is incomplete, generated API stubs will diverge from actual Meraki API spec, causing runtime errors in production code using new v3 features.
-- Files: `OASV3-MIGRATION.md`, `generator/generate_library.py` (current), `generator/generate_library_oasv3.py` (under development)
-- Migration plan: Follow deprecation plan in `OASV3-MIGRATION.md` section "Deprecation Plan". OASv3 generator must achieve parity with v2 (zero semantic differences on live spec for 2+ releases) before being set as default. Until then, continue using OASv2 generator for production releases.
-
-**Requests Library Pinned to <3:**
-- Risk: `requests>=2.33.1,<3` is pinned to major version 2. When requests 3.0 is released, dependency must be updated.
-- Impact: If requests 3.0 makes breaking changes (API changes, different retry behavior, etc.), this library may not work without code changes.
-- Files: `pyproject.toml:13`
-- Alternative: `httpx` (mentioned in TODO.md as potential replacement for both sync and async) is stable and maintained. Could unify sync/async code if migrated (breaking change for major version only).
-
-**aiohttp Version Constraint:**
-- Risk: `aiohttp>=3.13.5,<4` is pinned to major version 3. aiohttp 4.0 may introduce breaking changes.
-- Impact: Unknown until aiohttp 4.0 release.
-- Files: `pyproject.toml:14`
-
----
-
-## Test Coverage Gaps
-
-**Missing Sync/Async Error Path Coverage:**
-- What's not tested: Several error handling branches in `rest_session.py` and `aio/rest_session.py` are not covered. Lines 146-151 in `meraki/__init__.py` (logging edge case) have no test.
-- Files: `meraki/rest_session.py` (~25 lines uncovered, mostly logger-guarded branches), `meraki/aio/rest_session.py` (~6 lines uncovered), `meraki/__init__.py:146-151`
-- Risk: Log-guarded branches may have silent failures if logger state changes or env var is modified. Exception edge cases (e.g., API returns malformed JSON during retry) are not exercised.
-- Priority: Medium. Coverage target is 95.8% (currently met); these 36 lines are logger/simulate path branches that are rarely triggered in production but should be tested for completeness.
-- Note: TODO.md indicates "wait until after complexity refactors so you're not writing tests for code that's about to move."
-
-**Generator Golden Tests (OASv3):**
-- What's not tested: OASv3 generator output is not verified against golden files (unlike OASv2 which has `tests/generator/test_generate_library_golden.py`).
-- Files: Upcoming in `tests/generator/test_generate_library_oasv3_golden.py`
-- Risk: OASv3 generator bugs will not be caught until live API is tested.
-- Priority: Blocking. Must be implemented before OASv3 generator is promoted to default (see OASV3-MIGRATION.md step 1: "Parity gate").
-
----
-
-## Missing Critical Features
-
-**Type Checking in CI:**
-- Problem: No static type checking (mypy, pyright) in CI. `--no-strict` mode only catches obvious errors.
-- Blocks: Type-aware IDE features for downstream users. Early detection of type mismatches at build time.
-- Files: Relevant to all core modules listed under "No Type Annotations in Core Modules" tech debt section.
-
-**Adaptive Retry Strategy:**
-- Problem: All retries use fixed delays (1 second) or random backoff. No exponential backoff or observability into retry behavior.
-- Blocks: Large-scale deployments cannot tune retry strategy per endpoint or backoff strategy based on API health.
-- Files: `meraki/rest_session.py:296`, `meraki/aio/rest_session.py:212`
-
-**Request Cancellation and Timeout Context:**
-- Problem: No mechanism to cancel in-flight requests except relying on `single_request_timeout`. No request context for tracing or cancellation propagation in async.
-- Blocks: Integrations with observability tools (OpenTelemetry, etc.). Safe cancellation in long-running batches.
-- Files: `meraki/aio/rest_session.py`, `meraki/__init__.py`, `meraki/aio/__init__.py`
-
----
-
-*Concerns audit: 2026-04-29*
diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md
deleted file mode 100644
index 413cc3c7..00000000
--- a/.planning/codebase/CONVENTIONS.md
+++ /dev/null
@@ -1,167 +0,0 @@
-# Coding Conventions
-
-**Analysis Date:** 2026-04-29
-
-## Naming Patterns
-
-**Files:**
-- Snake_case for module files: `rest_session.py`, `response_handler.py`
-- Exception classes in `exceptions.py`
-- Generated API endpoint files use CamelCase where tied to service names: `devices.py`, `networks.py`, `cellularGateway.py`, `wirelessController.py`
-- Batch operation files: `meraki/api/batch/` directory with matching service names
-
-**Functions:**
-- camelCase for all function names: `check_python_version()`, `validate_user_agent()`, `getDevice()`, `updateDevice()`
-- Special methods use Python conventions: `__init__()`, `__repr__()`, `__str__()`
-- Private functions: no underscore prefix in generated code; prefix with `_` for internal helpers
-
-**Variables:**
-- camelCase for parameters: `be_geo_id`, `single_request_timeout`, `certificate_path`
-- snake_case for local variables: `user_agent`, `allowed_format_in_regex`
-- Dicts and collections use descriptive names: `metadata`, `payload`, `body_params`, `kwargs`
-- Metadata dicts follow pattern: `metadata = {"tags": [...], "operation": "..."}`
-
-**Types:**
-- Type hints used in function signatures: `def getDevice(self, serial: str):` (file `meraki/api/devices.py:9`)
-- Type hints for parameters but not always return types
-- Exception classes are all UPPERCASE suffixed with `Error`: `APIKeyError`, `APIResponseError`, `APIError`, `AsyncAPIError`, `PythonVersionError`, `SessionInputError` (file `meraki/exceptions.py`)
-
-**Classes:**
-- CamelCase: `DashboardAPI`, `RestSession`, `AsyncRestSession`, `Devices`, `Organizations` (file `meraki/__init__.py:58`)
-- Class names match API endpoint groups or functionality areas
-- Parent class inherits from `object`: `class DashboardAPI(object):` (file `meraki/__init__.py:58`)
-
-## Code Style
-
-**Formatting:**
-- Line length: 127 characters (configured in `pyproject.toml`)
-- Tool: ruff (formatter and linter)
-- Configuration: `tool.ruff` section in `pyproject.toml`
-
-**Linting:**
-- Tool: ruff with flake8 compatibility
-- Config file: `pyproject.toml` under `[tool.ruff]`
-- Pre-commit hooks run: `ruff-format` and `ruff --fix` (file `.pre-commit-config.yaml`)
-- Exclusions from formatting: generated API code in `meraki/(aio/api|api/batch|api)/`, notebooks, code generation snippets
-
-**Formatting examples from codebase:**
-```python
-# Long parameter lists continue on new lines
-def __init__(
- self,
- api_key=None,
- base_url=DEFAULT_BASE_URL,
- single_request_timeout=SINGLE_REQUEST_TIMEOUT,
- certificate_path=CERTIFICATE_PATH,
- # ... continues
-):
-```
-(file `meraki/__init__.py:87-112`)
-
-## Import Organization
-
-**Order:**
-1. Standard library imports: `import logging`, `import os`, `import platform`, `import re`, `import sys`, `import urllib.parse`
-2. Third-party imports: `import requests`, `import aiohttp`
-3. Local application imports: `from meraki.api.administered import Administered`
-
-**Path Aliases:**
-- No aliases used; direct relative imports within the package
-- Imports from `meraki.config` for constants (file `meraki/__init__.py:25-49`)
-
-**Import patterns:**
-```python
-import logging
-import os
-
-from meraki.api.administered import Administered
-from meraki.config import (
- API_KEY_ENVIRONMENT_VARIABLE,
- DEFAULT_BASE_URL,
- # ... multiline from imports
-)
-```
-(file `meraki/__init__.py:1-49`)
-
-## Error Handling
-
-**Patterns:**
-- Raise custom exceptions defined in `meraki/exceptions.py`: `APIError`, `AsyncAPIError`, `APIKeyError`, `APIResponseError`, `PythonVersionError`, `SessionInputError`
-- Check conditions and raise before proceeding: `if not api_key: raise APIKeyError()` (file `meraki/__init__.py:115-116`)
-- Exception __init__ stores attributes for later access: `self.status`, `self.reason`, `self.message` (file `meraki/exceptions.py:37-48`)
-- Exception __str__ and __repr__ methods format error output: `def exc_message(self):` returns formatted string (file `meraki/exceptions.py:22-26`)
-- Try/except for JSON decode failures: wrap `response.json()` and fallback to `response.content` (file `meraki/exceptions.py:43-46`)
-- 404 status codes append contextual help: "please wait a minute if the key or org was just newly created." (file `meraki/exceptions.py:47-48`)
-
-## Logging
-
-**Framework:** Python's built-in `logging` module
-
-**Patterns:**
-- Logger instance created in `__init__`: `self._logger = logging.getLogger(__name__)` (file `meraki/__init__.py:129`)
-- Logger can be inherited or created fresh based on `inherit_logging_config` flag
-- Suppress logging entirely with `suppress_logging=True` (file `meraki/__init__.py:128`)
-- Standard formatter: `"%(asctime)s %(name)12s: %(levelname)8s > %(message)s"` (file `meraki/__init__.py:135`)
-- Handlers: console handler (StreamHandler) and optional file handler (FileHandler)
-- Log level: DEBUG
-- Conditional logging based on `print_console` and `output_log` parameters (file `meraki/__init__.py:150-154`)
-
-## Comments
-
-**When to Comment:**
-- Docstrings for API methods show endpoint URL and parameters: `"""**Update the attributes of a device** https://developer.cisco.com/meraki/api-v1/..."""` (file `meraki/api/devices.py:28-41`)
-- TODO/FIXME comments exist in codebase (check `TODO.md` for list)
-- Inline comments explain algorithm details, especially in parameter encoding: `"""Encode parameters in a piece of data..."""` (file `meraki/rest_session.py:41-57`)
-
-**Docstring Format:**
-- Triple-quoted strings for docstrings
-- API endpoint methods include: operation description, link to documentation, parameter list with types
-- Example: `"""**Return a single device** https://developer.cisco.com/meraki/api-v1/#!get-device\n\n- serial (string): Serial"""` (file `meraki/api/devices.py:10-14`)
-
-## Function Design
-
-**Size:** Functions generally stay under 50 lines; generated API methods average 10-30 lines
-
-**Parameters:**
-- Use `**kwargs` to capture optional parameters: `def updateDevice(self, serial: str, **kwargs):` (file `meraki/api/devices.py:26`)
-- Extract known parameters from kwargs: `payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}` (file `meraki/api/devices.py:63`)
-- Validate user input early: check Python version at session init, validate API key before creating session
-
-**Return Values:**
-- API methods return result of session call: `return self._session.get(metadata, resource)` (file `meraki/api/devices.py:24`)
-- Exceptions raised on errors, no error codes or None returns for failure
-- Session methods handle retries, redirects, and error conversion internally
-
-## Module Design
-
-**Exports:**
-- Main public interface in `meraki/__init__.py`: imports all top-level API classes and `DashboardAPI`
-- Specific imports exposed: `from meraki.exceptions import APIKeyError` (file `meraki/__init__.py:51`)
-- Version exposed: `from meraki._version import __version__` (file `meraki/__init__.py:52`)
-
-**Barrel Files:**
-- `meraki/__init__.py` re-exports: all API endpoint classes (`Administered`, `Appliance`, `Camera`, etc.)
-- API batch operations under `meraki/api/batch/__init__.py` exports `Batch` class
-- Async variants under `meraki/aio/__init__.py` and `meraki/aio/api/`
-
-**Session Dependency Injection:**
-- All API classes receive session in __init__: `def __init__(self, session): self._session = session` (file `meraki/api/devices.py:5-6`)
-- Session methods (`get`, `post`, `put`, `delete`) handle all HTTP communication
-- Metadata dict passed with operation name and tags to session for logging and error handling
-
-## Configuration
-
-**Environment Variables:**
-- `MERAKI_DASHBOARD_API_KEY`: API key (defined as `API_KEY_ENVIRONMENT_VARIABLE`)
-- `BE_GEO_ID`: Partner identifier (deprecated)
-- `MERAKI_PYTHON_SDK_CALLER`: API caller tracking identifier
-- Default configuration constants in `meraki/config.py`
-
-**Constants Pattern:**
-- All config constants defined in `meraki/config.py` with uppercase names: `SINGLE_REQUEST_TIMEOUT`, `MAXIMUM_RETRIES`, `WAIT_ON_RATE_LIMIT`
-- Imported into `__init__.py` and passed to RestSession
-- Can be overridden at DashboardAPI instantiation time
-
----
-
-*Convention analysis: 2026-04-29*
diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md
deleted file mode 100644
index 49c7ba59..00000000
--- a/.planning/codebase/INTEGRATIONS.md
+++ /dev/null
@@ -1,149 +0,0 @@
-# External Integrations
-
-**Analysis Date:** 2026-04-29
-
-## APIs & External Services
-
-**Cisco Meraki Dashboard API:**
-- REST API for network, device, and organization management
- - Endpoint: `https://api.meraki.com/api/v1` (default) with regional alternatives
- - SDK/Client: requests (sync), aiohttp (async)
- - Auth: Bearer token via `Authorization: Bearer [API_KEY]` header
- - OpenAPI Spec: Available at `https://api.meraki.com/api/v1/openapiSpec`
- - Purpose: Core SDK interfaces all Meraki cloud-managed platform features via 16+ scoped API classes
- - Location: `meraki/api/` and `meraki/aio/api/` contain generated endpoint implementations
-
-**API Scopes/Modules:**
-The SDK exposes the following API scope classes, each wrapping a category of Dashboard API endpoints:
-- Organizations - Org management (`meraki/api/organizations.py`)
-- Networks - Network configuration (`meraki/api/networks.py`)
-- Devices - Device management (`meraki/api/devices.py`)
-- Wireless - Wireless networks (`meraki/api/wireless.py`)
-- Switch - Switch configuration (`meraki/api/switch.py`)
-- Appliance - Security appliance (`meraki/api/appliance.py`)
-- Camera - Camera settings (`meraki/api/camera.py`)
-- Sensor - Environmental sensors (`meraki/api/sensor.py`)
-- Licensing - License management (`meraki/api/licensing.py`)
-- Insight - Network analytics (`meraki/api/insight.py`)
-- SM - System Manager (`meraki/api/sm.py`)
-- CellularGateway - Cellular gateway settings (`meraki/api/cellularGateway.py`)
-- CampusGateway - Campus gateway settings (`meraki/api/campusGateway.py`)
-- WirelessController - Wireless controller (`meraki/api/wirelessController.py`)
-- Spaces - Workspace management (`meraki/api/spaces.py`)
-- Administered - Administered identities (`meraki/api/administered.py`)
-
-## Data Storage
-
-**Databases:**
-- None - This is a client library, not an application with persistent storage
-- All data originates from Cisco Meraki Dashboard cloud platform
-
-**File Storage:**
-- Local filesystem only - Logging output stored to disk if enabled
- - Default log location: Current working directory
- - Log file format: `meraki_api_[YYYY-MM-DD_HH-MM-SS].log`
- - Configurable via `log_path` and `log_file_prefix` parameters
-
-**Caching:**
-- None - Requests library handles HTTP caching per standard HTTP headers
-- Application developers can implement caching layers on top of SDK calls
-
-## Authentication & Identity
-
-**Auth Provider:**
-- Custom (API Key-based)
-- Implementation: HTTP Bearer token via `Authorization` header
-- API Key source: Environment variable `MERAKI_DASHBOARD_API_KEY` or constructor parameter
-- Key format: Long hexadecimal string issued via Meraki Dashboard UI
-- No OAuth, no session management
-- Location: `meraki/rest_session.py` (line 6-96 in sync), `meraki/aio/rest_session.py` (async equivalent)
-
-## Monitoring & Observability
-
-**Error Tracking:**
-- None - Library provides exception objects for caller to handle
-- Custom exception classes: `APIKeyError`, `APIError`, `AsyncAPIError`, `SessionInputError`
-- Location: `meraki/exceptions.py`
-
-**Logs:**
-- Python logging framework (stdlib)
-- Default: Logs to both console and rotating file if enabled
-- Can inherit external logger instance via `inherit_logging_config=True`
-- Log levels: DEBUG for full request/response, INFO for console output
-- Configurable via:
- - `suppress_logging=False` to enable logging
- - `output_log=True` to write to file
- - `print_console=True` for console output
- - `log_path` and `log_file_prefix` for custom locations
-- Location: Configured in `meraki/__init__.py` (lines 127-156)
-
-## CI/CD & Deployment
-
-**Hosting:**
-- PyPI (Python Package Index) - Distribution point for pip/uv installations
-- GitHub (source code and issue tracking)
-- GitHub Actions - CI pipeline for test execution
-
-**CI Pipeline:**
-- pytest runs on PR and main branch commits via GitHub Actions
-- Coverage requirement: 90% minimum (enforced in pyproject.toml)
-- Linting: flake8 and ruff applied via pre-commit hooks
-- Integration tests available in `tests/integration/` (separate from unit tests)
-
-## Environment Configuration
-
-**Required env vars:**
-- `MERAKI_DASHBOARD_API_KEY` - Meraki Dashboard API authentication key (required)
-
-**Optional env vars:**
-- `BE_GEO_ID` - Legacy partner identifier for API tracking (deprecated, use MERAKI_PYTHON_SDK_CALLER)
-- `MERAKI_PYTHON_SDK_CALLER` - Application identifier for API usage tracking (format: "AppName/Version VendorName")
-
-**Secrets location:**
-- Secrets NOT stored in repository (`.env*` in `.gitignore`)
-- Users manage API keys outside the codebase
-- No embedded credentials or configuration defaults for real environments
-
-## Webhooks & Callbacks
-
-**Incoming:**
-- None - SDK does not accept incoming webhooks
-- Users can configure webhooks in Meraki Dashboard to receive events (external to SDK)
-
-**Outgoing:**
-- API supports callback configuration for device events
-- Parameters: `callback` object with either `httpServerId` OR `url` and `sharedSecret`
-- Used in endpoints like `updateDeviceLiveToolsPing`, `createDeviceLiveToolsArpTable`, etc.
-- Location: Callback parameter support visible in `meraki/api/devices.py` and `meraki/aio/api/devices.py`
-- SDK passes callback configuration as JSON to Dashboard API; does not handle callback execution
-
-## Request/Response Patterns
-
-**Rate Limiting:**
-- Dashboard API rate limits via HTTP 429 responses
-- SDK automatically retries 429 errors with exponential backoff
-- Retry wait time: `nginx_429_retry_wait_time` (default 60s)
-- Maximum retries: `maximum_retries` (default 2)
-- Configurable via `wait_on_rate_limit=True/False`
-- `Retry-After` header parsed from 429 responses
-
-**Pagination:**
-- Built-in support for paginated results
-- Query parameters: `perPage`, `startingAfter`, `endingBefore`
-- Methods can return iterators or complete lists via `use_iterator_for_get_pages`
-- Link header parsing for next/prev pages
-
-**Error Handling:**
-- HTTP status codes >= 400 raise APIError with metadata
-- 4XX retries optional via `retry_4xx_error` (default False)
-- SSL/TLS certificate validation customizable via `certificate_path`
-- Proxy support via `requests_proxy` parameter
-
-**Simulation Mode:**
-- `simulate=True` parameter prevents POST/PUT/DELETE from executing
-- GET requests still execute normally
-- Useful for testing workflows without making actual changes
-
----
-
-*Integration audit: 2026-04-29*
diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md
deleted file mode 100644
index a576eadd..00000000
--- a/.planning/codebase/STACK.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Technology Stack
-
-**Analysis Date:** 2026-04-29
-
-## Languages
-
-**Primary:**
-- Python 3.11+ - Main language for SDK and all client implementations
-
-**Supporting:**
-- Jinja2 (templating) - Used in code generator for API endpoint generation
-
-## Runtime
-
-**Environment:**
-- CPython 3.11+ required per `pyproject.toml`
-
-**Package Manager:**
-- uv (modern Python package manager)
-- Lockfile: `uv.lock` present
-- Build system: Hatchling via `hatchling` backend
-
-## Frameworks
-
-**Core HTTP:**
-- requests 2.33.1-2.99.x - Synchronous HTTP client for REST API calls (`meraki/rest_session.py`)
-- aiohttp 3.13.5-3.99.x - Asynchronous HTTP client for concurrent API calls (`meraki/aio/rest_session.py`)
-
-**Testing:**
-- pytest 8.3.5-9.x - Test runner
-- pytest-asyncio 1.0-1.x - AsyncIO support for tests
-- pytest-cov 7.1.0-7.x - Code coverage tracking
-
-**Code Quality:**
-- flake8 7.0-7.x - Linting
-- ruff 0.15.12+ - Fast linter and formatter
-
-**Development:**
-- pre-commit 4.6.0+ - Git hook framework
-- responses 0.25-0.x - HTTP mocking for tests
-
-**Generator:**
-- Jinja2 3.1.6 - Template rendering for code generation
-
-## Key Dependencies
-
-**Critical:**
-- requests - Handles all synchronous HTTP communication with Meraki Dashboard API (`https://api.meraki.com/api/v1`)
-- aiohttp - Enables concurrent API requests via AsyncIO for performance-critical applications
-
-**Build/Runtime:**
-- hatchling - Build backend for wheel and sdist generation
-
-**Testing/Development:**
-- responses - Mocks HTTP responses in unit tests without hitting real API
-- pytest-asyncio - Manages async test execution and event loop lifecycle
-
-## Configuration
-
-**Environment:**
-- API key: `MERAKI_DASHBOARD_API_KEY` environment variable (fallback to constructor parameter)
-- Optional partner ID: `BE_GEO_ID` environment variable (deprecated but supported)
-- Optional caller identifier: `MERAKI_PYTHON_SDK_CALLER` environment variable for API usage tracking
-- Configuration file: `meraki/config.py` contains default values for all session parameters
-
-**Build:**
-- `pyproject.toml` - Project metadata, dependencies, tool configuration
-- `[tool.ruff]` - Line length set to 127
-- `[tool.pytest.ini_options]` - Test paths: `tests/unit`, test mode: `auto` for asyncio
-- `[tool.coverage.run]` - Coverage source: `meraki/` module, excludes auto-generated API endpoints
-
-**Dependency Groups:**
-- `dev` - Testing and linting tools (pytest, flake8, ruff, pre-commit, responses)
-- `generator` - Code generation dependencies (jinja2)
-
-## Platform Requirements
-
-**Development:**
-- Python 3.11+
-- uv package manager installed
-- Pre-commit hooks configured via `.pre-commit-config.yaml`
-
-**Production:**
-- Python 3.11+
-- requests library installed
-- aiohttp library installed (only if using AsyncIO API)
-- Network connectivity to `https://api.meraki.com/api/v1` (default endpoint)
-- Alternate regional endpoints supported:
- - Canada: `https://api.meraki.ca/api/v1`
- - China: `https://api.meraki.cn/api/v1`
- - India: `https://api.meraki.in/api/v1`
- - US Federal: `https://api.gov-meraki.com/api/v1`
-
-## Version
-
-**Current:** 3.0.0 (aligns with Dashboard API v1.69.0)
-
----
-
-*Stack analysis: 2026-04-29*
diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md
deleted file mode 100644
index 45d35748..00000000
--- a/.planning/codebase/STRUCTURE.md
+++ /dev/null
@@ -1,292 +0,0 @@
-# Codebase Structure
-
-**Analysis Date:** 2026-04-29
-
-## Directory Layout
-
-```
-meraki/
-├── __init__.py # DashboardAPI entry point (sync)
-├── _version.py # Version string
-├── config.py # Configuration constants and defaults
-├── exceptions.py # Exception classes (APIError, APIKeyError, etc.)
-├── common.py # Utility functions (validation, version checks)
-├── rest_session.py # RestSession HTTP layer (sync)
-├── response_handler.py # Response processing utilities
-├── aio/
-│ ├── __init__.py # AsyncDashboardAPI entry point (async)
-│ ├── rest_session.py # AsyncRestSession HTTP layer (async)
-│ └── api/
-│ ├── administered.py # AsyncAdministered scope
-│ ├── organizations.py # AsyncOrganizations scope
-│ ├── networks.py # AsyncNetworks scope
-│ ├── devices.py # AsyncDevices scope
-│ ├── [+ 13 more scope files]
-│ └── ...
-└── api/
- ├── __init__.py # API module init
- ├── administered.py # Administered scope
- ├── organizations.py # Organizations scope
- ├── networks.py # Networks scope
- ├── devices.py # Devices scope
- ├── appliance.py # Appliance scope
- ├── camera.py # Camera scope
- ├── cellularGateway.py # CellularGateway scope
- ├── campusGateway.py # CampusGateway scope
- ├── insight.py # Insight scope
- ├── licensing.py # Licensing scope
- ├── sensor.py # Sensor scope
- ├── sm.py # Systems Manager scope
- ├── spaces.py # Spaces scope
- ├── switch.py # Switch scope
- ├── wireless.py # Wireless scope
- ├── wirelessController.py # WirelessController scope
- └── batch/
- ├── __init__.py # Batch class aggregator
- ├── organizations.py # ActionBatchOrganizations
- ├── networks.py # ActionBatchNetworks
- ├── devices.py # ActionBatchDevices
- ├── [+ more batch scopes]
- └── ...
-
-tests/
-├── unit/
-│ ├── test_dashboard_api_init.py # DashboardAPI initialization tests
-│ ├── test_aio_rest_session.py # AsyncRestSession tests
-│ ├── test_common.py # common.py utility tests
-│ ├── test_mock_integration.py # Mock integration tests
-│ └── test_exceptions.py # Exception tests
-├── integration/
-│ ├── test_dashboard_api_python_library.py # Live API tests (requires key)
-│ ├── test_async_dashboard_api.py # Async integration tests
-│ └── conftest.py # Integration test fixtures
-└── generator/
- ├── test_generate_library_golden.py # Golden file comparison tests
- ├── test_pure_functions.py # Generator utility tests
- ├── conftest.py # Generator test fixtures
- └── golden/
- ├── meraki/api/networks.py # Expected generated output (sync)
- ├── meraki/aio/api/networks.py # Expected generated output (async)
- └── meraki/api/batch/networks.py # Expected generated output (batch)
-
-generator/
-├── generate_library.py # Main OpenAPI v2 library generator
-├── generate_library_oasv3.py # OpenAPI v3 library generator
-├── generate_snippets.py # Code snippet generator
-├── function_template.jinja2 # Template for sync operation methods
-├── async_function_template.jinja2 # Template for async operation methods
-├── batch_function_template.jinja2 # Template for batch operation methods
-├── class_template.jinja2 # Template for scope class wrapper
-├── async_class_template.jinja2 # Template for async scope class wrapper
-├── batch_class_template.jinja2 # Template for batch scope class wrapper
-├── common.py # Generator utility functions
-└── README.md # Generator documentation
-
-examples/
-├── org_wide_clients.py # Example: list all clients in org
-├── aio_org_wide_clients.py # Example: async client listing
-├── aio_ips2firewall.py # Example: async L7 firewall automation
-└── merakiApplianceVlanToL3SwitchInterfaceMigrator/
- └── ... # Example: network migration tool
-
-notebooks/
-└── Uplink preference backup and restore/
- └── ... # Jupyter notebook examples
-```
-
-## Directory Purposes
-
-**meraki/:**
-- Purpose: Main package containing synchronous SDK
-- Contains: Entry points, HTTP session, configuration, exceptions, utility functions
-- Key files: `__init__.py` (DashboardAPI), `rest_session.py` (HTTP layer), `config.py` (defaults)
-
-**meraki/api/:**
-- Purpose: Scope classes for synchronous API operations
-- Contains: 17 resource type classes (Organizations, Networks, Devices, etc.) each exposing operations from OpenAPI spec
-- Key files: `organizations.py`, `networks.py`, `devices.py` (primary scopes)
-
-**meraki/api/batch/:**
-- Purpose: Batch operation helper classes for Action Batch support
-- Contains: Specialized classes for staging batch requests without immediate execution
-- Key files: `__init__.py` (Batch aggregator), scope files mirror api/ structure
-
-**meraki/aio/:**
-- Purpose: Asynchronous SDK using asyncio/aiohttp
-- Contains: Async entry point and HTTP session, mirrors api/ structure
-- Key files: `__init__.py` (AsyncDashboardAPI), `rest_session.py` (async HTTP layer)
-
-**meraki/aio/api/:**
-- Purpose: Scope classes for asynchronous API operations
-- Contains: 17 async scope classes (AsyncOrganizations, AsyncNetworks, etc.)
-- Key files: Mirror meraki/api/ structure with Async prefix and await keywords
-
-**tests/unit/:**
-- Purpose: Unit tests for SDK internals, runnable without API key
-- Contains: DashboardAPI initialization, RestSession behavior, utilities, exceptions
-- Key files: `test_dashboard_api_init.py` (initialization tests), `test_common.py` (utility tests)
-
-**tests/integration/:**
-- Purpose: Integration tests against live Meraki API
-- Contains: Full workflows requiring valid API key and test organization
-- Key files: `test_dashboard_api_python_library.py` (sync tests), `test_async_dashboard_api.py` (async tests)
-
-**tests/generator/:**
-- Purpose: Validation of code generation from OpenAPI spec
-- Contains: Golden file comparison tests ensuring generated code matches expected output
-- Key files: `test_generate_library_golden.py` (output validation), `golden/` (expected files)
-
-**generator/:**
-- Purpose: OpenAPI spec to Python SDK code generation
-- Contains: Jinja2 templates for method/class generation, parser for OpenAPI spec
-- Key files: `generate_library.py` (OpenAPI v2), `generate_library_oasv3.py` (OpenAPI v3), `*_template.jinja2` (templates)
-
-**examples/:**
-- Purpose: Runnable example scripts demonstrating SDK usage
-- Contains: Real-world use cases like client listing, firewall automation
-- Key files: `org_wide_clients.py` (basic example), `aio_ips2firewall.py` (async example)
-
-**notebooks/:**
-- Purpose: Jupyter notebook examples for exploratory usage
-- Contains: Interactive workflows for specific tasks
-- Key files: Uplink preference backup/restore notebook
-
-## Key File Locations
-
-**Entry Points:**
-- `meraki/__init__.py`: DashboardAPI class - instantiate with api_key, exposes scope properties
-- `meraki/aio/__init__.py`: AsyncDashboardAPI class - async context manager, exposes async scope properties
-- `meraki/__main__.py`: Module runnable (if present) or package import for scripts
-
-**Configuration:**
-- `meraki/config.py`: All default constants (timeouts, retry counts, log settings, etc.)
-- `meraki/_version.py`: __version__ string (auto-generated)
-- No .env file in repository; env vars read from MERAKI_DASHBOARD_API_KEY, BE_GEO_ID, MERAKI_PYTHON_SDK_CALLER
-
-**Core Logic:**
-- `meraki/rest_session.py`: RestSession with request(), get(), post(), put(), delete(), get_pages()
-- `meraki/aio/rest_session.py`: AsyncRestSession with identical interface using aiohttp
-- `meraki/api/{scope}.py`: Scope classes (17 total) with operation methods
-- `meraki/aio/api/{scope}.py`: Async scope classes (17 total) mirroring sync structure
-
-**Request Handling:**
-- `meraki/rest_session.py`: HTTP client implementation, retry logic, rate limiting, pagination
-- `meraki/aio/rest_session.py`: Async HTTP client implementation
-- `meraki/response_handler.py`: Response processing (3xx redirect handling)
-- `meraki/common.py`: Validation functions called during initialization
-
-**Error Handling:**
-- `meraki/exceptions.py`: APIKeyError, APIError, AsyncAPIError, PythonVersionError, SessionInputError
-
-**Testing:**
-- `tests/unit/`: Mock-based tests, no API key required
-- `tests/integration/`: Live API tests, requires MERAKI_DASHBOARD_API_KEY
-- `tests/generator/`: Code generation validation against golden files
-- Golden files at `tests/generator/golden/meraki/api/networks.py`, `meraki/aio/api/networks.py`, `meraki/api/batch/networks.py`
-
-## Naming Conventions
-
-**Files:**
-- Scope resource names: camelCase with first letter lowercase (organizations.py, networkDevices.py, cellularGateway.py)
-- Test files: test_{module_under_test}.py or test_{feature}.py
-- Generated code: Classes have generated names matching OpenAPI operationId, methods match API paths
-- Templates: {context}_template.jinja2 (function_template.jinja2, async_function_template.jinja2, batch_function_template.jinja2)
-
-**Directories:**
-- Scope directories: lowercase (api/, aio/, batch/)
-- Test groupings: unit/, integration/, generator/
-- Generator artifacts: golden/ for expected outputs
-
-**Classes:**
-- Sync scopes: PascalCase (Organizations, Networks, Devices)
-- Async scopes: Async{SyncName} (AsyncOrganizations, AsyncNetworks, AsyncDevices)
-- Batch scopes: ActionBatch{SyncName} (ActionBatchOrganizations, ActionBatchNetworks)
-- Main classes: DashboardAPI (sync), AsyncDashboardAPI (async)
-- Exceptions: {Context}Error (APIKeyError, APIError, AsyncAPIError)
-- Sessions: RestSession (sync), AsyncRestSession (async)
-
-**Methods:**
-- API operations: camelCase matching OpenAPI operationId (getOrganizations, createNetwork, updateDevice)
-- Private methods: underscore prefix (_get_pages_iterator, _get_pages_legacy, _session)
-- Properties: snake_case (use_iterator_for_get_pages property)
-- Dunder methods: __init__, __repr__, __str__, __async_enter__, __async_exit__
-
-**Variables:**
-- Module-level constants: SCREAMING_SNAKE_CASE (API_KEY_ENVIRONMENT_VARIABLE, DEFAULT_BASE_URL)
-- Instance attributes: underscore prefix + snake_case (self._api_key, self._base_url, self._session)
-- Local variables: snake_case (params, resource, metadata, total_pages)
-- Generator context: camelCase matching OpenAPI (perPage, startingAfter, endingBefore, organizationId)
-
-## Where to Add New Code
-
-**New API Scope (when OpenAPI spec adds resource):**
-- Sync implementation: `meraki/api/{scope_name}.py` with class {ScopeName} inheriting from object, methods call self._session.{verb}()
-- Async implementation: `meraki/aio/api/{scope_name}.py` with class Async{ScopeName}, methods call await self._session.{verb}()
-- Batch helper: `meraki/api/batch/{scope_name}.py` with class ActionBatch{ScopeName} (stateless helper)
-- Register in: `meraki/__init__.py` (add import and self.{scope_name} property), `meraki/aio/__init__.py` (async equivalent)
-- Pattern: Follow existing scope file structure (getResource, createResource, updateResource, deleteResource methods)
-
-**New Operation (when OpenAPI spec adds endpoint):**
-- Add method to existing scope class in `meraki/api/{scope}.py` and `meraki/aio/api/{scope}.py`
-- Cannot manually add; operations are auto-generated from OpenAPI spec using generator/
-- If manually modifying for testing: follow kwargs.update(locals()), metadata dict, resource path, params extraction pattern
-- Register operation in batch scope if applicable: `meraki/api/batch/{scope}.py`
-
-**New Utility Function:**
-- Shared helpers: `meraki/common.py` (Python checks, validation)
-- Response processing: `meraki/response_handler.py` (HTTP response handling)
-- Exception handling: Add new exception class to `meraki/exceptions.py`
-
-**New Tests:**
-- Unit tests: `tests/unit/test_{feature}.py` with mocked RestSession
-- Integration tests: `tests/integration/test_{feature}.py` with live API calls
-- Generator tests: `tests/generator/test_{aspect}.py` with golden file comparisons
-- Test fixtures: Add to `tests/{category}/conftest.py` (pytest fixtures)
-
-**New Examples:**
-- Example scripts: `examples/{use_case}.py` as runnable Python scripts
-- Jupyter notebooks: `notebooks/{use_case}/` directory with .ipynb file
-- README: Document in examples/README.md and top-level README.md
-
-## Special Directories
-
-**meraki/api/batch/:**
-- Purpose: Batch operation helpers
-- Generated: Partially (method stubs auto-generated)
-- Committed: Yes, checked in to version control
-- Special: Classes are stateless, only build request dicts, do not execute HTTP calls
-
-**tests/generator/golden/:**
-- Purpose: Expected output from code generation
-- Generated: Auto-generated by running generator
-- Committed: Yes, checked in for golden file comparison
-- Special: Used as test fixtures; when generator output matches golden files, tests pass
-
-stitute:
-- Purpose: Cache files
-- Generated: Yes
-- Committed: No (.gitignore excludes)
-- Special: Safe to delete; will be regenerated on next build/test
-
-**.venv/:**
-- Purpose: Python virtual environment
-- Generated: Created by `uv sync`
-- Committed: No (.gitignore excludes)
-- Special: Development only; production uses different installation method
-
-## Generated vs Manual Code
-
-**Generated (from OpenAPI spec):**
-- All scope operation methods: Organizations.getOrganizations(), Networks.createNetwork(), etc.
-- Scope class definitions and parameters
-- Batch operation stubs
-- Generated via `python generator/generate_library_oasv3.py`
-
-**Manual (hand-written):**
-- RestSession HTTP layer: `meraki/rest_session.py`, `meraki/aio/rest_session.py`
-- DashboardAPI initialization: `meraki/__init__.py`, `meraki/aio/__init__.py`
-- Exception classes: `meraki/exceptions.py`
-- Configuration constants: `meraki/config.py`
-- Utility functions: `meraki/common.py`
-- Tests: All test files
-- Generator itself: `generator/*.py`
diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md
deleted file mode 100644
index a0a68f62..00000000
--- a/.planning/codebase/TESTING.md
+++ /dev/null
@@ -1,251 +0,0 @@
-# Testing Patterns
-
-**Analysis Date:** 2026-04-29
-
-## Test Framework
-
-**Runner:**
-- pytest 8.3.5 through 9.x
-- Config: `pyproject.toml` under `[tool.pytest.ini_options]`
-- Test paths: `tests/unit` (unit tests only; excludes `tests/generator`)
-
-**Assertion Library:**
-- pytest's built-in assertions and `assert` statements
-- No separate assertion library; standard pytest patterns
-
-**Run Commands:**
-```bash
-pytest # Run all unit tests
-pytest -v # Verbose output
-pytest tests/unit/ # Run unit tests only
-pytest -k "test_name" # Run specific test
-pytest --cov=meraki # Run with coverage
-pytest --cov=meraki --cov-report=html # Generate HTML coverage report
-pytest -m integration # Run integration tests (if marked)
-```
-
-**Coverage:**
-- Tool: pytest-cov
-- Requirement: 90% minimum (configured in `pyproject.toml` as `fail_under = 90`)
-- Excluded from coverage: `meraki/api/*` and `meraki/aio/api/*` (generated files) and `meraki/aio/__init__.py`
-- Report shows missing lines: `show_missing = true`
-
-## Test File Organization
-
-**Location:**
-- Co-located pattern: test files in `tests/` directory mirror source structure
-- Unit tests: `tests/unit/`
-- Integration tests: `tests/integration/`
-- Generator tests: `tests/generator/` (not run with default pytest)
-
-**Naming:**
-- Files: `test_*.py` prefix pattern (pytest discovery)
-- Example: `test_common.py`, `test_rest_session.py`, `test_exceptions.py`, `test_aio_rest_session.py`
-
-**Structure:**
-```
-tests/
-├── unit/
-│ ├── test_common.py
-│ ├── test_dashboard_api_init.py
-│ ├── test_exceptions.py
-│ ├── test_mock_integration.py
-│ ├── test_response_handler.py
-│ ├── test_rest_session.py
-│ └── test_aio_rest_session.py
-├── integration/
-│ ├── conftest.py (pytest_addoption for --apikey and --o flags)
-│ ├── test_async_dashboard_api.py
-│ └── test_dashboard_api_python_library.py
-└── generator/
- ├── conftest.py
- └── test_pure_functions.py
-```
-
-## Test Structure
-
-**Suite Organization:**
-- Test classes group related functionality: `class TestCheckPythonVersion:`, `class TestValidateUserAgent:`, `class TestAPIKeyError:` (file `tests/unit/test_common.py:16-30`)
-- One test method per assertion focus: `def test_valid_version(self):`, `def test_too_old_raises(self):`, `def test_python2_raises(self):`
-- Async tests use `async def test_*` pattern with pytest-asyncio
-- Async session fixture patches dependencies and creates mock client: (file `tests/unit/test_aio_rest_session.py:57-84`)
-
-**Patterns:**
-- Setup: `@pytest.fixture` decorator for reusable test fixtures
-- Example fixture for sync RestSession: (file `tests/unit/test_rest_session.py:10-32`)
- ```python
- @pytest.fixture
- def session():
- with patch("meraki.rest_session.check_python_version"):
- s = RestSession(
- logger=None,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- # ... all required parameters
- )
- return s
- ```
-- Teardown: No explicit teardown; fixtures auto-clean when test ends
-- Assertion pattern: `assert` statements with descriptive conditions: `assert "TestApp TestVendor" in result`
-
-## Mocking
-
-**Framework:** `unittest.mock` from Python standard library
-
-**Patterns:**
-```python
-from unittest.mock import MagicMock, patch, AsyncMock
-
-# Patch function/class
-@patch("meraki.rest_session.check_python_version")
-def test_something(self, mock_check):
- s = RestSession(...)
-
-# Patch with context manager
-with patch("meraki.rest_session.check_python_version"):
- from meraki.aio.rest_session import AsyncRestSession
- s = AsyncRestSession(...)
-
-# Create mock response
-resp = MagicMock(spec=requests.Response)
-resp.status_code = 200
-resp.reason = "OK"
-resp.headers = {}
-resp.content = b'{"ok":true}'
-resp.links = {}
-resp.json.return_value = {"ok": True}
-resp.close = MagicMock()
-```
-(file `tests/unit/test_rest_session.py:39-55`)
-
-**Async Mocking:**
-- AsyncMock for async methods: `AsyncMock()` returns awaitable
-- Wrapper class `_AwaitableValue` (file `tests/unit/test_aio_rest_session.py:10-50`) makes values both synchronously usable and awaitable for error handling compatibility
-- Patch `aiohttp.ClientSession`: (file `tests/unit/test_aio_rest_session.py:59-63`)
-
-**What to Mock:**
-- External dependencies: `requests.Response`, `aiohttp.ClientSession`, platform functions
-- Functions that check system state: `platform.python_version_tuple()`
-- Network calls: HTTP session methods
-- Do NOT mock the code being tested (the actual session class)
-
-**What NOT to Mock:**
-- The actual session classes being tested
-- Utility functions like `encode_params()`, `validate_base_url()`
-- Exception classes (let them construct naturally)
-- Local utility functions used by the code under test
-
-## Fixtures and Factories
-
-**Test Data:**
-- Helper method pattern: `def _metadata(operation="getOrganizations", tags=None):` (file `tests/unit/test_rest_session.py:35-36`)
-- Mock response factory: `def _mock_response(status_code=200, ...)` with parameter defaults (file `tests/unit/test_rest_session.py:39-55`)
-- pytest fixture for session: creates session with mocked dependencies (file `tests/unit/test_rest_session.py:10-32`)
-- Fixture scope: default (function scope); creates fresh instance per test
-
-**Location:**
-- Fixtures defined at module level or in fixture file
-- Helper methods defined as class methods with `_` prefix: `def _make_response(self, ...)`
-- Shared fixtures can be moved to `conftest.py` (see `tests/integration/conftest.py`)
-
-**Example fixture:**
-```python
-@pytest.fixture
-def session():
- with patch("meraki.rest_session.check_python_version"):
- s = RestSession(
- logger=None,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- # ... all parameters
- )
- return s
-```
-
-## Test Types
-
-**Unit Tests:**
-- Scope: Test individual functions and methods in isolation
-- Location: `tests/unit/`
-- Examples: `test_common.py` tests validation functions, `test_exceptions.py` tests exception classes
-- Pattern: Mock external dependencies, test internal logic
-- Coverage requirement: 90% minimum
-
-**Integration Tests:**
-- Scope: Test multiple components working together; typically requires real API key
-- Location: `tests/integration/`
-- Execution: Optional; requires `--apikey` parameter
-- Example: `test_dashboard_api_python_library.py` makes real API calls
-- CLI pattern: `pytest tests/integration/ --apikey=YOUR_KEY`
-
-**E2E Tests:**
-- Not used; integration tests serve as end-to-end validation
-
-**Generator Tests:**
-- Location: `tests/generator/`
-- Purpose: Test code generation templates and functions
-- Pattern: Pure function tests with fixtures
-- Example: `test_pure_functions.py` tests documentation URL generation, pagination generation (file `tests/generator/test_pure_functions.py:1-42`)
-
-## Async Testing
-
-**Pattern:**
-```python
-@pytest.mark.asyncio
-async def test_async_method(self):
- # test code
- await some_async_call()
-```
-
-**Async Session Creation:**
-```python
-@pytest.fixture
-async def async_session():
- with (
- patch("meraki.aio.rest_session.check_python_version"),
- patch("aiohttp.ClientSession") as mock_client,
- ):
- mock_client.return_value = MagicMock()
- from meraki.aio.rest_session import AsyncRestSession
- s = AsyncRestSession(...)
- return s
-```
-(file `tests/unit/test_aio_rest_session.py:57-84`)
-
-**pytest-asyncio Configuration:**
-- `asyncio_mode = "auto"` in `pyproject.toml` (line 56)
-- Automatically runs async tests without needing explicit markers in simple cases
-
-## Error Testing
-
-**Pattern:**
-```python
-def test_invalid_caller_raises(self):
- with pytest.raises(SessionInputError):
- validate_user_agent("", "invalid format!!!")
-
-def test_too_old_raises(self, mock_ver):
- with pytest.raises(PythonVersionError):
- check_python_version()
-```
-(file `tests/unit/test_common.py:42-44`, `tests/unit/test_common.py:22-24`)
-
-**Exception Assertion:**
-- Use `pytest.raises(ExceptionType)` context manager
-- Verify exception message/attributes: `err.message`, `err.status`, `err.reason`
-- Test both exception raising and exception attribute values (file `tests/unit/test_exceptions.py:64-72`)
-
-## Coverage Gaps and Strategy
-
-**Excluded from Coverage:**
-- Generated API endpoint files: `meraki/api/*` and `meraki/aio/api/*` (auto-generated; coverage would be fragile)
-- Async init files: `meraki/aio/__init__.py`
-
-**Testing Strategy:**
-- Unit test the non-generated code: session management, error handling, utilities
-- Integration tests for actual API calls to validate end-to-end flow
-- Generator tests validate template functions work correctly
-
----
-
-*Testing analysis: 2026-04-29*
diff --git a/.planning/milestones/v1.0-REQUIREMENTS.md b/.planning/milestones/v1.0-REQUIREMENTS.md
deleted file mode 100644
index 5bf3d3a7..00000000
--- a/.planning/milestones/v1.0-REQUIREMENTS.md
+++ /dev/null
@@ -1,88 +0,0 @@
-# Requirements Archive: v1.0 OASv3 Generator
-
-**Archived:** 2026-04-30
-**Status:** SHIPPED
-
-For current requirements, see `.planning/REQUIREMENTS.md`.
-
----
-
-# Requirements: Meraki Dashboard API Python SDK
-
-**Defined:** 2026-04-29
-**Core Value:** Developers can interact with every Meraki Dashboard API endpoint through a well-typed, well-documented Python client that stays current with the live API spec.
-
-## v3.1.0 Requirements
-
-Requirements for OASv3 generator milestone. Each maps to roadmap phases.
-
-### Parsing
-
-- [ ] **PARSE-01**: Generator resolves `$ref` JSON pointers with cycle protection and caching
-- [ ] **PARSE-02**: Generator parses `requestBody` for application/json, multipart/form-data, and application/octet-stream
-- [ ] **PARSE-03**: Generator handles `nullable: true` with `| None` type annotations and docstring notes
-- [ ] **PARSE-04**: Generator inherits path-level parameters, operation overrides on name+in match
-- [ ] **PARSE-05**: Generator resolves `oneOf` schemas as "string or object" with sub-property documentation
-- [ ] **PARSE-06**: Generator respects array param `style`/`explode` attributes (default: form + explode:true)
-
-### Code Generation
-
-- [ ] **GEN-01**: Generator produces sync/async/batch modules matching v2 output structure
-- [ ] **GEN-02**: Generated methods use explicit param construction instead of `kwargs.update(locals())`
-- [ ] **GEN-03**: Generator produces `.pyi` type stubs with full signatures via `--stubs` flag
-- [ ] **GEN-04**: Generator handles `x-batchable-actions` for batch class generation
-- [ ] **GEN-05**: CLI accepts same args as v2 (`-h`, `-o`, `-k`, `-v`, `-a`, `-g`) and fetches v3 spec
-
-### Testing & CI
-
-- [ ] **TEST-01**: Synthetic v3 fixture exercises all v3-specific features ($ref, requestBody, oneOf, nullable, multipart, path-level params)
-- [ ] **TEST-02**: Golden-file tests validate v3 generator output for sync, async, and batch modules
-- [ ] **TEST-03**: CI workflow runs semantic diff of v2 vs v3 generator output on live spec
-
-## Future Requirements
-
-### Deprecation Cycle
-
-- **DEP-01**: Rename v2 generator to `generate_library_oasv2.py` with deprecation warning
-- **DEP-02**: Promote v3 generator to `generate_library.py` (new default)
-- **DEP-03**: Remove v2 generator after one minor version cycle with no rollbacks
-
-## Out of Scope
-
-| Feature | Reason |
-|---------|--------|
-| Modifying the v2 generator | Kept for rollback until parity gate passes |
-| Changing runtime SDK behavior | rest_session, pagination, etc. are stable |
-| OpenAPI 3.1 support | Only 3.0.1 `nullable: true` style, not 3.1 `type: [string, null]` |
-| Rewriting Jinja2 templates from scratch | Reuse existing, extend as needed |
-| Pydantic model generation | Over-engineering; dict-based params match existing SDK contract |
-| Client-side request validation | Adds overhead, API validates server-side |
-| OAuth helper generation | Not part of Meraki auth model |
-
-## Traceability
-
-| Requirement | Phase | Status |
-|-------------|-------|--------|
-| PARSE-01 | Phase 1 | Pending |
-| PARSE-02 | Phase 1 | Pending |
-| PARSE-03 | Phase 2 | Pending |
-| PARSE-04 | Phase 2 | Pending |
-| PARSE-05 | Phase 2 | Pending |
-| PARSE-06 | Phase 2 | Pending |
-| GEN-01 | Phase 3 | Pending |
-| GEN-02 | Phase 3 | Pending |
-| GEN-03 | Phase 4 | Pending |
-| GEN-04 | Phase 3 | Pending |
-| GEN-05 | Phase 3 | Pending |
-| TEST-01 | Phase 5 | Pending |
-| TEST-02 | Phase 5 | Pending |
-| TEST-03 | Phase 5 | Pending |
-
-**Coverage:**
-- v3.1.0 requirements: 14 total
-- Mapped to phases: 14
-- Unmapped: 0
-
----
-*Requirements defined: 2026-04-29*
-*Last updated: 2026-04-29 after roadmap creation*
diff --git a/.planning/milestones/v1.0-ROADMAP.md b/.planning/milestones/v1.0-ROADMAP.md
deleted file mode 100644
index 764fcec8..00000000
--- a/.planning/milestones/v1.0-ROADMAP.md
+++ /dev/null
@@ -1,103 +0,0 @@
-# Roadmap: Meraki Dashboard API Python SDK
-
-## Overview
-
-Build a modular OASv3 generator that replaces the abandoned monolithic attempt, following v2's proven parse-organize-render architecture. Parser layer normalizes OASv3 features ($ref, requestBody, oneOf, nullable) into v2-compatible param dicts for template reuse. Five phases deliver foundation parsers, unified parameter handling, module generation, type stubs, and comprehensive testing with CI drift detection.
-
-## Phases
-
-**Phase Numbering:**
-- Integer phases (1, 2, 3): Planned milestone work
-- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
-
-Decimal phases appear between their surrounding integers in numeric order.
-
-- [ ] **Phase 1: Parser Foundation** - Core v3 parsing with $ref resolution, caching, and requestBody handling
-- [ ] **Phase 2: Unified Parameter Parser** - Path-level inheritance, nullable, oneOf, and array serialization
-- [ ] **Phase 3: Generation Integration** - Module generation, batch actions, and CLI entry point
-- [ ] **Phase 4: Type Stubs** - .pyi generation via Jinja2 for static analysis
-- [ ] **Phase 5: Testing & CI** - Golden files, v2 vs v3 drift detection, and integration tests
-
-## Phase Details
-
-### Phase 1: Parser Foundation
-**Goal**: Core v3 parsing functions normalize $ref resolution and requestBody handling
-**Depends on**: Nothing (first phase)
-**Requirements**: PARSE-01, PARSE-02
-**Success Criteria** (what must be TRUE):
- 1. Generator resolves $ref JSON pointers with cycle detection (no stack overflow on circular schemas)
- 2. Generator caches resolved $refs (no O(n^2) performance degradation)
- 3. Generator parses requestBody for application/json, multipart/form-data, and application/octet-stream
- 4. Parser functions return normalized params dict matching v2 format (enables template reuse)
-**Plans**: 2 plans
-Plans:
-- [x] 01-01-PLAN.md: $ref resolution with caching and cycle detection (TDD)
-- [x] 01-02-PLAN.md: requestBody parsing for json, multipart, octet-stream (TDD)
-
-### Phase 2: Unified Parameter Parser
-**Goal**: Unified parse_params_v3 function merges path, query, and body parameters with OASv3 features
-**Depends on**: Phase 1
-**Requirements**: PARSE-03, PARSE-04, PARSE-05, PARSE-06
-**Success Criteria** (what must be TRUE):
- 1. Generator inherits path-level parameters into operations (operation params override on name match)
- 2. Generator adds | None to type annotations for nullable: true parameters
- 3. Generator documents oneOf query params as "string or object" (not generic "object")
- 4. Golden-file test with synthetic v3 fixture validates parser output format
-**Plans**: 2 plans
-Plans:
-- [x] 02-01-PLAN.md: TDD parse_params_v3 with path inheritance, nullable, oneOf, style/explode
-- [x] 02-02-PLAN.md: Golden-file snapshot test for output contract validation
-
-### Phase 3: Generation Integration
-**Goal**: v3 generator produces sync, async, and batch modules from OASv3 spec
-**Depends on**: Phase 2
-**Requirements**: GEN-01, GEN-02, GEN-04, GEN-05
-**Success Criteria** (what must be TRUE):
- 1. Generator produces meraki/api/, meraki/aio/api/, and meraki/api/batch/ modules matching v2 structure
- 2. Generated methods use explicit param construction (not kwargs.update(locals()))
- 3. Generator handles x-batchable-actions for batch class generation (298 batch endpoints)
- 4. CLI accepts same args as v2 and fetches v3 spec with ?version=3 param
-**Plans**: 2 plans
-Plans:
-- [x] 03-01-PLAN.md: Core v3 generator module (sync/async/batch generation, explicit params, batch action matching)
-- [x] 03-02-PLAN.md: CLI entry point with v3 spec fetch and integration tests
-
-### Phase 4: Type Stubs
-**Goal**: Generator produces .pyi type stubs via Jinja2 for static analysis
-**Depends on**: Phase 3
-**Requirements**: GEN-03
-**Success Criteria** (what must be TRUE):
- 1. Generator creates .pyi files with full method signatures when --stubs flag passed
- 2. Package includes py.typed marker for PEP 561 compliance
- 3. Type stubs reflect nullable (str | None) and oneOf (Union[str, dict]) semantics
-**Plans**: 2 plans
-Plans:
-- [x] 04-01-PLAN.md: TDD stub generation module with typed signatures (nullable, oneOf)
-- [x] 04-02-PLAN.md: CLI --stubs flag integration and py.typed marker
-
-### Phase 5: Testing & CI
-**Goal**: Comprehensive test suite and CI drift detection validate v3 generator correctness
-**Depends on**: Phase 4
-**Requirements**: TEST-01, TEST-02, TEST-03
-**Success Criteria** (what must be TRUE):
- 1. Synthetic v3 fixture exercises all v3-specific features ($ref with cycles, requestBody, oneOf, nullable, multipart, path-level params)
- 2. Golden-file tests validate v3 generator output for sync, async, and batch modules (semantic correctness, not byte-for-byte v2 match)
- 3. CI workflow runs semantic diff of v2 vs v3 generator output on live spec (params, types, structure, not text diff)
-**Plans**: 3 plans
-Plans:
-- [x] 05-01-PLAN.md: Comprehensive synthetic v3 fixture with coverage assertion tests
-- [x] 05-02-PLAN.md: Golden-file tests for v3 generator output (sync, async, batch)
-- [x] 05-03-PLAN.md: CI semantic diff workflow for v2/v3 drift detection
-
-## Progress
-
-**Execution Order:**
-Phases execute in numeric order: 1 > 2 > 3 > 4 > 5
-
-| Phase | Plans Complete | Status | Completed |
-|-------|----------------|--------|-----------|
-| 1. Parser Foundation | 2/2 | Complete | 2026-04-30 |
-| 2. Unified Parameter Parser | 2/2 | Complete | 2026-04-30 |
-| 3. Generation Integration | 2/2 | Complete | 2026-04-30 |
-| 4. Type Stubs | 2/2 | Complete | 2026-04-30 |
-| 5. Testing & CI | 0/3 | Planning complete | - |
diff --git a/.planning/phases/06-generator-swap/06-01-PLAN.md b/.planning/phases/06-generator-swap/06-01-PLAN.md
deleted file mode 100644
index 76a684a7..00000000
--- a/.planning/phases/06-generator-swap/06-01-PLAN.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-phase: 06-generator-swap
-plan: 01
-type: execute
-wave: 1
-depends_on: []
-files_modified:
- - generator/generate_library.py
- - generator/generate_library_v3.py
- - generator/generate_library_oasv2.py
- - tests/generator/test_generate_library_v3.py
-autonomous: true
-requirements: [DEP-01, DEP-02]
-must_haves:
- truths:
- - Running python generator/generate_library.py executes v3 generator code
- - Running python generator/generate_library_oasv2.py emits deprecation warning
- - Both generators produce valid SDK output
- - Tests pass with updated imports
- artifacts:
- - path: generator/generate_library.py
- provides: Default v3 generator entry point
- min_lines: 600
- contains: "parser_v3"
- - path: generator/generate_library_oasv2.py
- provides: Deprecated v2 generator with warning
- min_lines: 800
- contains: "DeprecationWarning"
- - path: tests/generator/test_generate_library_v3.py
- provides: Updated test imports
- exports: ["import generate_library"]
- key_links:
- - from: generator/generate_library.py
- to: parser_v3
- via: import statement
- pattern: "from parser_v3 import"
- - from: generator/generate_library_oasv2.py
- to: warnings module
- via: deprecation call
- pattern: "warnings\\.warn.*DeprecationWarning"
- - from: tests/generator/test_generate_library_v3.py
- to: generator/generate_library.py
- via: import statement
- pattern: "import generate_library"
----
-
-
-Promote v3 generator to default entry point, deprecate v2 generator.
-
-Purpose: Make v3 parser the production default while preserving v2 for one version cycle.
-Output: Renamed files with deprecation warning in v2, updated test imports.
-
-
-
-@C:\Users\jkuchta\.claude\get-shit-done\workflows\execute-plan.md
-@C:\Users\jkuchta\.claude\get-shit-done\templates\summary.md
-
-
-
-@.planning/PROJECT.md
-@.planning/ROADMAP.md
-@.planning/STATE.md
-@.planning/REQUIREMENTS.md
-@.planning/phases/06-generator-swap/06-CONTEXT.md
-
-
-
-
-
- Task 1: Swap generator files and add deprecation warning
-
- - generator/generate_library.py (full file)
- - generator/generate_library_v3.py (full file)
-
-
- generator/generate_library.py
- generator/generate_library_v3.py
- generator/generate_library_oasv2.py
-
-
-Rename current generate_library.py to generate_library_oasv2.py using git mv. Add deprecation warning at top of generate_library_oasv2.py after imports:
-
-```python
-import warnings
-warnings.warn(
- "generate_library_oasv2.py is deprecated and will be removed in v1.2. Use generate_library.py instead.",
- DeprecationWarning,
- stacklevel=2
-)
-```
-
-Then rename generate_library_v3.py to generate_library.py using git mv. Remove imports from generate_library.py (line 14-20) that reference the old generate_library module since it's now this file.
-
-
- python -c "import warnings; warnings.simplefilter('always', DeprecationWarning); exec(open('generator/generate_library_oasv2.py').read())"
-
-
- - generator/generate_library_oasv2.py exists and emits DeprecationWarning when imported
- - generator/generate_library.py exists and contains parser_v3 import
- - generator/generate_library_v3.py no longer exists
- - No circular imports in generate_library.py
-
- File swap complete, deprecation warning working, no import errors.
-
-
-
- Task 2: Update test imports
-
- - tests/generator/test_generate_library_v3.py (full file)
-
-
- tests/generator/test_generate_library_v3.py
-
-
-Replace all occurrences of `generate_library_v3` with `generate_library` in test_generate_library_v3.py. This includes:
-- Import statement (line 41, 56)
-- Patch targets (line 45, 60)
-- Module references in test functions
-
-Do not rename the test file itself (it can still be called test_generate_library_v3.py for now).
-
-
- python -m pytest tests/generator/test_generate_library_v3.py -v
-
-
- - All test imports reference generate_library (not generate_library_v3)
- - All patch decorators target generate_library module
- - All tests pass
- - Test file references correct module name in import and patch statements
-
- Test imports updated, pytest runs clean.
-
-
-
-
-
-1. Run `python generator/generate_library.py -h` (should show v3 help, no errors)
-2. Run `python generator/generate_library_oasv2.py -h` (should show deprecation warning, then help)
-3. Run `python -m pytest tests/generator/test_generate_library_v3.py -v` (all tests pass)
-4. Check git status shows three renames: generate_library.py → generate_library_oasv2.py, generate_library_v3.py → generate_library.py, and modified test file
-
-
-
-- [ ] `python generator/generate_library.py` uses v3 parser (no errors)
-- [ ] `python generator/generate_library_oasv2.py` emits DeprecationWarning
-- [ ] Tests pass with new import paths
-- [ ] No broken imports or circular dependencies
-- [ ] Both generators produce valid output when run
-
-
-
diff --git a/.planning/phases/06-generator-swap/06-01-SUMMARY.md b/.planning/phases/06-generator-swap/06-01-SUMMARY.md
deleted file mode 100644
index 5ded93bb..00000000
--- a/.planning/phases/06-generator-swap/06-01-SUMMARY.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-phase: 06-generator-swap
-plan: 01
-subsystem: generator
-tags: [deprecation, file-rename, imports]
-dependency_graph:
- requires: [05-03]
- provides: [v3-default-entry]
- affects: [generator-entry, test-imports]
-tech_stack:
- added: []
- patterns: [deprecation-warning, import-redirect]
-key_files:
- created:
- - generator/generate_library_oasv2.py
- modified:
- - generator/generate_library.py
- - generator/parser_v3.py
- - generator/generate_stubs.py
- - tests/generator/test_generate_library_v3.py
- deleted:
- - generator/generate_library_v3.py
-decisions:
- - Import chain redirected through oasv2 module to avoid circular dependencies
- - Deprecation warning fires on module import rather than function call
- - Test file retains v3 naming for continuity
-metrics:
- tasks_completed: 2
- tasks_total: 2
- duration_minutes: 8
- files_modified: 5
- completed_date: 2026-04-30
----
-
-# Phase 06 Plan 01: Generator Swap Summary
-
-v3 generator promoted to default entry point, v2 deprecated with warning.
-
-## What Was Done
-
-Renamed v2 generator to `generate_library_oasv2.py` with DeprecationWarning, promoted v3 generator to `generate_library.py` as production default. Updated import chains in parser_v3.py and generate_stubs.py to reference oasv2 module, preventing circular imports. Test suite updated to import from new default module name.
-
-## Tasks Completed
-
-| Task | Name | Commit | Key Changes |
-|------|------|--------|-------------|
-| 1 | Swap generator files and add deprecation | 4ac836c | Renamed v2→oasv2, v3→default, added warning, fixed imports |
-| 2 | Update test imports | b8d9139 | Changed generate_library_v3→generate_library in tests |
-
-## Deviations from Plan
-
-**1. [Rule 3 - Blocking] Fixed circular import**
-- **Found during:** Task 1 verification
-- **Issue:** generate_library.py imported from parser_v3.py, parser_v3.py imported from generate_library.py
-- **Fix:** Updated parser_v3.py and generate_stubs.py to import from generate_library_oasv2 instead
-- **Files modified:** generator/parser_v3.py, generator/generate_stubs.py
-- **Commit:** 4ac836c
-
-## Verification Results
-
-All plan verification steps passed:
-
-1. ✓ `python generator/generate_library.py -h` shows v3 help (no errors)
-2. ✓ `python generator/generate_library_oasv2.py -h` emits DeprecationWarning
-3. ✓ `python -m pytest tests/generator/test_generate_library_v3.py -v` passes (16/16 tests)
-4. ✓ Git history shows correct renames and modifications
-
-## Output Artifacts
-
-- **generator/generate_library.py**: Default v3 generator entry point (631 lines)
-- **generator/generate_library_oasv2.py**: Deprecated v2 generator with warning (816 lines)
-- **tests/generator/test_generate_library_v3.py**: Updated test imports (213 lines)
-
-## Known Stubs
-
-None. All functionality is wired and operational.
-
-## Self-Check: PASSED
-
-**Created files:**
-- FOUND: generator/generate_library_oasv2.py
-
-**Modified files:**
-- FOUND: generator/generate_library.py
-- FOUND: generator/parser_v3.py
-- FOUND: generator/generate_stubs.py
-- FOUND: tests/generator/test_generate_library_v3.py
-
-**Commits:**
-- FOUND: 4ac836c
-- FOUND: b8d9139
-
-All files and commits verified present.
diff --git a/.planning/phases/06-generator-swap/06-CONTEXT.md b/.planning/phases/06-generator-swap/06-CONTEXT.md
deleted file mode 100644
index 47bb5fbd..00000000
--- a/.planning/phases/06-generator-swap/06-CONTEXT.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# Phase 6: Generator Swap - Context
-
-**Gathered:** 2026-04-30
-**Status:** Ready for planning
-**Mode:** Auto-generated (infrastructure phase)
-
-
-## Phase Boundary
-
-Rename v2 generator to generate_library_oasv2.py with deprecation warning, promote v3 generator to generate_library.py as the new default entry point.
-
-
-
-
-## Implementation Decisions
-
-### Claude's Discretion
-All implementation choices are at Claude's discretion. Key constraints:
-
-- `generate_library.py` must become v3 generator (copy/move generate_library_v3.py content)
-- `generate_library_oasv2.py` must be the old v2 generator (rename generate_library.py)
-- Deprecation warning on v2: `warnings.warn("generate_library_oasv2.py is deprecated, use generate_library.py", DeprecationWarning)`
-- Both generators must still work after the swap
-- Tests must still pass
-
-
-
-
-## Existing Code Insights
-
-### Files to swap
-- `generator/generate_library.py` (current v2, 800+ lines) -> `generator/generate_library_oasv2.py`
-- `generator/generate_library_v3.py` (current v3, 630 lines) -> `generator/generate_library.py`
-
-### Integration Points
-- Tests reference `generate_library_v3.py` in imports
-- CI workflows may reference `generate_library.py`
-- `generate_library.py` is called from project scripts
-
-
-
-
-## Specific Ideas
-
-No specific requirements beyond the swap.
-
-
-
-
-## Deferred Ideas
-
-None.
-
-
diff --git a/.planning/phases/07-legacy-cleanup/07-CONTEXT.md b/.planning/phases/07-legacy-cleanup/07-CONTEXT.md
deleted file mode 100644
index 748ef0d1..00000000
--- a/.planning/phases/07-legacy-cleanup/07-CONTEXT.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Phase 7: Legacy Cleanup - Context
-
-**Gathered:** 2026-04-30
-**Status:** Ready for planning
-**Mode:** Auto-generated (infrastructure phase)
-
-
-## Phase Boundary
-
-Remove abandoned generate_library_oasv3.py, update all imports and CI workflows referencing old filenames.
-
-
-
-
-## Implementation Decisions
-
-### Claude's Discretion
-All implementation choices are at Claude's discretion. Key constraints:
-
-- Delete `generator/generate_library_oasv3.py` (dead code, abandoned monolithic v3 attempt)
-- Update any CI workflows referencing old generator filenames
-- Update any documentation referencing old filenames
-- Ensure all internal imports use correct current filenames
-
-
-
-
-## Existing Code Insights
-
-### Files to remove
-- `generator/generate_library_oasv3.py` (abandoned v3 attempt, not used by anything)
-
-### References to update
-- Check .github/workflows/ for references to generate_library_v3.py or generate_library_oasv3.py
-- Check scripts/semantic_diff_v2_v3.py for old references
-- Check any README or docs referencing old filenames
-
-
-
-
-## Specific Ideas
-
-None.
-
-
-
-
-## Deferred Ideas
-
-None.
-
-
diff --git a/.planning/quick/260430-kti-create-integration-tests-based-on-exampl/260430-kti-PLAN.md b/.planning/quick/260430-kti-create-integration-tests-based-on-exampl/260430-kti-PLAN.md
deleted file mode 100644
index 8ca03039..00000000
--- a/.planning/quick/260430-kti-create-integration-tests-based-on-exampl/260430-kti-PLAN.md
+++ /dev/null
@@ -1,129 +0,0 @@
----
-phase: quick
-plan: 01
-type: execute
-wave: 1
-depends_on: []
-files_modified:
- - tests/integration/test_pagination_iterator.py
- - tests/integration/test_async_pagination_iterator.py
- - tests/integration/test_org_wide_workflows.py
-autonomous: true
-must_haves:
- truths:
- - "Sync pagination iterator yields same networks as legacy mode"
- - "Async pagination iterator yields same networks as legacy mode"
- - "Multi-endpoint org-wide workflow completes (orgs -> networks -> clients)"
- - "Async concurrent client fetching works via asyncio.as_completed"
- - "getOrganizationApiRequests returns records with expected fields"
- artifacts:
- - path: "tests/integration/test_pagination_iterator.py"
- provides: "Sync pagination + API requests log tests"
- - path: "tests/integration/test_async_pagination_iterator.py"
- provides: "Async pagination iterator tests"
- - path: "tests/integration/test_org_wide_workflows.py"
- provides: "Sync and async org-wide client workflow tests"
----
-
-
-Create integration tests covering the SDK's pagination iterator (sync+async), org-wide multi-endpoint workflows (sync+async), and API requests log endpoint.
-
-Purpose: Validate SDK machinery (pagination modes, async iteration, concurrent fetching) against live API.
-Output: Three new test files in tests/integration/
-
-
-
-@tests/integration/conftest.py
-@tests/integration/test_async_dashboard_api.py
-@tests/integration/test_dashboard_api_python_library.py
-@examples/get_pages_iterator.py
-@examples/aio_get_pages_iterator.py
-@examples/org_wide_clients_v1.py
-@examples/aio_org_wide_clients_v1.py
-@examples/apiData2CSV_v1.py
-
-
-
-
-
- Task 1: Sync pagination iterator + API requests log tests
- tests/integration/test_pagination_iterator.py
-
-Create `tests/integration/test_pagination_iterator.py` with session-scoped fixtures `api_key` and `org_id` (from pytestconfig, same pattern as existing tests).
-
-Tests to implement:
-
-1. `test_pagination_iterator_vs_legacy_networks` - Create two DashboardAPI instances: one with `use_iterator_for_get_pages=True`, one with `False`. Both call `getOrganizationNetworks(org_id, perPage=5, total_pages=-1)`. Collect results from both (iterator yields items via `for x in ...`; legacy returns list directly). Assert both produce the same set of network IDs. Use `suppress_logging=True`, `caller="PytestIntegration"`.
-
-2. `test_pagination_iterator_yields_dicts` - With iterator mode, verify each yielded item is a dict with keys `id` and `name`.
-
-3. `test_get_organization_api_requests` - Call `dashboard.organizations.getOrganizationApiRequests(org_id, timespan=900, total_pages=-1)`. Assert result is a list. If non-empty, assert first record has keys: `method`, `host`, `path`, `ts`, `responseCode`, `sourceIp`, `userAgent`. (List may be empty if no recent API activity besides this test itself, so only check fields if len > 0.)
-
-Use `meraki.DashboardAPI` directly (no async). Keep `suppress_logging=True` and `maximum_retries=5` on all clients.
-
-
- uv run pytest tests/integration/test_pagination_iterator.py --apikey $TEST_ORG_API_KEY --o $TEST_ORG_ID -v --timeout=120
-
- All sync pagination and API requests log tests pass against live API
-
-
-
- Task 2: Async pagination iterator tests
- tests/integration/test_async_pagination_iterator.py
-
-Create `tests/integration/test_async_pagination_iterator.py` with session-scoped fixtures `api_key` and `org_id`.
-
-Tests to implement (all marked `@pytest.mark.asyncio`):
-
-1. `test_async_pagination_iterator_vs_legacy_networks` - Create two `AsyncDashboardAPI` instances via `async with`: one with `use_iterator_for_get_pages=True`, one with `False`. Legacy mode: `for x in await dashboard.organizations.getOrganizationNetworks(org_id, perPage=5, total_pages=-1)`. Iterator mode: `async for x in dashboard.organizations.getOrganizationNetworks(org_id, perPage=5, total_pages=-1)`. Assert both produce the same set of network IDs.
-
-2. `test_async_iterator_yields_dicts` - With async iterator mode, verify each item is a dict with `id` and `name` keys.
-
-Use `suppress_logging=True`, `maximum_retries=5`, `caller="PytestIntegration"`.
-
-
- uv run pytest tests/integration/test_async_pagination_iterator.py --apikey $TEST_ORG_API_KEY --o $TEST_ORG_ID -v --timeout=120
-
- Async pagination iterator tests pass, confirming `async for` yields same data as `await` + list iteration
-
-
-
- Task 3: Org-wide workflow tests (sync + async)
- tests/integration/test_org_wide_workflows.py
-
-Create `tests/integration/test_org_wide_workflows.py` with session-scoped fixtures `api_key` and `org_id`.
-
-Tests to implement:
-
-1. `test_sync_org_wide_clients_workflow` - Using `meraki.DashboardAPI`: call `getOrganizationNetworks(org_id, total_pages="all", perPage=1000)`, assert returns non-empty list. Take first network, call `dashboard.networks.getNetworkClients(network_id, timespan=86400, perPage=1000, total_pages="all")`. Assert result is a list (may be empty for some networks, that's OK). If non-empty, assert first item is a dict with key `mac`.
-
-2. `test_async_org_wide_clients_workflow` - Using `meraki.aio.AsyncDashboardAPI` via `async with`: await `getOrganizationNetworks(org_id)`, take up to first 3 networks. Create tasks for `getNetworkClients` on each. Use `asyncio.as_completed` to collect results. Assert all results are lists. Verifies concurrent async fetching works.
-
-Mark async test with `@pytest.mark.asyncio`. Use `suppress_logging=True`, `maximum_retries=5`, `caller="PytestIntegration"`.
-
-
- uv run pytest tests/integration/test_org_wide_workflows.py --apikey $TEST_ORG_API_KEY --o $TEST_ORG_ID -v --timeout=180
-
- Both sync and async org-wide multi-endpoint workflows complete without error
-
-
-
-
-
-Run all new integration tests together:
-```
-uv run pytest tests/integration/test_pagination_iterator.py tests/integration/test_async_pagination_iterator.py tests/integration/test_org_wide_workflows.py --apikey $TEST_ORG_API_KEY --o $TEST_ORG_ID -v
-```
-All tests pass.
-
-
-
-- 7 new integration tests across 3 files
-- Pagination iterator (sync): proves iterator mode == legacy mode
-- Pagination iterator (async): proves `async for` == `await` + iterate
-- Org-wide workflow (sync): multi-endpoint chain works
-- Org-wide workflow (async): concurrent fetching via as_completed works
-- API requests log: endpoint returns expected record schema
-- All tests are read-only (no creates/deletes)
-- Tests follow existing conftest.py patterns (--apikey, --o options)
-
diff --git a/.planning/quick/260430-kti-create-integration-tests-based-on-exampl/260430-kti-SUMMARY.md b/.planning/quick/260430-kti-create-integration-tests-based-on-exampl/260430-kti-SUMMARY.md
deleted file mode 100644
index 2b56d084..00000000
--- a/.planning/quick/260430-kti-create-integration-tests-based-on-exampl/260430-kti-SUMMARY.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-status: complete
-quick_id: 260430-kti
-date: "2026-04-30"
----
-
-# Quick Task 260430-kti: Integration Tests
-
-## Completed
-
-- `tests/integration/test_pagination_iterator.py` (3 tests): sync iterator vs legacy, yields dicts, API requests log
-- `tests/integration/test_async_pagination_iterator.py` (2 tests): async iterator vs legacy, yields dicts
-- `tests/integration/test_org_wide_workflows.py` (2 tests): sync multi-endpoint chain, async concurrent fetching
-
-## Commits
-
-- c72e367: test(260430-kti): add sync pagination iterator and API requests log tests
-- 18e15d8: test(260430-kti): add async pagination iterator tests
-- 0311304: test(260430-kti): add org-wide workflow tests (sync + async)
diff --git a/.planning/reports/MILESTONE_SUMMARY-v1.1.md b/.planning/reports/MILESTONE_SUMMARY-v1.1.md
deleted file mode 100644
index 903059dd..00000000
--- a/.planning/reports/MILESTONE_SUMMARY-v1.1.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Milestone v1.1 - Project Summary
-
-**Generated:** 2026-05-01
-**Purpose:** Team onboarding and project review
-
----
-
-## 1. Project Overview
-
-Python SDK wrapping the Meraki Dashboard API, auto-generated from the OpenAPI spec. Provides sync/async interfaces with pagination, retry, rate limiting, and batch action support.
-
-**v1.1 Goal:** Promote the v3 generator to the default entry point and deprecate v2 legacy code.
-
-**Status:** Phase 6 complete, Phase 7 not yet started.
-
-## 2. Architecture & Technical Decisions
-
-- **Decision:** Deprecation warning fires on module import (not function call)
- - **Why:** Catches any usage immediately, even transitive imports
- - **Phase:** 6
-
-- **Decision:** Import chain redirected through oasv2 module to avoid circular dependencies
- - **Why:** parser_v3.py and generate_stubs.py referenced the old generate_library.py; pointing them at oasv2 breaks the cycle
- - **Phase:** 6
-
-- **Decision:** Test file retains `test_generate_library_v3.py` naming
- - **Why:** Continuity with prior milestone; tests validate v3 features regardless of entry point name
- - **Phase:** 6
-
-## 3. Phases Delivered
-
-| Phase | Name | Status | One-Liner |
-|-------|------|--------|-----------|
-| 6 | Generator Swap | Complete | v3 generator promoted to default, v2 deprecated with warning |
-| 7 | Legacy Cleanup | Not started | Remove abandoned oasv3 file, update CI/docs references |
-
-## 4. Requirements Coverage
-
-- ✅ **DEP-01**: v2 generator renamed to `generate_library_oasv2.py` with DeprecationWarning
-- ✅ **DEP-02**: v3 generator promoted to `generate_library.py`
-- ❌ **DEP-03**: `generate_library_oasv3.py` not yet removed (Phase 7)
-- ❌ **DEP-04**: CI/docs not yet updated for new filenames (Phase 7)
-
-## 5. Key Decisions Log
-
-| ID | Decision | Phase | Rationale |
-|----|----------|-------|-----------|
-| D-06-1 | Swap files rather than rewrite imports everywhere | 6 | Minimal blast radius; both generators keep working |
-| D-06-2 | Deprecation via `warnings.warn` on import | 6 | Standard Python pattern, tooling-friendly |
-| D-06-3 | Fix circular import by pointing at oasv2 | 6 | Blocking issue found during verification; cleanest fix |
-
-## 6. Tech Debt & Deferred Items
-
-- `generate_library_oasv3.py` still exists (dead code, Phase 7 will remove)
-- CI workflows still reference old filenames in some places
-- v2 generator retained for one version cycle buffer before removal
-- Integration test suite still being iterated (xdist parallelization, retry tuning)
-
-## 7. Getting Started
-
-- **Run the v3 generator:** `python generator/generate_library.py -o meraki/ -k `
-- **Run the deprecated v2:** `python generator/generate_library_oasv2.py` (emits DeprecationWarning)
-- **Key directories:** `generator/` (code gen), `meraki/` (SDK output), `tests/` (pytest suite)
-- **Tests:** `pytest tests/generator/` (unit), `pytest tests/integration/` (live API)
-- **Where to look first:** `generator/generate_library.py`, `generator/parser_v3.py`, `generator/common.py`
-
----
-
-## Stats
-
-- **Timeline:** 2026-04-29 to 2026-05-01 (ongoing)
-- **Phases:** 1/2 complete
-- **Commits:** 144
-- **Files changed:** 137 (+44,744 / -21,104)
-- **Contributors:** John M. Kuchta, dependabot[bot]
-
----
-
-## Quick Tasks Completed
-
-| ID | Description | Date |
-|----|-------------|------|
-| 260430-kti | Integration tests: pagination iterators, org-wide clients, API requests log | 2026-04-30 |
diff --git a/.planning/research/ARCHITECTURE.md b/.planning/research/ARCHITECTURE.md
deleted file mode 100644
index 83b63565..00000000
--- a/.planning/research/ARCHITECTURE.md
+++ /dev/null
@@ -1,664 +0,0 @@
-# Architecture Patterns: OASv3 Code Generator Integration
-
-**Domain:** Code generator for OpenAPI v3 SDK
-**Researched:** 2026-04-29
-
-## Recommended Architecture
-
-The v3 generator should follow v2's modular parse-organize-render pipeline but with a separate spec parsing layer that normalizes OASv3 features into the existing template data model.
-
-```
-┌─────────────────────────────────────────────────────────────────────┐
-│ Main Entry Point (generate_library_oasv3.py) │
-│ - CLI parsing (reuse v2 pattern) │
-│ - Spec fetching (?version=3 query param) │
-│ - Call generate_library() │
-└────────────────────────┬────────────────────────────────────────────┘
- │
- ┌────────────▼──────────────┐
- │ generate_library() │
- │ - Scope initialization │
- │ - Directory creation │
- │ - Non-generated files │
- │ - organize_spec() call │
- └────────────┬───────────────┘
- │
- ┌────────────▼──────────────────────────┐
- │ OASv3 Parser Layer (NEW) │
- │ - resolve_ref() with cache & cycles │
- │ - parse_params_v3() unified function │
- │ - Path/query from parameters[] │
- │ - Body from requestBody │
- │ - Path-level param inheritance │
- │ - get_schema_from_item() with $ref │
- │ - parse_request_body() multi-content │
- └────────────┬───────────────────────────┘
- │
- ┌────────────▼──────────────────────┐
- │ common.organize_spec() (REUSE) │
- │ - Path iteration │
- │ - Scope assignment via tags │
- │ - Operations list │
- └────────────┬────────────────────────┘
- │
- ┌────────────▼──────────────────────────────┐
- │ generate_modules() (REUSE with changes) │
- │ - Template rendering loop │
- │ - Call parse_params_v3 instead of v2 │
- │ - Pass spec for $ref resolution │
- └────────────┬─────────────────────────────┘
- │
- ┌────────────▼──────────────────────────────┐
- │ Jinja2 Templates (REUSE) │
- │ - function_template.jinja2 │
- │ - class_template.jinja2 │
- │ - batch_function_template.jinja2 │
- │ - async_class_template.jinja2 │
- │ - async_function_template.jinja2 │
- │ - batch_class_template.jinja2 │
- └────────────┬─────────────────────────────┘
- │
- ┌────────▼────────┐
- │ Output: meraki/ │
- │ - api/ │
- │ - aio/api/ │
- │ - api/batch/ │
- └─────────────────┘
-```
-
-### Component Boundaries
-
-| Component | Responsibility | Communicates With |
-|-----------|---------------|-------------------|
-| **generate_library_oasv3.py** | CLI entry, spec fetch, pipeline orchestration | Parser layer, common.organize_spec, generate_modules |
-| **OASv3 Parser Layer** | Normalize v3 spec into v2-compatible param dicts | Raw spec dict, returns normalized params |
-| **common.organize_spec()** | Path/scope organization (version-agnostic) | Receives spec paths, returns scopes dict |
-| **generate_modules()** | Module generation loop, template rendering | Parser layer for params, Jinja2 for rendering |
-| **parse_get/post/delete_params()** | HTTP method-specific logic | Parser layer, returns call_line + param dicts |
-| **Jinja2 Templates** | Code generation from normalized data | Template vars, outputs Python code |
-
-## Data Flow
-
-**OASv3 Spec to Generated Code:**
-
-```
-1. Fetch OASv3 spec from Meraki API
- https://api.meraki.com/api/v1/openapiSpec?version=3
-
-2. Parse spec structure
- spec = {
- "openapi": "3.0.1",
- "paths": {
- "/networks/{networkId}": {
- "get": {
- "operationId": "getNetwork",
- "parameters": [{"name": "networkId", "in": "path", "schema": {...}}],
- "requestBody": null # GET has no body
- },
- "put": {
- "operationId": "updateNetwork",
- "parameters": [{"name": "networkId", "in": "path", "schema": {...}}],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UpdateNetworkRequest"
- }
- }
- }
- }
- }
- }
- },
- "components": {
- "schemas": {
- "UpdateNetworkRequest": {
- "type": "object",
- "properties": {
- "name": {"type": "string"},
- "tags": {"type": "array", "items": {"type": "string"}}
- }
- }
- }
- }
- }
-
-3. Initialize scope structure
- scopes = {"networks": {}, "organizations": {}, ...}
-
-4. organize_spec() groups paths by scope
- scopes["networks"]["/networks/{networkId}"] = {
- "get": endpoint_dict,
- "put": endpoint_dict
- }
-
-5. For each endpoint, parse_params_v3() normalizes parameters
-
- Input (OASv3):
- - parameters: [{"name": "networkId", "in": "path", "schema": {"type": "string"}}]
- - requestBody: {"content": {"application/json": {"schema": {...}}}}
-
- Output (normalized for templates):
- {
- "networkId": {
- "required": True,
- "in": "path",
- "type": "string",
- "description": "Network ID"
- },
- "name": {
- "required": False,
- "in": "body",
- "type": "string",
- "description": "Network name"
- },
- "tags": {
- "required": False,
- "in": "body",
- "type": "array",
- "description": "Network tags"
- }
- }
-
-6. return_params() filters by criteria
- parse_params_v3("updateNetwork", params, requestBody, spec, ["required"])
- # Returns only required params for function signature
-
-7. Template renders with normalized data
- function_template.jinja2 receives:
- - operation: "updateNetwork"
- - function_definition: ", networkId: str"
- - path_params: {"networkId": {...}}
- - body_params: {"name": {...}, "tags": {...}}
- - call_line: "return self._session.put(metadata, resource, payload)"
-
-8. Generated code
- def updateNetwork(self, networkId: str, **kwargs):
- kwargs = locals()
- metadata = {"tags": ["networks", "configure"], "operation": "updateNetwork"}
- networkId = urllib.parse.quote(str(networkId), safe="")
- resource = f"/networks/{networkId}"
- body_params = ["name", "tags"]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
- return self._session.put(metadata, resource, payload)
-```
-
-**State Management:**
-
-| State | Storage | Lifetime |
-|-------|---------|----------|
-| OpenAPI spec | `spec` dict in generate_library() | Function scope |
-| $ref resolution cache | `_ref_cache` dict in resolve_ref() | Function scope, reset per generate_library() call |
-| $ref resolution stack | `_ref_stack` list in resolve_ref() | Call stack (cycle detection) |
-| Scopes dict | `scopes` in generate_library() | Function scope |
-| Jinja2 environment | `jinja_env` in generate_library() | Function scope |
-| Template directory | `template_dir` string | Function scope |
-
-## Integration Points with Existing Code
-
-### NEW Components (v3-specific)
-
-**1. resolve_ref(spec, ref, cache=None, stack=None)**
-- **Purpose:** Resolve `$ref` references with cycle detection and caching
-- **Location:** generate_library_oasv3.py
-- **Dependencies:** None (pure function)
-- **Used by:** get_schema_from_item, parse_request_body
-- **Signature:**
- ```python
- def resolve_ref(spec: dict, ref: str, cache: dict = None, stack: list = None) -> dict | None:
- """
- Resolve $ref like #/components/schemas/Network to actual schema.
-
- Args:
- spec: Full OpenAPI spec dict
- ref: Reference string starting with #/
- cache: Dict for memoization (mutated in place)
- stack: List for cycle detection (mutated in place)
-
- Returns:
- Resolved schema dict or None if reference invalid/cyclic
- """
- ```
-
-**2. get_schema_from_item(item, spec, cache=None)**
-- **Purpose:** Extract schema from parameter/requestBody, resolve $ref if present
-- **Location:** generate_library_oasv3.py
-- **Dependencies:** resolve_ref()
-- **Used by:** parse_params_v3, parse_request_body
-- **Signature:**
- ```python
- def get_schema_from_item(item: dict, spec: dict, cache: dict = None) -> dict | None:
- """
- Extract schema from OASv3 item (parameter or content item).
-
- Args:
- item: Dict with "schema" key (e.g., parameter or content item)
- spec: Full spec for $ref resolution
- cache: Shared cache for resolve_ref
-
- Returns:
- Schema dict (inline or resolved from $ref) or None
- """
- ```
-
-**3. parse_request_body(operation, request_body, spec, cache=None)**
-- **Purpose:** Parse OASv3 requestBody into params dict with "in": "body"
-- **Location:** generate_library_oasv3.py
-- **Dependencies:** resolve_ref, get_schema_from_item
-- **Used by:** parse_params_v3
-- **Signature:**
- ```python
- def parse_request_body(operation: str, request_body: dict, spec: dict, cache: dict = None) -> dict:
- """
- Parse OASv3 requestBody into normalized params dict.
-
- Args:
- operation: Operation ID (for logging)
- request_body: OASv3 requestBody object
- spec: Full spec for $ref resolution
- cache: Shared cache
-
- Returns:
- Dict of {param_name: {required, in, type, description, enum?, items?}}
-
- Notes:
- - Handles application/json (primary), multipart/form-data, application/octet-stream
- - Flattens schema properties into top-level params
- - Sets "in": "body" for all params
- """
- ```
-
-**4. parse_params_v3(operation, parameters, request_body, spec, param_filters=None)**
-- **Purpose:** Unified parameter parser for OASv3 (replaces v2's parse_params)
-- **Location:** generate_library_oasv3.py
-- **Dependencies:** return_params (from common or v2), parse_request_body, get_schema_from_item
-- **Used by:** generate_standard_and_async_functions, generate_action_batch_functions
-- **Signature:**
- ```python
- def parse_params_v3(
- operation: str,
- parameters: list | None,
- request_body: dict | None,
- spec: dict,
- param_filters: list | None = None
- ) -> dict:
- """
- Parse OASv3 parameters and requestBody into normalized dict.
-
- Args:
- operation: Operation ID
- parameters: List of OASv3 parameter objects (path, query, header)
- request_body: OASv3 requestBody object or None
- spec: Full spec for $ref resolution
- param_filters: List of filters for return_params (e.g., ["required", "path"])
-
- Returns:
- Normalized params dict matching v2 format:
- {
- param_name: {
- "required": bool,
- "in": "path" | "query" | "body",
- "type": "string" | "integer" | "boolean" | "array" | "object",
- "description": str,
- "enum": list (optional),
- "items": dict (optional, for arrays)
- }
- }
-
- Notes:
- - Merges parameters[] and requestBody into single dict
- - Handles path-level parameter inheritance (future enhancement)
- - Passes through return_params for filtering
- - Adds pagination params if perPage detected
- """
- ```
-
-### REUSED Components (from v2 or common.py)
-
-**1. organize_spec(paths, scopes)**
-- **Location:** common.py
-- **Status:** REUSE AS-IS
-- **Why:** Path-to-scope mapping is version-agnostic
-
-**2. return_params(operation, params, param_filters)**
-- **Location:** generate_library.py (v2) - MOVE TO common.py
-- **Status:** REUSE with extraction
-- **Why:** Filtering logic (required, path, query, body, array, enum) is identical for v2 and v3
-- **Action:** Extract to common.py, import in both generators
-
-**3. generate_pagination_parameters(operation)**
-- **Location:** generate_library.py (v2) - MOVE TO common.py
-- **Status:** REUSE with extraction
-- **Why:** Pagination is a library feature, not spec-version-specific
-- **Action:** Extract to common.py
-
-**4. docs_url(operation)**
-- **Location:** generate_library.py (v2) - MOVE TO common.py
-- **Status:** REUSE with extraction
-- **Why:** Pure transformation of operation ID to documentation URL
-- **Action:** Extract to common.py
-
-**5. Jinja2 Templates**
-- **Location:** generator/*.jinja2
-- **Status:** REUSE AS-IS
-- **Why:** Templates consume normalized param dicts; v3 parser produces same format as v2
-
-**6. generate_modules(batchable_actions, jinja_env, scopes, template_dir)**
-- **Location:** generate_library.py (v2) - DUPLICATE with modifications
-- **Status:** DUPLICATE and modify for v3
-- **Why:** Core structure identical, but calls parse_params_v3 instead of parse_params
-- **Changes:**
- - Replace `endpoint["parameters"]` with `endpoint.get("parameters")` and `endpoint.get("requestBody")`
- - Replace `parse_params(op, params, filters)` with `parse_params_v3(op, params, request_body, spec, filters)`
- - Thread `spec` through all parsing calls
-
-**7. generate_standard_and_async_functions()**
-- **Location:** generate_library.py (v2) - DUPLICATE with modifications
-- **Status:** DUPLICATE and modify for v3
-- **Changes:** Same as generate_modules
-
-**8. generate_action_batch_functions()**
-- **Location:** generate_library.py (v2) - DUPLICATE with modifications
-- **Status:** DUPLICATE and modify for v3
-- **Changes:** Same as generate_modules
-
-### MODIFIED Components
-
-**parse_get_params, parse_post_and_put_params, parse_delete_params**
-- **Status:** REUSE AS-IS (they consume normalized params)
-- **Why:** HTTP method logic operates on normalized params dict, not raw spec
-
-## Patterns to Follow
-
-### Pattern 1: $ref Resolution with Cycle Detection
-**What:** Recursive reference resolution with memoization and stack-based cycle detection
-**When:** Parsing any OASv3 schema that may contain $ref
-**Example:**
-```python
-def resolve_ref(spec, ref, cache=None, stack=None):
- if cache is None:
- cache = {}
- if stack is None:
- stack = []
-
- # Already resolved
- if ref in cache:
- return cache[ref]
-
- # Cycle detected
- if ref in stack:
- return None
-
- # Parse #/components/schemas/Network -> ["components", "schemas", "Network"]
- if not ref.startswith("#/"):
- return None
- parts = ref[2:].split("/")
-
- # Walk the spec
- stack.append(ref)
- result = spec
- for part in parts:
- if isinstance(result, dict) and part in result:
- result = result[part]
- else:
- stack.pop()
- return None
-
- # Cache and return
- cache[ref] = result
- stack.pop()
- return result
-```
-
-### Pattern 2: Unified Parameter Parsing
-**What:** Single function handles path, query, and body parameters
-**When:** Parsing any OASv3 operation
-**Example:**
-```python
-def parse_params_v3(operation, parameters, request_body, spec, param_filters=None):
- all_params = {}
- cache = {} # Shared across parameters and requestBody
-
- # Parse path/query parameters
- if parameters:
- for p in parameters:
- schema = get_schema_from_item(p, spec, cache)
- # Extract type, description, required from schema
- all_params[p["name"]] = normalize_param(p, schema)
-
- # Parse requestBody
- if request_body:
- body_params = parse_request_body(operation, request_body, spec, cache)
- all_params.update(body_params)
-
- # Add pagination if perPage present
- if "perPage" in all_params:
- all_params.update(generate_pagination_parameters(operation))
-
- # Filter and return
- return return_params(operation, all_params, param_filters)
-```
-
-### Pattern 3: Content-Type Aware Body Parsing
-**What:** Handle multiple requestBody content types (JSON, multipart, octet-stream)
-**When:** Parsing OASv3 requestBody
-**Example:**
-```python
-def parse_request_body(operation, request_body, spec, cache):
- if "content" not in request_body:
- return {}
-
- content = request_body["content"]
-
- # Priority: application/json > multipart/form-data > application/octet-stream
- media_type = None
- if "application/json" in content:
- media_type = content["application/json"]
- elif "multipart/form-data" in content:
- media_type = content["multipart/form-data"]
- elif "application/octet-stream" in content:
- # Binary upload, no schema properties to extract
- return {}
-
- if not media_type:
- return {}
-
- schema = get_schema_from_item(media_type, spec, cache)
- if not schema or "properties" not in schema:
- return {}
-
- # Flatten properties into params
- params = {}
- required_fields = schema.get("required", [])
- for prop_name, prop_schema in schema["properties"].items():
- if "$ref" in prop_schema:
- prop_schema = resolve_ref(spec, prop_schema["$ref"], cache)
- params[prop_name] = {
- "required": prop_name in required_fields,
- "in": "body",
- "type": prop_schema.get("type", "object"),
- "description": prop_schema.get("description", "")
- }
- if "enum" in prop_schema:
- params[prop_name]["enum"] = prop_schema["enum"]
-
- return params
-```
-
-### Pattern 4: Path-Level Parameter Inheritance
-**What:** Path-level parameters apply to all operations on that path
-**When:** Parsing OASv3 paths
-**Example:**
-```python
-# In generate_library, when iterating paths:
-for path, path_item in paths.items():
- # OASv3: path-level parameters inherited by all operations
- path_level_params = path_item.get("parameters", [])
-
- for method in ["get", "post", "put", "delete", "patch"]:
- if method not in path_item:
- continue
-
- endpoint = path_item[method]
-
- # Merge path-level and operation-level parameters
- operation_params = endpoint.get("parameters", [])
- # Operation params override path params with same name
- param_names = {p["name"] for p in operation_params}
- inherited = [p for p in path_level_params if p["name"] not in param_names]
- all_parameters = operation_params + inherited
-
- # Now parse with merged parameters
- parsed = parse_params_v3(
- endpoint["operationId"],
- all_parameters,
- endpoint.get("requestBody"),
- spec
- )
-```
-
-## Anti-Patterns to Avoid
-
-### Anti-Pattern 1: Monolithic Parser Function
-**What:** Single function that handles spec fetching, parsing, organizing, and generation
-**Why bad:** Impossible to test in isolation, cannot reuse components, hard to debug
-**Instead:** Separate concerns into functions with single responsibilities
-**Evidence from abandoned attempt:** generate_library_oasv3.py lines 262-765 is a single function doing everything
-
-### Anti-Pattern 2: Inline $ref Resolution
-**What:** Resolving references at template time or in every parsing function separately
-**Why bad:** No caching, cycle detection fragile, templates become spec-aware
-**Instead:** Resolve all $ref at parse time, cache results, pass normalized dicts to templates
-**Example of wrong approach:**
-```python
-# BAD: Template has to understand $ref
-{% if body_params[param].get("$ref") %}
- # Special handling in template
-{% endif %}
-
-# GOOD: Parser resolves before template
-body_params = {
- "name": {"type": "string", "description": "Network name"} # Already resolved
-}
-```
-
-### Anti-Pattern 3: Duplicating return_params Logic
-**What:** Reimplementing filter logic (required, path, query, etc.) in v3 parser
-**Why bad:** Code duplication, divergence over time, missed edge cases
-**Instead:** Extract return_params to common.py, reuse in both generators
-
-### Anti-Pattern 4: Not Threading Spec Through Functions
-**What:** Passing partial dicts and losing context needed for $ref resolution
-**Why bad:** Cannot resolve references, have to refetch or restructure data
-**Instead:** Thread full `spec` dict through all parsing functions, use cache for performance
-**Example from abandoned attempt:**
-```python
-# Lines 196-259: parse_params needs spec for $ref but loses context in nested calls
-def parse_params(operation, parameters, request_body, spec, param_filters=None):
- # ...
- for p in parameters:
- schema = get_schema_from_item(p, spec) # Correct, spec threaded
- # ...
- body_params = parse_request_body(operation, request_body, spec) # Correct
-```
-
-### Anti-Pattern 5: Using locals() for Param Construction
-**What:** `kwargs.update(locals())` to capture function arguments
-**Why bad:** Captures unintended vars (self, operation, metadata), fails static analysis
-**Instead:** Explicit param dict construction or structured capture
-**Note:** This is v2 tech debt; v3 is opportunity to fix but not blocking for parity
-
-### Anti-Pattern 6: Assuming Single Content Type
-**What:** Only parsing application/json from requestBody
-**Why bad:** Meraki API uses multipart/form-data for firmware uploads, octet-stream for binaries
-**Instead:** Priority-based content type selection (JSON > multipart > octet-stream)
-
-## Scalability Considerations
-
-| Concern | At 100 operations | At 400+ operations (current) | At 1000+ operations |
-|---------|-------------------|------------------------------|---------------------|
-| $ref cache | Not needed | Essential (298 batchable actions share schemas) | Critical (memory vs re-parse tradeoff) |
-| Template rendering | Sequential OK | Sequential OK (fast with Jinja2) | Consider parallel per scope |
-| Spec download | Network OK | Network OK | Consider caching in CI |
-| Code formatting | ruff fast | ruff fast (current: <5s) | Consider incremental formatting |
-
-**Current scale:** 298 operations across 17 scopes, v3 spec is ~3.2MB JSON
-
-**Performance targets:**
-- Full generation (fetch + parse + render + format): <30s
-- Parser layer (parse all operations): <5s
-- Template rendering: <10s
-- Code formatting: <5s
-
-**Bottlenecks to watch:**
-1. $ref resolution without caching (O(n²) with nested schemas)
-2. Jinja2 template reloading per function (use jinja_env.from_string with reuse)
-3. ruff formatting on individual files (batch invocation faster)
-
-## Build Order
-
-**Phase 1: Parser Foundation**
-1. resolve_ref() with tests (cycle detection, caching)
-2. get_schema_from_item() with tests
-3. parse_request_body() with tests (JSON, multipart, octet-stream)
-4. Extract return_params to common.py, update v2 imports
-
-**Phase 2: Unified Parser**
-5. parse_params_v3() with tests (path, query, body merging)
-6. Path-level parameter inheritance
-7. Golden-file test with synthetic v3 fixture
-
-**Phase 3: Generation Integration**
-8. Duplicate generate_modules and modify for parse_params_v3 calls
-9. Duplicate generate_standard_and_async_functions with spec threading
-10. Duplicate generate_action_batch_functions with v3 batch operation detection
-
-**Phase 4: CLI and Entry Point**
-11. generate_library_oasv3.py main() with ?version=3 param
-12. Integration test with live v3 spec
-13. CI drift detection (v2 vs v3 output comparison)
-
-**Dependency order:**
-- resolve_ref is foundation (no deps)
-- get_schema_from_item depends on resolve_ref
-- parse_request_body depends on get_schema_from_item and resolve_ref
-- parse_params_v3 depends on parse_request_body and return_params
-- Generation functions depend on parse_params_v3
-
-**Testing order:**
-- Unit tests for pure functions (resolve_ref, get_schema_from_item)
-- Unit tests for parse functions with synthetic schemas
-- Golden-file tests with synthetic spec (minimal but representative)
-- Integration test with live v3 spec (slow, run in CI)
-
-## Sources
-
-**HIGH confidence:**
-- Existing v2 generator code analysis (generate_library.py, common.py)
-- Abandoned v3 attempt analysis (generate_library_oasv3.py anti-patterns)
-- Jinja2 template structure (function_template.jinja2)
-- Test suite structure (test_pure_functions.py, test_generate_library_golden.py)
-- PROJECT.md requirements and constraints
-
-**MEDIUM confidence:**
-- OASv3 spec structure (from OpenAPI 3.0.1 standard, verified in abandoned code)
-- Multi-version generator patterns (inferred from v2 structure, industry practice)
-
-**LOW confidence:**
-- openapi-generator internal architecture (docs don't cover implementation)
-- Optimal caching strategy (scale assumptions based on current 298 operations)
-
-## Gaps and Assumptions
-
-**Assumptions made:**
-1. v3 spec structure matches OpenAPI 3.0.1 standard (verified in abandoned code)
-2. Meraki v3 spec uses same x-batchable-actions as v2 (PROJECT.md confirms 298 entries)
-3. Templates can consume normalized params without modification (confirmed from template analysis)
-4. path-level parameter inheritance exists in v3 spec (standard feature, need to verify in live spec)
-
-**Gaps to address in implementation:**
-1. oneOf query param handling (mentioned in PROJECT.md, not in abandoned code)
-2. nullable type annotations (mentioned in PROJECT.md, need parser support)
-3. components/schemas usage patterns (need to analyze live v3 spec)
-4. Exact batch operation detection logic for v3 (v2 uses summary match, v3 may differ)
-5. Error handling strategy for malformed $ref or missing schemas
diff --git a/.planning/research/FEATURES.md b/.planning/research/FEATURES.md
deleted file mode 100644
index 4cfe24f0..00000000
--- a/.planning/research/FEATURES.md
+++ /dev/null
@@ -1,207 +0,0 @@
-# Feature Landscape: OpenAPI 3.0 Code Generator
-
-**Domain:** Python SDK generation from OpenAPI 3.0 specifications
-**Researched:** 2026-04-29
-**Context:** Building OASv3 generator for Meraki Dashboard API Python SDK
-
-## Table Stakes
-
-Features users expect in any production OpenAPI 3.0 Python generator. Missing these makes the SDK feel incomplete or amateurish.
-
-| Feature | Why Expected | Complexity | Notes |
-|---------|--------------|------------|-------|
-| **$ref resolution** | Core OAS3 feature, all specs use references | Medium | Needs cycle detection, caching. OASV3-MIGRATION.md already addresses |
-| **requestBody parsing** | OAS3 moved body params out of parameters array | Medium | application/json, multipart/form-data, octet-stream. Already planned |
-| **Type annotations** | Python 3.10+ standard, enables IDE autocomplete | Low | Basic types straightforward, `oneOf` needs Union |
-| **Sync and async methods** | Modern Python expects both | Low | Already implemented in v2 generator |
-| **Pagination support** | Large result sets require paging | Low | Already implemented (total_pages, direction params) |
-| **Error handling** | SDK must surface API errors clearly | Low | Already exists in rest_session.py (APIError, APIResponseError) |
-| **Query param serialization** | Arrays, objects, special chars must encode correctly | Medium | Existing encode_params() handles dicts; need array style/explode |
-| **Path parameter substitution** | URLs need variable interpolation | Low | Standard in all generators |
-| **Retry logic** | Network failures happen | Low | Already implemented (MAXIMUM_RETRIES, WAIT_ON_RATE_LIMIT) |
-| **oneOf/anyOf handling** | OAS3 standard for polymorphic params | High | Already planned as "string or object" in docstrings |
-| **nullable type annotations** | OAS3 nullable: true is common | Low | Planned: `param: str \| None` syntax |
-| **Enum support** | Constrained values are common | Low | Standard generator feature |
-| **Multi-content-type requestBody** | APIs often accept JSON OR form data | Medium | Parse all content types, document in signature |
-
-## Differentiators
-
-Features that set excellent SDK generators apart from mediocre ones. Not expected by default, but high value when present.
-
-| Feature | Value Proposition | Complexity | Notes |
-|---------|-------------------|------------|-------|
-| **Type stubs (.pyi)** | Static analysis, mypy, IDE without runtime cost | Medium | Already planned in OASV3-MIGRATION.md with --stubs flag |
-| **kwarg validation with opt-in logging** | Catch typos, inform about invalid params | Low | Already implemented in v2 (validate_kwargs flag) |
-| **Golden-file test suite** | Regression protection on generator changes | Medium | Already planned in OASV3-MIGRATION.md |
-| **CI drift detection** | Automated v2 vs v3 output comparison | Medium | Already planned in OASV3-MIGRATION.md |
-| **Explicit param construction** | Replaces locals() antipattern, enables static analysis | Medium | Already planned; improves over v2 |
-| **Vendor extension preservation** | Allows custom metadata (x-batchable-actions) | Low | Already handling x-batchable-actions |
-| **Docstring generation from descriptions** | API docs inline in code | Low | Standard but quality varies |
-| **Custom HTTP client support** | Pluggable transport (requests vs httpx) | High | Not needed, requests/aiohttp work |
-| **Response model objects** | Type-safe response parsing with dataclasses/pydantic | High | Overkill for dict-based API; adds complexity |
-| **Automatic pagination iterators** | Generator functions for transparent paging | Medium | Already implemented (getPages methods) |
-| **Operation-specific exceptions** | NotFoundError vs UnauthorizedError | Medium | Nice-to-have, current APIError works |
-| **Request/response logging hooks** | Debugging, audit trails | Low | Possible via session config |
-| **Configurable timeouts per endpoint** | Different operations need different timeouts | Low | Global timeout works for most cases |
-| **Array serialization control** | Respect style/explode from spec | Medium | Already planned (OAS3 default: form, explode: true) |
-| **Path-level parameter inheritance** | DRY spec = correct client | Medium | Already planned in OASV3-MIGRATION.md |
-
-## Anti-Features
-
-Features commonly requested or present in other generators that should be avoided for this project.
-
-| Anti-Feature | Why Avoid | What to Do Instead |
-|--------------|-----------|-------------------|
-| **Pydantic model generation** | Runtime overhead, spec churn causes breaking changes | Keep dict-based returns, use type hints for IDE support |
-| **Full OAS 3.1 support** | Different type system (type: [string, null]), adds complexity | Support OAS 3.0 only, document limitation |
-| **Automatic model class generation** | Meraki spec has 1000+ endpoints, classes balloon SDK size | Dict returns work, TypedDict stubs provide typing |
-| **SDK method name customization** | operationId already provides names, customization causes confusion | Use operationId directly |
-| **Client-side validation (pydantic)** | Adds dependency, validation logic duplicates server | Rely on server validation, surface errors clearly |
-| **Sync wrapper around async** | async-first with sync wrapper adds indirection | Generate both from spec independently |
-| **Auto-generated examples in docstrings** | Specs rarely have good examples, stale examples mislead | Provide links to official docs (already doing this) |
-| **Nested SDK namespacing** | client.api.networks.devices.getDevice() too verbose | Flat client.networks.getNetworkDevices() matches v2 |
-| **OAuth flow helpers** | Meraki uses API key only | Simple X-Cisco-Meraki-API-Key header (already done) |
-| **Mock server generation** | Out of scope for SDK generator | User can use stripe-mock or similar |
-| **Webhook signature validation** | Different concern from API client | Separate library if needed |
-| **GraphQL support** | Meraki is REST only | N/A |
-| **Auto-retry on ALL 4xx** | Some 4xx are permanent (400, 401, 403) | Retry 429 only, flag for 4xx opt-in (already done) |
-
-## Feature Dependencies
-
-```
-$ref resolution
- ↓
-requestBody parsing (refs in schemas)
- ↓
-Type annotations (schema types)
-
-oneOf handling
- ↓
-Union type annotations
-
-Path-level parameters
- ↓
-parse_params unification
-
-Explicit param construction
- ↓
-Template changes (function_template.jinja2)
-
-Type stubs
- ↓
-All type annotation logic finalized
-```
-
-## MVP Recommendation
-
-**Phase 1: Core OAS3 Parsing** (table stakes)
-1. $ref resolution with cycle protection
-2. requestBody parsing (JSON, multipart, octet-stream)
-3. oneOf as Union[str, dict] (docstring: "string or object")
-4. nullable type annotations (param: str | None)
-5. Path-level parameter inheritance
-6. Array serialization (style/explode)
-
-**Phase 2: Code Quality** (differentiators)
-1. Explicit param construction (replace locals())
-2. Type stub generation (.pyi)
-3. Golden-file test suite
-4. CI drift detection
-
-**Phase 3: Polish** (optional)
-1. Enhanced docstrings (oneOf sub-properties documented)
-2. Request/response logging hooks
-3. Per-endpoint timeout configuration
-
-**Defer to future milestones:**
-- Response model objects (dict returns work fine)
-- Operation-specific exceptions (nice-to-have)
-- Custom HTTP clients (requests/aiohttp sufficient)
-
-## Feature Prioritization Matrix
-
-| Feature | User Value | Implementation Cost | Priority |
-|---------|------------|---------------------|----------|
-| $ref resolution | Critical | Medium | P0 |
-| requestBody parsing | Critical | Medium | P0 |
-| oneOf handling | High | Medium | P0 |
-| nullable annotations | High | Low | P0 |
-| Type stubs | High | Medium | P1 |
-| Explicit param construction | Medium | Medium | P1 |
-| Golden-file tests | High (dev) | Medium | P1 |
-| CI drift detection | High (dev) | Medium | P1 |
-| Path-level params | Medium | Low | P0 |
-| Array serialization | Medium | Low | P0 |
-| Response models | Low | High | P3 |
-| Custom HTTP clients | Low | High | P3 |
-| Operation exceptions | Low | Medium | P3 |
-
-## Complexity Breakdown
-
-**Low complexity** (< 1 day):
-- Nullable annotations
-- Path-level parameter inheritance
-- Array serialization style/explode
-- Vendor extension preservation
-
-**Medium complexity** (1-3 days):
-- $ref resolution with caching and cycle detection
-- requestBody parsing (multiple content types)
-- oneOf/anyOf Union type generation
-- Type stub generation
-- Explicit param construction
-- Golden-file test suite
-- CI drift detection
-
-**High complexity** (> 3 days):
-- Response model generation (Pydantic/dataclasses)
-- Custom HTTP client pluggability
-- Full OAS 3.1 support (type arrays)
-
-## Integration with Existing Features
-
-| Existing Feature | OAS3 Integration Point | Notes |
-|------------------|------------------------|-------|
-| Pagination (total_pages, direction) | No change | Still added to endpoints with perPage param |
-| Batch actions (x-batchable-actions) | Still present in OAS3 spec | Same matching logic works |
-| Retry logic (MAXIMUM_RETRIES) | No change | rest_session.py handles this |
-| kwarg validation | No change | Works with OAS3 params same way |
-| Sync/async generation | No change | Template-based, agnostic to OAS version |
-| Rate limiting (WAIT_ON_RATE_LIMIT) | No change | rest_session.py feature |
-| encode_params() | Needs array handling | Already handles dict query params; add array support |
-
-## Sources
-
-**High Confidence:**
-- Context7: /openapi-generators/openapi-python-client (type annotations, dataclasses, async support)
-- Context7: /openapitools/openapi-generator (Python generator features)
-- OASV3-MIGRATION.md (project-specific OAS3 features)
-- PROJECT.md (existing v2 features)
-- OpenAPI 3.0 vs 3.1 migration guide (official)
-
-**Medium Confidence:**
-- Stripe Python SDK patterns (async, pagination, type hints, retry logic)
-- openapi-python-client GitHub issues (common pitfalls: oneOf, allOf, nullable enums, file uploads)
-
-**Low Confidence:**
-- WebFetch openapi-python-client repo (feature list)
-- WebFetch openapi-generator.tech docs (config options)
-
-## Feature Coverage Comparison
-
-| Feature Category | openapi-python-client | openapi-generator | Meraki v2 | Meraki v3 (Target) |
-|------------------|----------------------|-------------------|-----------|-------------------|
-| Type annotations | ✓ Full | ✓ Basic | ✗ None | ✓ Full + stubs |
-| Async support | ✓ asyncio | ✓ asyncio/tornado | ✓ aiohttp | ✓ aiohttp |
-| Pagination | Manual | Manual | ✓ Auto (total_pages) | ✓ Auto (total_pages) |
-| Retry logic | Manual (httpx) | Manual | ✓ Built-in | ✓ Built-in |
-| oneOf/anyOf | ✓ Union | ✓ Union | N/A (OAS2) | ✓ Union (docstring) |
-| nullable | ✓ Optional | ✓ Optional | N/A (OAS2) | ✓ Optional (| None) |
-| $ref resolution | ✓ Full | ✓ Full | N/A (OAS2 inline) | ✓ Full + cycle detect |
-| Batch actions | ✗ | ✗ | ✓ x-batchable-actions | ✓ x-batchable-actions |
-| Type stubs | ✗ | ✗ | ✗ | ✓ .pyi generation |
-| kwarg validation | ✗ | ✗ | ✓ Optional logging | ✓ Optional logging |
-| CI drift detection | ✗ | ✗ | ✗ | ✓ Planned |
-| Response models | ✓ Dataclasses | ✗ | ✗ Dicts | ✗ Dicts (intentional) |
-
-**Competitive advantage:** Meraki v3 generator combines strong typing (stubs, annotations) with operational features (pagination, retry, batch, validation) that pure code generators lack.
diff --git a/.planning/research/PITFALLS.md b/.planning/research/PITFALLS.md
deleted file mode 100644
index 963efd69..00000000
--- a/.planning/research/PITFALLS.md
+++ /dev/null
@@ -1,309 +0,0 @@
-# Domain Pitfalls: OASv3 Code Generator
-
-**Domain:** OpenAPI 3.0 code generation for existing v2 system
-**Researched:** 2026-04-29
-**Context:** Adding OASv3 generator alongside working v2 generator for Meraki Dashboard API Python SDK
-
-## Critical Pitfalls
-
-Mistakes that cause rewrites or major issues.
-
-### Pitfall 1: Infinite Loop in $ref Resolution Without Cycle Detection
-**What goes wrong:** Circular `$ref` chains (Schema A → Schema B → Schema A) cause infinite recursion and stack overflow. The abandoned oasv3 file has NO cycle detection in `resolve_ref()` (lines 26-41).
-
-**Why it happens:** OpenAPI 3.0 spec allows circular references for recursive data structures. Simple traversal hits the same refs repeatedly without tracking visited nodes.
-
-**Consequences:** Generator crashes on valid specs with recursive schemas. Silent hang if max recursion isn't reached but loops for seconds. Production failure on spec updates that introduce circular refs.
-
-**Prevention:**
-```python
-def resolve_ref(spec: dict, ref: str, _visiting: set | None = None) -> dict | None:
- if _visiting is None:
- _visiting = set()
-
- if ref in _visiting:
- return None # Circular ref detected
-
- _visiting.add(ref)
- # ... rest of resolution logic
-```
-
-**Detection:** Spec with `#/components/schemas/Foo` containing `properties: { child: { $ref: "#/components/schemas/Foo" } }` triggers the issue. Test fixture MUST include circular ref case.
-
-### Pitfall 2: Missing $ref Cache Causes O(n²) Performance
-**What goes wrong:** Resolving the same `$ref` thousands of times when spec has shared schemas referenced by 298+ endpoints. Each resolution traverses the full JSON pointer path.
-
-**Why it happens:** No memoization. Abandoned oasv3 file calls `resolve_ref()` inline everywhere (lines 54, 167, 188, 235) with no caching.
-
-**Consequences:** 30+ second generation time for live spec (vs <5s for v2). CI timeouts. Developer friction during iteration.
-
-**Prevention:** Add cache on first spec access:
-```python
-if "_ref_cache" not in spec:
- spec["_ref_cache"] = {}
-
-if ref in spec["_ref_cache"]:
- return spec["_ref_cache"][ref]
-
-# resolve and cache before returning
-```
-
-**Detection:** `time python generate_library_oasv3.py` taking >10s on live spec when v2 takes <5s.
-
-### Pitfall 3: Path-Level Parameter Inheritance Not Implemented
-**What goes wrong:** OASv3 allows parameters at path level that apply to all operations. Abandoned file ignores `paths[path]["parameters"]` and only checks `paths[path][method]["parameters"]` (line 209, 441). Missing required path params like `organizationId`.
-
-**Why it happens:** v2 doesn't have path-level params. Direct port of v2 logic misses this OASv3 feature.
-
-**Consequences:** Generated functions missing required parameters. Runtime errors when calling SDK methods. Silent param drops if parameter appears at path level but not operation level.
-
-**Prevention:**
-```python
-# Collect path-level params first
-path_level_params = paths[path].get("parameters", [])
-operation_params = endpoint.get("parameters", [])
-
-# Merge with operation params overriding on (name, in) collision
-merged = merge_params(path_level_params, operation_params)
-```
-
-**Detection:** Golden file test with path-level param that doesn't appear in operation-level params. Diff v3 vs v2 output on live spec shows missing params.
-
-### Pitfall 4: requestBody Content-Type Priority Inverted
-**What goes wrong:** Abandoned file checks `application/json` first (line 155) and ignores other content types. Multipart/form-data endpoints (file uploads) get parsed as JSON and lose binary field markers.
-
-**Why it happens:** Defaulting to JSON without checking all content types. Spec can have multiple `requestBody.content` keys for different consumers.
-
-**Consequences:** File upload endpoints broken (missing `Content-Type: multipart/form-data`). Binary fields treated as string params. Runtime errors when SDK tries to JSON-encode binary data.
-
-**Prevention:**
-```python
-content = request_body.get("content", {})
-
-# Priority order: json → multipart → octet-stream → warn on unsupported
-if "application/json" in content:
- # parse JSON schema
-elif "multipart/form-data" in content:
- # parse form data, mark format:binary fields
-elif "application/octet-stream" in content:
- # single binary body param
-else:
- # Warn about unsupported content type, don't silently drop
-```
-
-**Detection:** Endpoint with `multipart/form-data` in fixture generates code expecting JSON. Manual test of file upload fails.
-
-### Pitfall 5: Template Data Format Mismatch (Breaking Change)
-**What goes wrong:** v3 parser returns `dict[str, dict]` for params but v2 templates expect different keys or structure. Template renders wrong code (empty param lists, missing type annotations).
-
-**Why it happens:** v3 has `parameter.schema.type` nested one level deeper than v2's `parameter.type` OR `parameter.schema.properties`. Changing parse logic without checking template expectations.
-
-**Consequences:** Generated functions missing params entirely. Type annotations wrong (all params become `str`). Pagination/kwargs handling broken. Appears to work but output is subtly wrong.
-
-**Prevention:**
-- Golden file tests that CHECK output structure, not just "does it run"
-- Parse v3 into SAME dict format v2 produces: `{ "paramName": { "type": "...", "required": bool, "in": "...", "description": "..." } }`
-- Test against existing function_template.jinja2 WITHOUT template changes
-
-**Detection:** Golden file content differs from expected in param types or counts. Ruff errors in generated code. CI diff check shows structural differences.
-
-## Moderate Pitfalls
-
-### Pitfall 6: oneOf Reported as Generic "object" Type
-**What goes wrong:** oneOf query params (string OR object with lt/gt/lte/gte) get type annotation `object`, losing string option. Docstring says "object" when user can pass a string.
-
-**Why it happens:** Abandoned file doesn't check for `oneOf` (missing from `get_schema_from_item`). Falls back to `type: object` from schema.
-
-**Consequences:** Misleading documentation. Static analysis tools reject valid string inputs. User confusion when passing string and it works despite docs saying "object".
-
-**Prevention:**
-```python
-if "oneOf" in schema:
- # Check constituent types
- types = [s.get("type") for s in schema["oneOf"]]
- if "string" in types and "object" in types:
- return ("string or object", f"string or object with properties: {list_object_props(schema)}")
-```
-
-**Detection:** Endpoint with oneOf query param generates docstring without "string or" prefix.
-
-### Pitfall 7: No Validation for Missing $ref Targets
-**What goes wrong:** Spec references `#/components/schemas/NonExistent` that doesn't exist. `resolve_ref` returns `None` silently (line 40). Param gets skipped or defaults to wrong type.
-
-**Why it happens:** Defensive programming (return None on error) without logging or validation step.
-
-**Consequences:** Missing parameters in generated code. Silent data loss. Hard to debug ("why is this param not showing up?").
-
-**Prevention:**
-```python
-if result is None:
- # Log warning with context
- print(f"WARNING: Failed to resolve $ref '{ref}' in operation '{operation}'")
- # Option: treat as opaque 'object' type rather than skip
-```
-
-**Detection:** Spec with broken `$ref` generates code without warnings. Add fixture with invalid ref, verify warning appears.
-
-## Minor Pitfalls
-
-### Pitfall 8: Array Serialization Style Ignored
-**What goes wrong:** OASv3 has `style` (form/spaceDelimited/pipeDelimited) and `explode` (true/false) for array params. Abandoned file ignores these (no check for `style` in param parsing).
-
-**Why it happens:** v2 doesn't have these attributes. Defaulting to single strategy without checking spec.
-
-**Consequences:** Array query params serialized wrong format. API rejects requests with "invalid format" errors. Works in some cases (default form+explode matches API expectation) but breaks on non-default.
-
-**Prevention:**
-```python
-# OAS3 defaults: style=form, explode=true for query params
-style = param.get("style", "form")
-explode = param.get("explode", True)
-
-# Document in param description how arrays are sent
-if param_type == "array":
- params[name]["serialization"] = {"style": style, "explode": explode}
-```
-
-**Detection:** Endpoint with array param + explicit style generates code that doesn't respect style.
-
-### Pitfall 9: nullable Not Reflected in Type Annotations
-**What goes wrong:** Param has `nullable: true` but generated function signature is `param: str` instead of `param: str | None`.
-
-**Why it happens:** Abandoned file checks `nullable` in parsing (not shown in excerpt) but doesn't thread through to type annotation logic.
-
-**Consequences:** Type checkers reject valid `None` inputs. Misleading type hints. Runtime passes None but static analysis fails.
-
-**Prevention:**
-```python
-# In function definition builder
-if values["type"] == "string":
- if values.get("nullable", False):
- definition += f", {p}: str | None"
- else:
- definition += f", {p}: str"
-```
-
-**Detection:** Param with `nullable: true` generates signature without `| None`.
-
-### Pitfall 10: Vendor Extension Loss
-**What goes wrong:** `x-batchable-actions` survives (line 292) but other `x-*` fields at parameter or operation level get dropped during parsing.
-
-**Why it happens:** Explicit extraction only for known vendor extensions. Generic `x-*` fields not forwarded.
-
-**Consequences:** Custom tooling that relies on vendor extensions breaks. Metadata loss that downstream consumers need.
-
-**Prevention:**
-```python
-# Copy all x- prefixed keys
-for key, value in schema.items():
- if key.startswith("x-"):
- params[name][key] = value
-```
-
-**Detection:** Spec with custom `x-meraki-preview` flag on param doesn't appear in generated code.
-
-## Phase-Specific Warnings
-
-| Phase Topic | Likely Pitfall | Mitigation |
-|-------------|---------------|------------|
-| Phase 1: Core v3 Parsing | Circular $ref causing crash | Implement cycle detection in `resolve_ref` with visited-set guard |
-| Phase 1: Core v3 Parsing | Missing $ref cache causing slow generation | Add `spec["_ref_cache"]` dict, check before traversal |
-| Phase 2: Unified parse_params | Path-level params ignored | Merge path-level and operation-level params before parsing |
-| Phase 2: Unified parse_params | requestBody content-type priority wrong | Parse all content types, document priority order |
-| Phase 3: HTTP Method Parsers | Template data format doesn't match v2 | Golden file tests BEFORE changing templates |
-| Phase 4: Module Generation | locals() antipattern survives in v3 | Update templates to explicit param construction DURING v3 work |
-| Phase 5: Batch Actions | Operation type lookup fails for v3 structure | Test batch endpoint in golden fixture, verify operation field |
-| Phase 6: oneOf Handling | Generic "object" type loses oneOf semantics | `resolve_oneof_type` helper with accurate type strings |
-| Phase 7: Testing | Golden files too rigid (byte-for-byte match) | v3 golden files allow enhanced docstrings, not v2 parity |
-| Phase 8: CI Drift Detection | False positives from docstring enhancements | Semantic diff (params, types, structure) not text diff |
-
-## Integration Gotchas
-
-### Gotcha 1: Shared common.py Not Threadsafe for spec Param
-**What:** v2's `common.organize_spec()` doesn't expect `spec` arg. Threading spec through all functions breaks imports if v2 and v3 generators run concurrently in tests.
-
-**Impact:** Test pollution. Race conditions if CI runs both generators in parallel.
-
-**Fix:** Either accept breaking import change (update v2 if needed) OR namespace v3 helpers differently (`common_v3.py`).
-
-### Gotcha 2: Template Filter Registration Skipped
-**What:** v2 registers `jinja_env.filters["to_double_quote_list"]` (line 299 in v2). If oasv3 file forgets this, template rendering fails with "unknown filter" error.
-
-**Impact:** Generation crashes late (after parsing succeeds). Confusing error far from root cause.
-
-**Fix:** Copy ALL jinja_env setup from v2, not just template loading. Add test that uses filter.
-
-### Gotcha 3: ruff Invocation Assumes cwd
-**What:** v2 runs `subprocess.run(["ruff", "check", "--fix", "meraki/"])` assuming cwd is project root (line 306). If v3 generator changes cwd or runs from generator/ dir, ruff formats wrong files or fails.
-
-**Impact:** Generated code not formatted. CI fails on style check. Looks like generator is broken when it's just cwd issue.
-
-**Fix:** Use absolute paths for ruff invocation. Test in tmp_path directory like golden tests do.
-
-### Gotcha 4: Non-Generated Files Downloaded Every Run
-**What:** Lines 272-287 in v2 download from GitHub every generation (no cache check). v3 copy/paste means slower iteration and network dependency.
-
-**Impact:** Offline generation fails. Slow feedback loop during development.
-
-**Fix:** Check if files exist and are current version before downloading. Or expect files present (don't auto-download).
-
-## "Looks Done But Isn't" Checklist
-
-Generator appears to work but has subtle correctness issues:
-
-- [ ] Circular $ref test in fixture (not just inline schemas)
-- [ ] Path-level parameters inherited into operations (not just operation-level)
-- [ ] requestBody with multiple content-types handled correctly (not just JSON)
-- [ ] oneOf query params documented as "string or object" (not generic "object")
-- [ ] nullable params get `| None` type annotation (not bare type)
-- [ ] Array params respect style/explode attributes (not default serialization for all)
-- [ ] Missing $ref target logs warning (not silent None return)
-- [ ] Template receives same dict format as v2 (not nested differently)
-- [ ] v3 golden files validate v3-specific output (not byte-for-byte match with v2)
-- [ ] CI drift detection checks semantic structure (not just text diff)
-- [ ] Batch actions work with v3 operation lookup (not hardcoded from v2 assumptions)
-- [ ] Enum assertions survive parsing (not lost in translation)
-- [ ] Pagination params injected for perPage endpoints (not dropped)
-- [ ] locals() antipattern replaced in templates (not persisted from v2)
-- [ ] $ref cache used for performance (not resolving same ref 1000x)
-
-## Technical Debt Patterns
-
-### Debt Pattern 1: Monolithic parse_params (Abandoned Approach)
-**What:** Single 200-line function handling path, query, body, requestBody, $ref, oneOf all inline. Abandoned oasv3 file has this (lines 196-260).
-
-**Why it's debt:** Impossible to test individual parsing steps. Changes in one param type affect all others. Hard to debug which clause failed.
-
-**Better approach:** Separate functions: `parse_path_params()`, `parse_query_params()`, `parse_request_body()`, then merge. Each unit-testable.
-
-### Debt Pattern 2: No Intermediate Representation
-**What:** Parsing directly into template dict format. Any template change requires parser changes.
-
-**Why it's debt:** Tight coupling. Can't reuse parser for different output formats (like .pyi stubs). Hard to diff "what did parsing extract" vs "what did template render".
-
-**Better approach:** Parse to normalized IR (dataclass or TypedDict), then map IR → template dict separately. Enables stub generation reusing same IR.
-
-### Debt Pattern 3: Error Handling by Omission
-**What:** Failed $ref → return None → param dropped silently. Unsupported content-type → skip without warning (implicit in abandoned code).
-
-**Why it's debt:** Silent failures. Debugging "why is param missing" requires reading spec + code. No visibility into what went wrong.
-
-**Better approach:** Explicit warnings. Fail-fast option (`--strict` flag) for CI that errors on missing refs.
-
-## Sources
-
-**Code analysis:**
-- `generator/generate_library_oasv3.py` (abandoned attempt, lines 26-833)
-- `generator/generate_library.py` (v2 production generator, lines 1-800)
-- `generator/function_template.jinja2` (template expectations)
-- `tests/generator/test_generate_library_golden.py` (test patterns)
-- `OASV3-MIGRATION.md` (known challenges)
-
-**Research:**
-- OpenAPI 3.0.3 specification (spec.openapis.org) - $ref resolution warnings, circular reference gaps
-- Swagger.io $ref documentation - sibling element confusion, escape character issues
-- Codebase git history - abandoned oasv3 file introduced commit a0ea07f, minimal iteration
-
-**Confidence:** HIGH for pitfalls observed in abandoned code, MEDIUM for pitfalls from spec analysis (OAS3 docs incomplete on edge cases), LOW for external tooling pitfalls (Brave API unavailable, OpenAPI Generator issues page shallow)
-
-**Analysis method:** Compared abandoned oasv3 file against working v2 generator line-by-line. Identified missing features (cycle detection, caching, path-level params). Cross-referenced with OAS3 spec for undocumented behaviors. Verified template expectations from jinja2 files.
diff --git a/.planning/research/STACK.md b/.planning/research/STACK.md
deleted file mode 100644
index 57e09bf0..00000000
--- a/.planning/research/STACK.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# Technology Stack: OASv3 Code Generator
-
-**Domain:** Python code generation from OpenAPI 3.0.1 specs
-**Researched:** 2026-04-29
-**Overall confidence:** HIGH
-
-## Executive Summary
-
-The OASv3 generator requires minimal new dependencies. The live Meraki spec (tested 2026-04-29) uses requestBody, nullable, and oneOf but has ZERO $refs and no components/schemas, so complex dereferencing libraries are unnecessary. Hand-rolled JSON pointer traversal (already present in abandoned generator) suffices for future-proofing. Type stub generation should use Jinja2 templates (consistency with existing generator) rather than external tools.
-
-## Core Technologies
-
-All existing runtime dependencies remain unchanged. Generator adds one dependency.
-
-| Technology | Version | Purpose | Why |
-|------------|---------|---------|-----|
-| Python | >=3.11 | Runtime requirement | Already specified in pyproject.toml |
-| Jinja2 | ==3.1.6 | Template rendering | Already used for code generation, pinned in `dependency-groups.generator` |
-| requests | >=2.33.1,<3 | Fetching OpenAPI spec | Already used in v2 generator |
-| ruff | >=0.15.12 | Code formatting | Already used for post-generation formatting |
-
-**No new core dependencies required.**
-
-## Supporting Libraries
-
-### For $ref Resolution: NONE
-
-**Decision:** Hand-roll JSON pointer traversal (port from abandoned `generate_library_oasv3.py`).
-
-**Rationale:**
-- Live Meraki v3 spec has **0 $refs** (verified 2026-04-29)
-- Simple `#/components/schemas/X` pointer walking: 15 lines of code
-- No external URLs, no file loading, no complex edge cases
-- Cycle detection: visited set, 5 lines
-- Libraries like `jsonref` (1.1.0), `jsonpointer` (3.1.1), `prance` (25.4.8.0) are overkill
-
-**If future specs have $refs:**
-- `jsonpointer` (3.1.1, MIT): RFC 6901 compliant, production-stable, Python 3.10+
-- Fallback: current hand-rolled resolver handles simple cases fine
-
-### For OpenAPI Parsing: NONE
-
-**Decision:** Direct dict traversal of parsed JSON.
-
-**Rationale:**
-- `openapi-spec-validator` (0.8.5): Validates specs, doesn't help parsing
-- `openapi-core`: Request/response validation, not generation
-- `prance` (25.4.8.0): Parser + validator, but adds dependency for features we don't need (external file refs, validation backends)
-- Meraki spec is pre-validated (published by API team), direct access simpler
-
-### For Type Stub Generation: Jinja2 Templates
-
-**Decision:** Use existing Jinja2 template approach, not `mypy stubgen`.
-
-**Rationale:**
-- `mypy stubgen` (1.20.2): CLI-only, generates drafts with `Any` types, requires manual refinement
-- Jinja2 templates give precise control over generated stubs with OAS types → Python types mapping
-- Consistency with existing generator architecture
-- Pattern already proven in `function_template.jinja2`
-
-**Template approach:**
-```python
-# api_stub_template.jinja2 generates:
-def getOrganization(self, organizationId: str) -> dict: ...
-def updateOrganization(self, organizationId: str, **kwargs: Any) -> dict: ...
-```
-
-**PEP 561 compliance:**
-- Add `py.typed` marker file to package root (already present per grep results)
-- `.pyi` files alongside `.py` modules (e.g., `meraki/api/organizations.pyi`)
-
-## Alternatives Considered
-
-| Category | Recommended | Alternative | Why Not |
-|----------|-------------|-------------|---------|
-| $ref resolution | Hand-rolled | `jsonref` 1.1.0 | Live spec has 0 $refs. Hand-rolled is 20 lines including cycle detection. Library is 3 files + proxy overhead for unused features. |
-| $ref resolution | Hand-rolled | `prance` 25.4.8.0 | Parser includes validation backends, external file handling, URI resolution. Adds 5 dependencies for features not used. Documentation says cycle detection "not mentioned." |
-| OpenAPI parsing | Direct dict access | `openapi-spec-validator` 0.8.5 | Validates specs, doesn't simplify parsing. Adds dependency for unused validation (Meraki spec is pre-validated). |
-| OpenAPI parsing | Direct dict access | `openapi-core` | Request/response validation library, not a spec parser. Wrong tool for code generation. |
-| Type stubs | Jinja2 templates | `mypy stubgen` 1.20.2 | CLI-only, generates `Any` everywhere, requires manual fixes. No programmatic API. Template approach gives full type precision from OAS types. |
-| Type stubs | Jinja2 templates | `stubgen` package | PyPI page failed to load (2026-04-29). Mypy's stubgen is CLI-only per official docs. |
-
-## What NOT to Use
-
-### jsonschema (4.26.0)
-**Why:** JSON Schema validator, not OpenAPI parser. Does NOT provide OpenAPI-specific $ref resolution. Adds validation overhead for features not needed in code generation.
-
-### openapi-python-client (0.28.3)
-**Why:** Full client generator, not a library. Generates entire SDK with opinionated structure. We need selective parsing for our existing architecture, not a competing generator.
-
-### jsonref (1.1.0)
-**Why:** Proxy-based lazy evaluation is clever but unnecessary. Live spec has 0 $refs. If future specs have refs, they're simple `#/components/schemas/X` pointers, not recursive or external. Hand-rolled resolver is clearer and avoids proxy overhead.
-
-## Integration with Existing Generator
-
-The v2 generator uses:
-- `common.organize_spec()` - organizes paths by scope tags
-- Jinja2 templates: `class_template.jinja2`, `function_template.jinja2`, `batch_function_template.jinja2`
-- Jinja2 filter: `to_double_quote_list` for JSON arrays
-- `ruff` for post-generation formatting
-
-**v3 generator additions:**
-- New `resolve_ref()` function (port from abandoned oasv3, already exists)
-- New `parse_request_body()` function for OAS3 requestBody
-- Thread `spec` dict through all parse functions
-- New template: `stub_template.jinja2` for `.pyi` generation
-
-**No changes to:**
-- `common.py`
-- Existing templates (reuse as-is)
-- Runtime SDK (`rest_session.py`, pagination logic, etc.)
-
-## Installation
-
-No changes to runtime dependencies. Generator dependencies already in `pyproject.toml`:
-
-```toml
-[dependency-groups]
-generator = ["jinja2==3.1.6"]
-```
-
-For type stub generation, add `py.typed` marker if not present:
-
-```bash
-echo "" > meraki/py.typed
-```
-
-## Live Spec Verification (2026-04-29)
-
-Tested against `https://api.meraki.com/api/v1/openapiSpec?version=3`:
-
-| Feature | Count | Impact |
-|---------|-------|--------|
-| `openapi` | 3.0.1 | Target version confirmed |
-| `$ref` | 0 | No dereferencing needed for live spec |
-| `components/schemas` | 0 | No reusable schemas |
-| `oneOf` | 2 | Need oneOf type handling |
-| `nullable` | 152 | Need nullable annotation |
-| `requestBody` | 340 | Need requestBody parser |
-| `x-batchable-actions` | 298 | Existing batch handling reusable |
-
-**Implication:** The project requirements list `$ref` resolution as a feature, but the live spec doesn't use it. This suggests it's either:
-1. Future-proofing for anticipated spec changes
-2. Testing requirement (synthetic fixtures may include $refs)
-3. Mistaken assumption from OAS3 spec review
-
-**Recommendation:** Implement simple hand-rolled resolver (20 lines) for completeness, but flag in research that it's not exercised by production spec.
-
-## Sources
-
-**HIGH confidence:**
-- PyPI (official): openapi-spec-validator 0.8.5, prance 25.4.8.0, jsonschema 4.26.0, jsonref 1.1.0, jsonpointer 3.1.1, mypy 1.20.2, openapi-python-client 0.28.3
-- Live Meraki spec verification (2026-04-29): 0 $refs, 340 requestBody, 152 nullable, 2 oneOf
-- PEP 561: Type stub distribution standards (py.typed marker, .pyi files)
-- Existing codebase: pyproject.toml dependency groups, generate_library.py patterns, abandoned generate_library_oasv3.py resolve_ref()
-
-**MEDIUM confidence:**
-- Swagger.io docs: $ref resolution rules, edge cases (escape chars, sibling elements ignored)
-- OpenAPI 3.0.3 spec: $ref processing, JSON Reference standard
-- mypy docs: stubgen CLI-only, generates draft stubs
-
-**LOW confidence:**
-- None (all critical findings verified with authoritative sources)
diff --git a/.planning/research/SUMMARY.md b/.planning/research/SUMMARY.md
deleted file mode 100644
index cb18bb9d..00000000
--- a/.planning/research/SUMMARY.md
+++ /dev/null
@@ -1,284 +0,0 @@
-# Research Summary: OASv3 Generator Project
-
-**Date:** 2026-04-29
-**Project:** Meraki Dashboard API Python SDK - OpenAPI 3.0 Generator
-
-## Executive Summary
-
-- **Live spec tested (2026-04-29) has 0 $refs**, 340 requestBody, 152 nullable, 2 oneOf. Hand-rolled JSON pointer resolver (20 lines) sufficient, no jsonref dependency needed.
-- **Core challenge is OASv3 requestBody parsing** (moved from parameters array), not spec complexity. Templates reusable, parser layer normalizes v3 → v2 data format.
-- **Abandoned attempt has 5 critical bugs**: no cycle detection, no $ref cache (O(n²)), ignores path-level params, wrong content-type priority, no oneOf detection.
-- **Zero new runtime dependencies**. Jinja2 templates (not mypy stubgen) for type stubs. Ruff already present for formatting.
-- **298 batchable actions share schemas**. $ref cache essential for performance even though live spec has 0 refs (future-proofing + test fixtures will use refs).
-
-## Stack Additions Needed
-
-**None for runtime.** Generator uses existing dependencies.
-
-| Component | Version | Purpose | Status |
-|-----------|---------|---------|--------|
-| Jinja2 | 3.1.6 | Template rendering + stub generation | Already in pyproject.toml |
-| requests | >=2.33.1 | Fetch v3 spec (?version=3 param) | Already present |
-| ruff | >=0.15.12 | Post-generation formatting | Already present |
-| Python | >=3.11 | Type annotation syntax (str \| None) | Runtime requirement |
-
-**Rejected:**
-- jsonref (1.1.0): Proxy overhead for 0 refs in live spec
-- prance (25.4.8.0): 5 dependencies for unused file loading
-- openapi-spec-validator (0.8.5): Validation we don't need (spec pre-validated)
-- mypy stubgen (1.20.2): CLI-only, generates Any everywhere, no programmatic API
-
-## Feature Table Stakes vs Differentiators
-
-### Table Stakes (P0)
-
-Must-have for production generator:
-
-| Feature | Complexity | Notes |
-|---------|------------|-------|
-| $ref resolution + cycle detection | Medium | 0 in live spec but needed for fixtures, abandoned code crashes on cycles |
-| requestBody parsing (JSON/multipart/octet-stream) | Medium | 340 uses in live spec, v2 doesn't have this |
-| oneOf as Union[str, dict] | Medium | 2 in live spec, docstring "string or object" |
-| nullable → str \| None annotations | Low | 152 in live spec |
-| Path-level parameter inheritance | Low | OASv3 standard, abandoned code ignores |
-| Array serialization (style/explode) | Low | OASv3 defaults: form + explode=true |
-
-### Differentiators (P1)
-
-High-value, not expected by default:
-
-| Feature | Value | Status |
-|---------|-------|--------|
-| Type stubs (.pyi) via Jinja2 | Static analysis without runtime cost | Planned with --stubs flag |
-| Explicit param construction | Replaces locals() antipattern | Enables static analysis |
-| Golden-file test suite | Regression protection | Planned |
-| CI drift detection | v2 vs v3 output comparison | Planned |
-| kwarg validation + opt-in logging | Catch typos | Already in v2 |
-| Vendor extension (x-batchable-actions) | 298 batch endpoints | Already in v2 |
-
-### Anti-Features (Avoid)
-
-Commonly requested but wrong for this project:
-
-- **Pydantic model generation**: Runtime overhead, spec churn = breaking changes, 1000+ endpoints balloon size
-- **Full OAS 3.1 support**: Different type system (type: [string, null]), adds complexity
-- **Response model objects**: Dict returns work, TypedDict stubs provide typing
-- **Auto-generated examples in docstrings**: Specs rarely have good examples, go stale
-
-## Architecture Integration Strategy
-
-### Parser Layer (NEW)
-
-Normalizes OASv3 → v2-compatible param dicts for template reuse.
-
-```
-OASv3 spec fetch
- ↓
-resolve_ref(spec, ref, cache, stack) ← 20 lines, cycle detection, caching
- ↓
-get_schema_from_item(item, spec, cache) ← Extract schema, handle $ref
- ↓
-parse_request_body(op, requestBody, spec, cache) ← JSON/multipart/octet-stream → params dict
- ↓
-parse_params_v3(op, params, requestBody, spec, filters) ← Unified parser merges path/query/body
- ↓
-return_params(op, params, filters) ← Reuse v2 filtering (extract to common.py)
- ↓
-Templates (REUSE AS-IS) ← function_template.jinja2, class_template.jinja2, batch_template.jinja2
-```
-
-### Component Changes
-
-| Component | Action | Why |
-|-----------|--------|-----|
-| generate_library_oasv3.py | NEW | Entry point, ?version=3 param, spec fetch |
-| OASv3 parser functions | NEW | resolve_ref, get_schema_from_item, parse_request_body, parse_params_v3 |
-| return_params() | EXTRACT to common.py | Reuse filter logic (required, path, query, array, enum) |
-| generate_pagination_parameters() | EXTRACT to common.py | Version-agnostic |
-| docs_url() | EXTRACT to common.py | Pure transform op → URL |
-| organize_spec() | REUSE | Path/scope mapping version-agnostic |
-| Jinja2 templates | REUSE | Consume normalized params, no changes |
-| generate_modules() | DUPLICATE + modify | Call parse_params_v3, thread spec |
-
-### Data Flow Critical Point
-
-**Parser must produce v2-compatible dict format:**
-
-```python
-{
- "paramName": {
- "required": bool,
- "in": "path" | "query" | "body",
- "type": "string" | "integer" | "boolean" | "array" | "object",
- "description": str,
- "enum": list, # optional
- "items": dict, # optional for arrays
- "nullable": bool # NEW for v3
- }
-}
-```
-
-Templates expect this. Change breaks generated code.
-
-## Key Pitfalls to Watch
-
-### Critical (Rewrite Risk)
-
-1. **No cycle detection in $ref**: Circular schemas crash generator. Abandoned code lacks visited-set guard. Add `_visiting` set param to resolve_ref().
-
-2. **No $ref cache**: O(n²) with 298 batchable operations. 30+ second generation vs <5s. Add `spec["_ref_cache"]` dict, check before traversal.
-
-3. **Path-level params ignored**: OASv3 allows `paths[path]["parameters"]` inherited by all operations. Abandoned code only checks operation-level. Merge before parsing.
-
-4. **requestBody content-type priority wrong**: Checks JSON only, multipart endpoints (file uploads) break. Priority: JSON → multipart → octet-stream → warn.
-
-5. **Template data format mismatch**: Parser returns wrong dict structure, templates render empty params. Golden file tests catch this. Match v2 format exactly.
-
-### Moderate (Correctness Issues)
-
-6. **oneOf reported as generic "object"**: Loses "string or object" semantics. Add oneOf detection in get_schema_from_item, docstring enhancement.
-
-7. **Missing $ref target silent**: Returns None, param dropped without warning. Log warning with operation context.
-
-### Minor (Enhancement Opportunities)
-
-8. **Array serialization style ignored**: OASv3 style/explode attributes not checked. Document defaults (form + explode=true).
-
-9. **nullable not in type annotations**: `nullable: true` doesn't add `| None`. Thread nullable through to type builder.
-
-10. **Vendor extension loss**: x-batchable-actions survives, other x-* fields dropped. Forward all x- prefixed keys.
-
-### Integration Gotchas
-
-- **Shared common.py not threadsafe**: If v2/v3 run concurrently in tests, spec param breaks imports. Namespace v3 helpers or accept breaking change.
-- **Template filter registration skipped**: v2 registers `to_double_quote_list`, forget = crash. Copy ALL jinja_env setup.
-- **ruff assumes cwd**: Absolute paths needed. Test in tmp_path.
-
-## Phase Ordering Implications
-
-### Phase 1: Parser Foundation (5-7 days)
-**What:** Core v3 parsing without generation
-
-**Delivers:**
-- resolve_ref() with cycle detection + caching (unit tests)
-- get_schema_from_item() with $ref support
-- parse_request_body() (JSON, multipart, octet-stream)
-- Extract return_params() to common.py
-
-**Pitfalls addressed:** #1 (cycles), #2 (cache), #4 (content-type)
-
-**Research needed:** No. Patterns well-documented, abandoned code shows what NOT to do.
-
-**Rationale:** Foundation must be solid. $ref resolution used by all downstream parsing. Unit tests fast, isolated from generation complexity.
-
-### Phase 2: Unified Parameter Parser (3-5 days)
-**What:** parse_params_v3() merges path/query/body
-
-**Delivers:**
-- parse_params_v3() with path-level inheritance
-- Golden-file test with synthetic v3 fixture
-- Pagination param injection for perPage endpoints
-
-**Pitfalls addressed:** #3 (path-level params), #5 (data format)
-
-**Research needed:** No. Template expectations clear from function_template.jinja2.
-
-**Rationale:** Parser output must match template input. Golden file prevents template breakage. Synthetic fixture exercises edge cases (cycle, oneOf, nullable, multipart) not in live spec.
-
-**Dependencies:** Phase 1 complete (resolve_ref, parse_request_body)
-
-### Phase 3: Generation Integration (4-6 days)
-**What:** Duplicate generate_modules() with v3 parsing
-
-**Delivers:**
-- generate_library_oasv3.py entry point
-- generate_modules() calling parse_params_v3
-- HTTP method parsers (get/post/put/delete) with v3 support
-- Batch action detection for v3 structure
-
-**Pitfalls addressed:** #5 (template format validation)
-
-**Research needed:** No. generate_modules() structure proven in v2.
-
-**Rationale:** Duplication safer than modification. v2 stays stable, v3 iterates independently. Thread `spec` through all parsing calls.
-
-**Dependencies:** Phase 2 complete (parse_params_v3 produces correct format)
-
-### Phase 4: Type Stubs (3-4 days)
-**What:** .pyi generation via Jinja2
-
-**Delivers:**
-- stub_template.jinja2 for function signatures
-- --stubs flag in generate_library_oasv3.py
-- py.typed marker in package root
-- nullable → str | None, oneOf → Union[str, dict]
-
-**Pitfalls addressed:** #6 (oneOf detection), #9 (nullable)
-
-**Research needed:** No. PEP 561 compliance straightforward, Jinja2 approach proven.
-
-**Rationale:** Defer until core generation stable. Type stubs reuse same parse_params_v3 output. Differentiator feature, not table stakes.
-
-**Dependencies:** Phase 3 complete (generation working)
-
-### Phase 5: Quality & CI (2-3 days)
-**What:** Testing, drift detection, docs
-
-**Delivers:**
-- Golden file tests expanded (edge cases: cycle, multipart, oneOf, nullable)
-- CI drift detection (v2 vs v3 semantic diff, not text)
-- Integration test with live v3 spec
-- OASV3-MIGRATION.md updates
-
-**Pitfalls addressed:** #7 (missing $ref warnings), #8 (array style), #10 (vendor extensions)
-
-**Research needed:** No. Test patterns exist in test_generate_library_golden.py.
-
-**Rationale:** Catch regressions before v2 replacement. Semantic diff prevents false positives from docstring enhancements.
-
-**Dependencies:** Phase 4 complete (full feature set)
-
-### Defer to Future
-
-- Response model objects (Pydantic/dataclasses): High complexity, low value for dict-based API
-- Operation-specific exceptions (NotFoundError): Nice-to-have, APIError works
-- Custom HTTP clients (httpx pluggability): requests/aiohttp sufficient
-
-## Open Questions
-
-1. **Does live v3 spec use path-level parameters?** Abandoned code suggests yes (OASv3 standard), but 0 uses found in manual inspection. Verify during Phase 2 golden file fixture creation.
-
-2. **What's the v3 batch action detection logic?** v2 uses summary field match. Does v3 spec structure x-batchable-actions differently? Test during Phase 3 with live spec.
-
-3. **Should v3 fix locals() antipattern?** OASV3-MIGRATION.md suggests explicit param construction. Do it in v3 (fresh start) or defer (maintain v2 parity)? Decide during Phase 3 template work.
-
-4. **CI drift detection semantic vs text diff?** How to diff "params correct, docstrings enhanced" vs "params missing"? Design diffing logic in Phase 5.
-
-5. **Should return_params() extraction break v2 imports?** Move to common.py changes imports. Update v2 (safer) or namespace as common_v3.py (isolation)? Decide in Phase 1.
-
-## Confidence Assessment
-
-| Area | Confidence | Rationale |
-|------|------------|-----------|
-| Stack | HIGH | Live spec tested 2026-04-29. Jinja2/requests/ruff proven in v2. No new dependencies confirmed. |
-| Features | HIGH | OASV3-MIGRATION.md + PROJECT.md align. Table stakes clear from v2 gaps. Live spec verified (340 requestBody, 152 nullable). |
-| Architecture | HIGH | v2 structure analyzed. Parse-organize-render pipeline proven. Abandoned code shows pitfalls. Template reuse confirmed. |
-| Pitfalls | HIGH | Abandoned code line-by-line comparison. 5 critical bugs identified with prevention. OASv3 spec edge cases documented. |
-
-**Gaps identified:**
-- Path-level parameter usage in live spec (assume present per standard)
-- Batch action structure in v3 (likely same x-batchable-actions)
-- oneOf query param frequency (2 in live spec, need broader fixture coverage)
-
-**No research blockers.** All questions answerable during implementation with live spec + fixtures.
-
-## Ready for Requirements
-
-All research complete. Roadmapper can structure phases with confidence in:
-- Technology stack (no new deps, Jinja2 for stubs)
-- Feature priorities (table stakes vs differentiators clear)
-- Architecture approach (parser layer + template reuse)
-- Pitfall prevention (5 critical bugs with solutions)
-- Build order (Phase 1-5 dependencies mapped)
-
-Research files committed together for traceability.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d9586a94..ba5accd2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,8 +8,8 @@ add a news fragment under `changelog.d/` for every user-facing change. See
-## 3.3.0 (2026-07-01)
+## 4.2.0b1 (2026-06-10)
-### Added
+### Changed
-- On 5xx responses, the SDK now logs the Meraki `X-Request-Id` response header so it can be shared with Meraki to look up the request in server-side logs. If the header is absent, `none` is logged in its place. After retries are exhausted, the request ID is also logged at error level.
+- Migrated the HTTP transport layer from `requests`/`aiohttp` to `httpx`.
diff --git a/README.md b/README.md
index 43129482..d2a6d317 100644
--- a/README.md
+++ b/README.md
@@ -207,10 +207,6 @@ Unless you are an ecosystem partner, this identifier is optional.
rep.
2. If you have any questions about the formatting, please ask your question by opening an issue in this repo.
-## Releasing
-
-See [docs/releasing.md](docs/releasing.md) for versioning rules and the automated release process.
-
## Development
This project uses [uv](https://docs.astral.sh/uv/) for dependency management and builds with
diff --git a/changelog.d/+log-x-request-id-on-5xx.added.md b/changelog.d/+log-x-request-id-on-5xx.added.md
new file mode 100644
index 00000000..a242f188
--- /dev/null
+++ b/changelog.d/+log-x-request-id-on-5xx.added.md
@@ -0,0 +1 @@
+On 5xx responses, the SDK now logs the Meraki `X-Request-Id` response header so it can be shared with Meraki to look up the request in server-side logs. If the header is absent, `none` is logged in its place. After retries are exhausted, the request ID is also logged at error level.
diff --git a/docs/HTTPX-MIGRATION.md b/docs/HTTPX-MIGRATION.md
index c5acc4e1..9ee139e4 100644
--- a/docs/HTTPX-MIGRATION.md
+++ b/docs/HTTPX-MIGRATION.md
@@ -163,6 +163,60 @@ These have **different signatures and different attribute sources**. Unifying re
---
+## Deprecated: AsyncAPIError
+
+**Status:** Deprecated as of v4.0. Use `APIError` for both sync and async exceptions.
+
+### What Changed
+
+In previous versions, the SDK used two separate exception classes:
+- `APIError` for synchronous errors
+- `AsyncAPIError` for asynchronous errors
+
+Starting in v4.0, both sync and async sessions raise exceptions that inherit from `APIError`. The `AsyncAPIError` class remains available for backwards compatibility but is deprecated.
+
+### Migration
+
+**Before (v3.x):**
+```python
+from meraki.aio import AsyncDashboardAPI
+from meraki.exceptions import AsyncAPIError
+
+async with AsyncDashboardAPI(api_key=API_KEY) as aiomeraki:
+ try:
+ response = await aiomeraki.organizations.getOrganizations()
+ except AsyncAPIError as e:
+ print(f"Error: {e.status} {e.reason}")
+```
+
+**After (v4.0+):**
+```python
+from meraki.aio import AsyncDashboardAPI
+from meraki.exceptions import APIError # Changed
+
+async with AsyncDashboardAPI(api_key=API_KEY) as aiomeraki:
+ try:
+ response = await aiomeraki.organizations.getOrganizations()
+ except APIError as e: # Changed
+ print(f"Error: {e.status} {e.reason}")
+```
+
+### Backwards Compatibility
+
+Existing code using `except AsyncAPIError:` will continue to work because `AsyncAPIError` is now a subclass of `APIError`. However, you will see a `DeprecationWarning` when the exception is raised.
+
+To suppress the warning during migration:
+```python
+import warnings
+warnings.filterwarnings('ignore', category=DeprecationWarning, module='meraki')
+```
+
+### Recommended Action
+
+Update exception handlers to catch `APIError` instead of `AsyncAPIError`. This future-proofs your code and eliminates deprecation warnings.
+
+---
+
## Phase 6: Update Dependencies
**Modify `pyproject.toml`:**
diff --git a/docs/generation-report.md b/docs/generation-report.md
index 5f480fc9..a3710fa3 100644
--- a/docs/generation-report.md
+++ b/docs/generation-report.md
@@ -1,12 +1,60 @@
# Generation Report
-## 2026-07-01 | Library v3.3.0 | API 1.72.0
+## 2026-07-08 | Library v4.3.0b1 | API 1.72.0-beta.1
No Python keyword parameter conflicts detected.
-## 2026-06-04 | Library v3.2.0 | API 1.71.0
+## 2026-07-01 | Library v4.3.0b0 | API 1.72.0-beta.0
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-06-24 | Library v4.2.0b3 | API 1.71.0-beta.3
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-06-17 | Library v4.2.0b2 | API 1.71.0-beta.2
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-06-10 | Library v4.2.0b1 | API 1.71.0-beta.1
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-06-10 | Library v4.1.0b1 | API 1.71.0-beta.1
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-05-27 | Library v4.1.0b3 | API 1.70.0-beta.3
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-05-20 | Library v4.1.0b2 | API 1.70.0-beta.2
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-05-14 | Library v4.1.0b1 | API 1.70.0-beta.1
+
+
+No Python keyword parameter conflicts detected.
+
+
+## 2026-05-08 | Library v4.1.0b0 | API 1.70.0-beta.0
No Python keyword parameter conflicts detected.
diff --git a/docs/superpowers/plans/2026-07-08-httpx-to-main-migration.md b/docs/superpowers/plans/2026-07-08-httpx-to-main-migration.md
new file mode 100644
index 00000000..d42360be
--- /dev/null
+++ b/docs/superpowers/plans/2026-07-08-httpx-to-main-migration.md
@@ -0,0 +1,231 @@
+# httpx → main Final Migration Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Merge the httpx-based transport rewrite (branch `origin/httpx`) into `main`, making main's tree exactly httpx while preserving both branches' commit history, then regenerate the API surface to GA.
+
+**Architecture:** A no-fast-forward merge records httpx as a second parent (preserving both histories in the DAG), then `git read-tree --reset` forces the working tree to be byte-identical to httpx (no 155-file conflict resolution). The one genuinely main-only feature not already on httpx (X-Request-Id-on-5xx) is replayed via cherry-pick. The generated `meraki/api` code and version strings arrive as beta throwaway and are regenerated to GA by the maintainer.
+
+**Tech Stack:** git (merge, read-tree, cherry-pick), Python 3, uv, pytest, ruff.
+
+## Global Constraints
+
+- Base branch for the PR: `main`. Work branch: `migrate/httpx`.
+- httpx tip = `origin/httpx` (`6b20c2a`). main tip = `ec91975`. Merge base = `6d3dd19`.
+- Tree after merge MUST equal `origin/httpx` byte-for-byte (verified via `git diff --stat origin/httpx` = empty).
+- Both parent histories MUST remain reachable (merge commit has exactly 2 parents).
+- Do NOT hand-port app-id/bearer or delete()-params — both already exist on httpx tip.
+- Do NOT cherry-pick dangling `6c8bf68` — it is a duplicate of httpx tip's app-id/bearer feature.
+- The maintainer regenerates `meraki/api`, `meraki/aio/api`, and version strings AFTER the merge — the plan does not touch generated code or versions.
+- Pre-existing stashes `stash@{0}` / `stash@{1}` on main are the maintainer's — do not pop or drop them.
+
+---
+
+### Task 1: Create migration branch and history-preserving merge
+
+**Files:**
+- No file edits; git plumbing only. Result: `migrate/httpx` branch with a 2-parent merge commit whose tree == `origin/httpx`.
+
+**Interfaces:**
+- Consumes: `main` (current), `origin/httpx` (fetched).
+- Produces: branch `migrate/httpx` at a merge commit `M` with parents `[main_tip, origin/httpx_tip]` and tree identical to `origin/httpx`.
+
+- [ ] **Step 1: Fetch and confirm clean starting state**
+
+```bash
+cd "c:/Users/jkuchta/Work/_Repos/meraki/dashboard-api-python"
+git fetch origin
+git checkout main
+git status --short # expect: empty (stashes are fine, not shown here)
+git rev-parse --short main origin/httpx
+```
+Expected: working tree clean; `main` = `ec91975...`, `origin/httpx` = `6b20c2a...`.
+
+- [ ] **Step 2: Create the migration branch**
+
+```bash
+git checkout -b migrate/httpx main
+```
+Expected: `Switched to a new branch 'migrate/httpx'`.
+
+- [ ] **Step 3: Start the merge without committing**
+
+```bash
+git merge --no-commit --no-ff origin/httpx
+```
+Expected: reports conflicts (155 files). This is expected and ignored — the next step overwrites the tree wholesale. Do NOT resolve conflicts by hand.
+
+- [ ] **Step 4: Force index + working tree to exactly httpx**
+
+```bash
+git read-tree -u --reset origin/httpx
+```
+Expected: no output. Index and working tree now match `origin/httpx` byte-for-byte; merge is still in progress (MERGE_HEAD set).
+
+- [ ] **Step 5: Verify tree equals httpx before committing**
+
+```bash
+git diff --stat origin/httpx # expect: EMPTY (identical trees)
+git diff --stat --cached origin/httpx # expect: EMPTY
+```
+Expected: both empty. If not empty, STOP — do not commit; investigate.
+
+- [ ] **Step 6: Commit the merge**
+
+```bash
+git commit --no-edit
+```
+Expected: a merge commit is created.
+
+- [ ] **Step 7: Verify 2-parent merge and history preservation**
+
+```bash
+git log -1 --format='%h parents: %p' # expect 2 parent hashes
+git rev-parse --short 'HEAD^1' 'HEAD^2' # expect ec91975 (main), 6b20c2a (httpx)
+git merge-base --is-ancestor ec91975 HEAD && echo "MAIN HISTORY PRESERVED"
+git merge-base --is-ancestor 6b20c2a HEAD && echo "HTTPX HISTORY PRESERVED"
+git rev-list --count origin/httpx..HEAD^1 # expect 83 (main-only commits reachable)
+```
+Expected: 2 parents (main tip + httpx tip), both "PRESERVED" lines print, count = 83.
+
+- [ ] **Step 8: No commit here** — the merge commit from Step 6 is the deliverable. Proceed to Task 2.
+
+---
+
+### Task 2: Replay X-Request-Id-on-5xx (the one missing feature)
+
+**Files:**
+- Modify (via cherry-pick `18e47b1`): `meraki/session/base.py`, `meraki/session/async_.py`
+- Test (via cherry-pick): `tests/unit/test_rest_session.py`, `tests/unit/test_aio_rest_session.py`, `tests/unit/conftest.py`
+- Add (via cherry-pick): `changelog.d/+log-x-request-id-on-5xx.added.md`
+
+**Interfaces:**
+- Consumes: merge commit from Task 1 (httpx `session/` layout).
+- Produces: X-Request-Id logging on 5xx responses in both sync and async sessions, with unit tests. `18e47b1` was built on an older base (`5da8e29`), so a conflict in `base.py`/`async_.py` is possible.
+
+- [ ] **Step 1: Confirm the feature is genuinely absent at the merge tip**
+
+```bash
+git show HEAD:meraki/session/base.py | grep -niE "x-request-id|request_id|requestId" || echo "ABSENT — cherry-pick needed"
+```
+Expected: "ABSENT — cherry-pick needed".
+
+- [ ] **Step 2: Cherry-pick the feature commit**
+
+```bash
+git cherry-pick 18e47b1
+```
+Expected: either clean success, OR a conflict in `meraki/session/base.py` / `meraki/session/async_.py`.
+
+- [ ] **Step 3: If conflict — resolve**
+
+Open each conflicted file. The intent: on a 5xx response, read the `X-Request-Id` response header and include it in the error log line. Keep httpx's surrounding code (its `session/base.py` structure), inserting only the request-id logging from the incoming patch. After resolving:
+
+```bash
+git add meraki/session/base.py meraki/session/async_.py
+git cherry-pick --continue
+```
+Expected: cherry-pick completes. If the changelog/test files also conflict, take the incoming (`--theirs`) version for the new changelog fragment and merge test additions.
+
+- [ ] **Step 4: Run the cherry-picked tests to verify they pass**
+
+```bash
+uv run pytest tests/unit/test_rest_session.py tests/unit/test_aio_rest_session.py -v -k "request_id or requestId or 5xx or request_id_log" 2>&1 | tail -30
+```
+Expected: the X-Request-Id tests from `18e47b1` PASS. If the `-k` filter matches nothing, run the two files in full and confirm the request-id tests are present and green.
+
+- [ ] **Step 5: No separate commit** — `git cherry-pick` already created the commit. Proceed to Task 3.
+
+---
+
+### Task 3: Full verification before handoff
+
+**Files:**
+- No edits. Verification only.
+
+**Interfaces:**
+- Consumes: `migrate/httpx` after Tasks 1-2.
+- Produces: evidence the merged tree imports and the httpx test suite passes on top of the merge. (Generated `meraki/api` is still beta here — regeneration is the maintainer's step, done after this plan.)
+
+- [ ] **Step 1: Sync dependencies to the merged lockfile**
+
+```bash
+uv sync
+```
+Expected: environment resolves against httpx's `uv.lock` (httpx, not requests). No errors.
+
+- [ ] **Step 2: Import smoke test (transport swap sanity)**
+
+```bash
+uv run python -c "import meraki; d = meraki.DashboardAPI.__init__; print('sync import OK'); import meraki.aio; print('async import OK')"
+```
+Expected: both "OK" lines print, no ImportError/ModuleNotFoundError referencing `rest_session`.
+
+- [ ] **Step 3: Run the unit + session test suite**
+
+```bash
+uv run pytest tests/unit -q 2>&1 | tail -30
+```
+Expected: all pass. These are httpx's own tests plus the cherry-picked request-id tests.
+
+- [ ] **Step 4: Run generator tests**
+
+```bash
+uv run pytest tests/generator -q 2>&1 | tail -20
+```
+Expected: pass (validates the httpx generator/scaffolding landed intact).
+
+- [ ] **Step 5: Lint**
+
+```bash
+uv run ruff check meraki tests 2>&1 | tail -20
+```
+Expected: clean, or only pre-existing httpx-branch findings (compare against `git show origin/httpx` if unsure).
+
+- [ ] **Step 6: Record verification result**
+
+If any step fails, STOP and report which — do not open the PR. If all pass, the branch is ready for the maintainer's regeneration step and PR.
+
+---
+
+### Task 4: Handoff for regeneration + PR (maintainer-owned)
+
+**Files:**
+- Maintainer regenerates: `meraki/api/**`, `meraki/aio/api/**`, `meraki/_version.py`, `meraki/__init__.py` (`__api_version__`).
+
+**Interfaces:**
+- Consumes: verified `migrate/httpx` branch.
+- Produces: GA-versioned generated code, then a PR into `main`.
+
+- [ ] **Step 1: Regenerate API surface to GA (maintainer runs the generator)**
+
+The generated code and version strings on the branch are currently httpx's beta values (`4.3.0b1`, `1.72.0-beta.1`). Maintainer runs the generator against the GA spec and sets the GA version. This plan does not prescribe the generator command — it is the maintainer's existing workflow.
+
+- [ ] **Step 2: Re-run verification after regeneration**
+
+```bash
+uv run pytest tests/unit tests/generator -q 2>&1 | tail -20
+uv run python -c "import meraki, meraki.aio; print('import OK')"
+```
+Expected: pass. Confirms regenerated code matches httpx session call signatures.
+
+- [ ] **Step 3: Push and open the PR**
+
+```bash
+git push -u origin migrate/httpx
+```
+Then open a PR `migrate/httpx -> main`. PR body should note: transport rewrite (requests → httpx), both histories preserved, X-Request-Id-on-5xx replayed, API regenerated to GA.
+
+- [ ] **Step 4: Do NOT delete branch `httpx`** until the PR is merged and the team confirms the dev track's next steps.
+
+---
+
+## Appendix: PyPI publish outage (root-caused during this migration)
+
+**Symptom:** Every beta/dev release after 2026-06-10 (`3.2.0b3`, `3.3.0b0`, `4.2.0b1/b2/b3`, `4.3.0b0/b1`) created a GitHub Release but never published to PyPI. GA releases (`3.2.0`, `3.3.0`) published fine.
+
+**Root cause:** `release`-triggered workflows run the workflow file from the **tagged commit's tree**, not the default branch. PRs #407 (`db0ddfe`, beta) and #408 (`1f84868`, httpx) deleted `publish-release.yml` from beta+httpx on 2026-06-10 as "unreachable orchestration." The first beta cut 7 minutes later (`4.2.0b1`) had no publish workflow in its tree, so the `release: created` event had nothing to run. GA survived because GA tags come off `main`, which kept the file. Truth table (publish-release.yml in tag tree ⟺ on PyPI) held with zero exceptions.
+
+**Forward fix (applied 2026-07-08):** restored `publish-release.yml` to `httpx` (`acbfd6a`), `beta` (`7fd69d5`), and `migrate/httpx` (`c7800d2`, part of this migration). `create-release`/`watch-openapi-release`/`regenerate-library`/`enable-early-access` correctly stay single-sourced on `main` (their `workflow_run`/`schedule`/`workflow_dispatch` triggers use main's copy; only `release`-triggered workflows must live on every release-cutting branch).
+
+**Backfill:** decided NOT to backfill the 8 orphaned PyPI versions — superseded quickly, and PyPI uploads are permanent/non-reusable. Gaps remain by choice.
diff --git a/examples/async_crud_lifecycle.py b/examples/async_crud_lifecycle.py
new file mode 100644
index 00000000..a79ac9cb
--- /dev/null
+++ b/examples/async_crud_lifecycle.py
@@ -0,0 +1,344 @@
+"""Async CRUD lifecycle demo for the Meraki Dashboard API Python SDK.
+
+Exercises create/update/delete workflows across org-level and network-level
+resources (policy objects, alerts profiles, group policies, MQTT brokers,
+webhooks, SSIDs, network settings, and action batches) using the async client.
+
+All operations run concurrently per org and each resource is fully cleaned up
+before the script exits.
+
+Usage:
+ export MERAKI_DASHBOARD_API_KEY=
+ python examples/async_crud_lifecycle.py
+"""
+
+import asyncio
+import hashlib
+import time
+from functools import wraps
+
+import meraki.aio
+
+
+KEYWORD = "TestKeyword"
+
+
+def _salt():
+ return hashlib.md5(str(time.time()).encode()).hexdigest()[:6]
+
+
+def timed(fn):
+ @wraps(fn)
+ async def wrapper(*args, **kwargs):
+ start = time.perf_counter()
+ result = await fn(*args, **kwargs)
+ elapsed = time.perf_counter() - start
+ return (*result, elapsed)
+
+ return wrapper
+
+
+@timed
+async def test_policy_object(dashboard, org_id, org_name):
+ """Create -> rename -> delete a policy object."""
+ salt = _salt()
+ print(f"[{org_name}] Creating policy object...")
+ obj = await dashboard.organizations.createOrganizationPolicyObject(
+ org_id,
+ name=f"test-policy-object-{salt}",
+ category="network",
+ type="cidr",
+ cidr="10.0.0.0/24",
+ )
+ obj_id = obj["id"]
+ print(f"[{org_name}] Created policy object: {obj_id}")
+
+ print(f"[{org_name}] Renaming policy object...")
+ await dashboard.organizations.updateOrganizationPolicyObject(org_id, obj_id, name=f"test-policy-object-{salt}-r")
+
+ print(f"[{org_name}] Deleting policy object...")
+ await dashboard.organizations.deleteOrganizationPolicyObject(org_id, obj_id)
+ print(f"[{org_name}] Policy object deleted.")
+
+ return ("policy_object", obj_id)
+
+
+@timed
+async def test_policy_object_group(dashboard, org_id, org_name):
+ """Create -> rename -> delete a policy object group."""
+ salt = _salt()
+ print(f"[{org_name}] Creating policy object group...")
+ group = await dashboard.organizations.createOrganizationPolicyObjectsGroup(
+ org_id, name=f"test-policy-group-{salt}", category="NetworkObjectGroup"
+ )
+ group_id = group["id"]
+ print(f"[{org_name}] Created policy object group: {group_id}")
+
+ print(f"[{org_name}] Renaming policy object group...")
+ await dashboard.organizations.updateOrganizationPolicyObjectsGroup(org_id, group_id, name=f"test-policy-group-{salt}-r")
+
+ print(f"[{org_name}] Deleting policy object group...")
+ await dashboard.organizations.deleteOrganizationPolicyObjectsGroup(org_id, group_id)
+ print(f"[{org_name}] Policy object group deleted.")
+
+ return ("policy_object_group", group_id)
+
+
+@timed
+async def test_alerts_profile(dashboard, org_id, org_name):
+ """Create -> update -> delete an org alerts profile."""
+ salt = _salt()
+ print(f"[{org_name}] Creating alerts profile...")
+ profile = await dashboard.organizations.createOrganizationAlertsProfile(
+ org_id,
+ type="wanUtilization",
+ alertCondition={"duration": 60, "window": 600, "bit_rate_bps": 1000000, "interface": "wan1"},
+ recipients={"emails": ["test@example.com"]},
+ networkTags=["__all_tags__"],
+ description=f"test-alert-profile-{salt}",
+ )
+ profile_id = profile["id"]
+ print(f"[{org_name}] Created alerts profile: {profile_id}")
+
+ print(f"[{org_name}] Updating alerts profile description...")
+ await dashboard.organizations.updateOrganizationAlertsProfile(
+ org_id, profile_id, description=f"test-alert-profile-{salt}-r"
+ )
+
+ print(f"[{org_name}] Deleting alerts profile...")
+ await dashboard.organizations.deleteOrganizationAlertsProfile(org_id, profile_id)
+ print(f"[{org_name}] Alerts profile deleted.")
+
+ return ("alerts_profile", profile_id)
+
+
+@timed
+async def test_group_policy(dashboard, net_id, org_name):
+ """Create -> update -> delete a group policy."""
+ salt = _salt()
+ print(f"[{org_name}] Creating group policy...")
+ gp = await dashboard.networks.createNetworkGroupPolicy(net_id, name=f"test-group-policy-{salt}")
+ gp_id = gp["groupPolicyId"]
+ print(f"[{org_name}] Created group policy: {gp_id}")
+
+ print(f"[{org_name}] Updating group policy...")
+ await dashboard.networks.updateNetworkGroupPolicy(net_id, gp_id, name=f"test-group-policy-{salt}-r")
+
+ print(f"[{org_name}] Deleting group policy...")
+ await dashboard.networks.deleteNetworkGroupPolicy(net_id, gp_id)
+ print(f"[{org_name}] Group policy deleted.")
+
+ return ("group_policy", gp_id)
+
+
+@timed
+async def test_mqtt_broker(dashboard, net_id, org_name):
+ """Create -> update -> delete an MQTT broker."""
+ salt = _salt()
+ print(f"[{org_name}] Creating MQTT broker...")
+ broker = await dashboard.networks.createNetworkMqttBroker(
+ net_id, name=f"test-mqtt-broker-{salt}", host="mqtt.example.com", port=1883
+ )
+ broker_id = broker["id"]
+ print(f"[{org_name}] Created MQTT broker: {broker_id}")
+
+ print(f"[{org_name}] Updating MQTT broker...")
+ await dashboard.networks.updateNetworkMqttBroker(net_id, broker_id, name=f"test-mqtt-broker-{salt}-r")
+
+ print(f"[{org_name}] Deleting MQTT broker...")
+ await dashboard.networks.deleteNetworkMqttBroker(net_id, broker_id)
+ print(f"[{org_name}] MQTT broker deleted.")
+
+ return ("mqtt_broker", broker_id)
+
+
+@timed
+async def test_webhook_http_server(dashboard, net_id, org_name):
+ """Create -> update -> delete a webhook HTTP server."""
+ salt = _salt()
+ print(f"[{org_name}] Creating webhook HTTP server...")
+ server = await dashboard.networks.createNetworkWebhooksHttpServer(
+ net_id, name=f"test-webhook-server-{salt}", url="https://example.com/webhook"
+ )
+ server_id = server["id"]
+ print(f"[{org_name}] Created webhook HTTP server: {server_id}")
+
+ print(f"[{org_name}] Updating webhook HTTP server...")
+ await dashboard.networks.updateNetworkWebhooksHttpServer(net_id, server_id, name=f"test-webhook-server-{salt}-r")
+
+ print(f"[{org_name}] Deleting webhook HTTP server...")
+ await dashboard.networks.deleteNetworkWebhooksHttpServer(net_id, server_id)
+ print(f"[{org_name}] Webhook HTTP server deleted.")
+
+ return ("webhook_http_server", server_id)
+
+
+@timed
+async def test_webhook_payload_template(dashboard, net_id, org_name):
+ """Create -> delete a webhook payload template."""
+ salt = _salt()
+ print(f"[{org_name}] Creating webhook payload template...")
+ template = await dashboard.networks.createNetworkWebhooksPayloadTemplate(
+ net_id,
+ name=f"test-payload-template-{salt}",
+ body='{"event": "{{alertType}}", "network": "{{networkName}}"}',
+ )
+ template_id = template["payloadTemplateId"]
+ print(f"[{org_name}] Created payload template: {template_id}")
+ print(f"[{org_name}] body: {template.get('body', '')[:80]}")
+
+ print(f"[{org_name}] Deleting payload template...")
+ await dashboard.networks.deleteNetworkWebhooksPayloadTemplate(net_id, template_id)
+ print(f"[{org_name}] Payload template deleted.")
+
+ return ("webhook_payload_template", template_id)
+
+
+@timed
+async def test_ssid(dashboard, net_id, org_name):
+ """Read -> update -> restore SSID 0."""
+ print(f"[{org_name}] Reading SSID 0...")
+ ssid = await dashboard.wireless.getNetworkWirelessSsid(net_id, "0")
+ original_name = ssid["name"]
+ print(f"[{org_name}] SSID 0 name: {original_name}")
+
+ new_name = "test-ssid-renamed"
+ print(f"[{org_name}] Updating SSID 0 name to '{new_name}'...")
+ await dashboard.wireless.updateNetworkWirelessSsid(net_id, "0", name=new_name)
+
+ print(f"[{org_name}] Restoring SSID 0 name to '{original_name}'...")
+ await dashboard.wireless.updateNetworkWirelessSsid(net_id, "0", name=original_name)
+ print(f"[{org_name}] SSID 0 restored.")
+
+ return ("ssid_0", net_id)
+
+
+@timed
+async def test_network_settings(dashboard, net_id, org_name):
+ """Read -> toggle -> restore network settings."""
+ print(f"[{org_name}] Reading network settings...")
+ settings = await dashboard.networks.getNetworkSettings(net_id)
+ original = settings.get("localStatusPageEnabled", True)
+ print(f"[{org_name}] localStatusPageEnabled = {original}")
+
+ toggled = not original
+ print(f"[{org_name}] Toggling localStatusPageEnabled to {toggled}...")
+ await dashboard.networks.updateNetworkSettings(net_id, localStatusPageEnabled=toggled)
+
+ print(f"[{org_name}] Restoring localStatusPageEnabled to {original}...")
+ await dashboard.networks.updateNetworkSettings(net_id, localStatusPageEnabled=original)
+ print(f"[{org_name}] Network settings restored.")
+
+ return ("network_settings", net_id)
+
+
+@timed
+async def test_action_batch(dashboard, org_id, net_id, org_name):
+ """Submit async action batch with 3 air marshal rules, poll to completion."""
+ actions = [
+ {
+ "resource": f"/networks/{net_id}/wireless/airMarshal/rules",
+ "operation": "create",
+ "body": {
+ "type": "block",
+ "match": {"string": f"test-rule-{i}", "type": "bssid"},
+ },
+ }
+ for i in range(1, 4)
+ ]
+
+ print(f"[{org_name}] Submitting action batch with 3 air marshal rules...")
+ batch = await dashboard.organizations.createOrganizationActionBatch(org_id, actions, confirmed=True, synchronous=False)
+ batch_id = batch["id"]
+ print(f"[{org_name}] Action batch submitted: {batch_id}")
+
+ while True:
+ status = await dashboard.organizations.getOrganizationActionBatch(org_id, batch_id)
+ if status["status"]["completed"]:
+ break
+ if status["status"]["failed"]:
+ raise RuntimeError(f"Action batch {batch_id} failed in org {org_id}")
+ await asyncio.sleep(1)
+
+ print(f"[{org_name}] Action batch completed. Rules created:")
+ for action in status["actions"]:
+ rule = action.get("body", {})
+ print(f" - type={rule.get('type')}, match={rule.get('match')}")
+
+ return ("action_batch", batch_id)
+
+
+async def process_org(dashboard, org):
+ org_id = org["id"]
+ org_name = org["name"]
+
+ # Create network (needed for network-level tests)
+ print(f"[{org_name}] Creating wireless network...")
+ network = await dashboard.organizations.createOrganizationNetwork(
+ org_id,
+ name=f"test-airmarshal-network-{_salt()}",
+ productTypes=["wireless"],
+ )
+ net_id = network["id"]
+ print(f"[{org_name}] Created network: {net_id}")
+
+ # Run all tests concurrently
+ results = await asyncio.gather(
+ # Org-level (no network dependency)
+ test_policy_object(dashboard, org_id, org_name),
+ test_policy_object_group(dashboard, org_id, org_name),
+ test_alerts_profile(dashboard, org_id, org_name),
+ # Network-level
+ test_group_policy(dashboard, net_id, org_name),
+ test_mqtt_broker(dashboard, net_id, org_name),
+ test_webhook_http_server(dashboard, net_id, org_name),
+ test_webhook_payload_template(dashboard, net_id, org_name),
+ test_ssid(dashboard, net_id, org_name),
+ test_network_settings(dashboard, net_id, org_name),
+ test_action_batch(dashboard, org_id, net_id, org_name),
+ )
+
+ # Delete the network
+ print(f"[{org_name}] Deleting network {net_id}...")
+ await dashboard.networks.deleteNetwork(net_id)
+ print(f"[{org_name}] Network deleted.")
+
+ return {
+ "org_id": org_id,
+ "network_id": net_id,
+ "resources": list(results),
+ }
+
+
+async def main():
+ total_start = time.perf_counter()
+
+ async with meraki.aio.AsyncDashboardAPI(suppress_logging=True) as dashboard:
+ orgs = await dashboard.organizations.getOrganizations()
+ targets = [o for o in orgs if KEYWORD in o["name"]]
+
+ results = await asyncio.gather(*(process_org(dashboard, org) for org in targets))
+
+ total_elapsed = time.perf_counter() - total_start
+
+ print("\n" + "=" * 60)
+ print("Resources touched:")
+ print("=" * 60)
+ for r in results:
+ print(f"\nOrg: {r['org_id']}")
+ print(f" Network: {r['network_id']}")
+ for resource_type, resource_id, elapsed in r["resources"]:
+ print(f" {resource_type}: {resource_id} ({elapsed:.2f}s)")
+
+ print("\n" + "=" * 60)
+ print("Timing summary:")
+ print("=" * 60)
+ for r in results:
+ print(f"\nOrg: {r['org_id']}")
+ for resource_type, _, elapsed in r["resources"]:
+ print(f" {resource_type:30s} {elapsed:6.2f}s")
+ print(f"\nTotal elapsed: {total_elapsed:.2f}s")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/ci/enable_all_early_access.py b/examples/ci/enable_all_early_access.py
deleted file mode 100644
index 19a7b5ed..00000000
--- a/examples/ci/enable_all_early_access.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""Opt in to all available early access features for Meraki organizations.
-
-Reads EA_ORG_0 through EA_ORG_7 from the environment, and for each org
-fetches the feature list, creates org-wide opt-ins for any features not
-already enabled, and prints a summary report.
-
-WARNING: This will subject the organizations to unannounced breaking API
-changes.
-"""
-
-import asyncio
-import os
-import sys
-
-import meraki.aio
-
-ORG_IDS: list[str] = [v for i in range(8) if (v := os.environ.get(f"EA_ORG_{i}", ""))]
-if not ORG_IDS:
- sys.exit("No EA_ORG_* environment variables are set")
-
-
-async def enable_early_access(dashboard, org_id: str):
- features = await dashboard.organizations.getOrganizationEarlyAccessFeatures(org_id)
- opt_ins = await dashboard.organizations.getOrganizationEarlyAccessFeaturesOptIns(org_id)
-
- opted_in_short_names = {oi["shortName"] for oi in opt_ins}
-
- tasks = []
- for feature in features:
- if feature["shortName"] not in opted_in_short_names:
- tasks.append(dashboard.organizations.createOrganizationEarlyAccessFeaturesOptIn(org_id, feature["shortName"]))
-
- new_opt_ins = await asyncio.gather(*tasks) if tasks else []
-
- all_opt_ins = opt_ins + list(new_opt_ins)
- print(f"\nOrg {org_id}: enabled {len(new_opt_ins)} new features ({len(opt_ins)} already opted in)")
- print(f" All early access features ({len(all_opt_ins)} total):")
- for oi in all_opt_ins:
- print(f" - {oi['shortName']}")
-
- return all_opt_ins
-
-
-async def main():
- async with meraki.aio.AsyncDashboardAPI(suppress_logging=True) as dashboard:
- results = await asyncio.gather(*(enable_early_access(dashboard, org_id) for org_id in ORG_IDS))
- return results
-
-
-if __name__ == "__main__":
- asyncio.run(main())
diff --git a/examples/ssid_tool/ssid_tool.py b/examples/ssid_tool/ssid_tool.py
index 0251ba7c..029d1cf8 100644
--- a/examples/ssid_tool/ssid_tool.py
+++ b/examples/ssid_tool/ssid_tool.py
@@ -9,7 +9,7 @@
import meraki.aio
from meraki.exceptions import AsyncAPIError
-TOOL_VERSION = "1.0.0"
+TOOL_VERSION = "0.1.0b"
DEFAULT_NETWORK_ID = ""
DEFAULT_ORG_ID = ""
BACKUP_DIR = Path(__file__).parent / "ssid_backups"
@@ -264,8 +264,8 @@ async def _fetch_main():
async def backup_all_ssids(api: meraki.aio.AsyncDashboardAPI, network_id: str) -> tuple[Path, list]:
- today = datetime.now().strftime("%Y-%m-%d")
- filename = f"{today}-{network_id}-ssids.jsonc"
+ timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
+ filename = f"{timestamp}-{network_id}-ssids.jsonc"
filepath = BACKUP_DIR / filename
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
@@ -289,7 +289,7 @@ async def _backup_slot(ssid: dict):
header = f"// SSID Backup - ssid_tool v{TOOL_VERSION}\n// {datetime.now().isoformat()}\n// Network: {network_id}\n"
with open(filepath, "w", encoding="utf-8") as f:
f.write(header)
- json.dump(all_ssids, f, indent=2)
+ json.dump(all_ssids, f, indent=2, ensure_ascii=False)
return filepath, all_errors
@@ -300,10 +300,6 @@ async def swap_ssid_slots(
slot_a: int,
slot_b: int,
) -> dict:
- cprint(" Creating safety backup...", Color.YELLOW)
- backup_path, _ = await backup_all_ssids(api, network_id)
- cprint(f" Saved: {backup_path.name}", Color.GREEN)
-
async with AsyncSpinner(f"Reading slots {slot_a} and {slot_b}"):
(config_a, _), (config_b, _) = await asyncio.gather(
fetch_ssid_full_config(api, network_id, slot_a),
@@ -312,6 +308,13 @@ async def swap_ssid_slots(
results = {"success": [], "failed": []}
+ # Free up SSID names to avoid uniqueness constraint during swap
+ async with AsyncSpinner("Preparing swap"):
+ await asyncio.gather(
+ api.wireless.updateNetworkWirelessSsid(network_id, str(slot_a), name=f"_swap_tmp_{slot_a}"),
+ api.wireless.updateNetworkWirelessSsid(network_id, str(slot_b), name=f"_swap_tmp_{slot_b}"),
+ )
+
async with AsyncSpinner("Swapping configurations"):
async def _apply(resource_name, src_slot, dst_slot, config):
@@ -327,6 +330,8 @@ async def _apply(resource_name, src_slot, dst_slot, config):
swap_tasks = []
for resource_name in SSID_SUB_RESOURCES:
+ if resource_name in ("vpn", "hotspot20"):
+ continue
swap_tasks.append(_apply(resource_name, slot_a, slot_b, config_a))
swap_tasks.append(_apply(resource_name, slot_b, slot_a, config_b))
@@ -459,9 +464,7 @@ async def main() -> None:
sys.exit(1)
async with meraki.aio.AsyncDashboardAPI(
- output_log=False,
- print_console=False,
- maximum_retries=10,
+ output_log=True, print_console=False, maximum_retries=10, smart_flow=True, smart_flow_logging=True
) as api:
while True:
display_menu()
@@ -476,15 +479,28 @@ async def main() -> None:
display_report("Backup Complete", results)
elif choice == "2":
+ async with AsyncSpinner("Fetching current SSIDs"):
+ ssids = await api.wireless.getNetworkWirelessSsids(network_id)
+ display_ssid_summary(ssids)
+
+ backup_task = asyncio.create_task(backup_all_ssids(api, network_id))
+
try:
slot_a = int(input(f"{Color.YELLOW} First SSID slot (0-14): {Color.RESET}"))
slot_b = int(input(f"{Color.YELLOW} Second SSID slot (0-14): {Color.RESET}"))
except ValueError:
cprint(" Invalid input.", Color.RED)
+ backup_task.cancel()
continue
if not (0 <= slot_a <= 14 and 0 <= slot_b <= 14 and slot_a != slot_b):
cprint(" Slots must be 0-14 and different.", Color.RED)
+ backup_task.cancel()
continue
+
+ cprint(" Waiting for backup to complete...", Color.DIM)
+ backup_path, _ = await backup_task
+ cprint(f" Saved: {backup_path.name}", Color.GREEN)
+
results = await swap_ssid_slots(api, network_id, slot_a, slot_b)
display_report(f"Swap: Slot {slot_a} <-> Slot {slot_b}", results)
diff --git a/generator/async_function_template.jinja2 b/generator/async_function_template.jinja2
index bcc5faef..99a30c84 100644
--- a/generator/async_function_template.jinja2
+++ b/generator/async_function_template.jinja2
@@ -11,6 +11,13 @@
{% if kwarg_line|length > 0 %}
{{ kwarg_line }}
+ {% if renamed_params|length > 0 %}
+ {% for safe, orig in renamed_params.items() %}
+ if "{{ safe }}" in kwargs:
+ kwargs["{{ orig }}"] = kwargs.pop("{{ safe }}")
+ {% endfor %}
+
+ {% endif %}
{% endif %}
{% if assert_blocks|length > 0 %}
{% for param, values, nullable in assert_blocks %}
diff --git a/generator/batch_function_template.jinja2 b/generator/batch_function_template.jinja2
index 33d7e712..3a30a25a 100644
--- a/generator/batch_function_template.jinja2
+++ b/generator/batch_function_template.jinja2
@@ -10,11 +10,14 @@
{% if kwarg_line|length > 0 %}
{{ kwarg_line }}
- {% for safe_name, original_name in (renamed_params | default({})).items() %}
- if "{{ safe_name }}" in kwargs:
- kwargs["{{ original_name }}"] = kwargs.pop("{{ safe_name }}")
+
+ {% if renamed_params|length > 0 %}
+ {% for safe, orig in renamed_params.items() %}
+ if "{{ safe }}" in kwargs:
+ kwargs["{{ orig }}"] = kwargs.pop("{{ safe }}")
{% endfor %}
+ {% endif %}
{% endif %}
{% if assert_blocks|length > 0 %}
{% for param, values, nullable in assert_blocks %}
@@ -25,7 +28,7 @@
{% endif %}
{% for param in path_params %}
- {{ param }} = urllib.parse.quote({{ param }}, safe="")
+ {{ param }} = urllib.parse.quote(str({{ param }}), safe="")
{% endfor %}
resource = f"{{ resource }}"
diff --git a/generator/common.py b/generator/common.py
index d3b64416..38b1d1e2 100644
--- a/generator/common.py
+++ b/generator/common.py
@@ -1,3 +1,124 @@
+import platform
+import sys
+
+
+REVERSE_PAGINATION = ["getNetworkEvents", "getOrganizationConfigurationChanges"]
+
+
+def generate_pagination_parameters(operation: str):
+ ret = {
+ "total_pages": {
+ "type": "integer or string",
+ "description": 'use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages',
+ },
+ "direction": {
+ "type": "string",
+ "description": 'direction to paginate, either "next" or "prev" (default) page'
+ if operation in REVERSE_PAGINATION
+ else 'direction to paginate, either "next" (default) or "prev" page',
+ },
+ }
+ if operation == "getNetworkEvents":
+ ret["event_log_end_time"] = {
+ "type": "string",
+ "description": "ISO8601 Zulu/UTC time, to use in conjunction with startingAfter, "
+ "to retrieve events within a time window",
+ }
+ return ret
+
+
+def check_python_version():
+ version_warning_string = (
+ f"This library generator requires Python 3.10 at minimum. "
+ f"Your interpreter version is: {platform.python_version()}. "
+ f"Please consult the readme at your convenience: "
+ f"https://github.com/meraki/dashboard-api-python/blob/main/generator/readme.md "
+ f"Additional details: "
+ f"python_version_tuple()[0] = {platform.python_version_tuple()[0]}; "
+ f"python_version_tuple()[1] = {platform.python_version_tuple()[1]} "
+ )
+
+ if not (int(platform.python_version_tuple()[0]) == 3 and int(platform.python_version_tuple()[1]) >= 10):
+ sys.exit(version_warning_string)
+
+
+def docs_url(operation: str):
+ base_url = "https://developer.cisco.com/meraki/api-v1/#!"
+ ret = ""
+ for letter in operation:
+ if letter.islower():
+ ret += letter
+ else:
+ ret += f"-{letter.lower()}"
+ return base_url + ret
+
+
+def return_params(operation: str, params: dict, param_filters):
+ if not param_filters:
+ return params
+ else:
+ ret = {}
+ if "required" in param_filters:
+ ret.update({k: v for k, v in params.items() if "required" in v and v["required"]})
+ if "pagination" in param_filters:
+ ret.update(generate_pagination_parameters(operation) if "perPage" in params else {})
+ if "optional" in param_filters:
+ ret.update({k: v for k, v in params.items() if "required" in v and not v["required"]})
+ if "path" in param_filters:
+ ret.update({k: v for k, v in params.items() if "in" in v and v["in"] == "path"})
+ if "query" in param_filters:
+ ret.update({k: v for k, v in params.items() if "in" in v and v["in"] == "query"})
+ if "body" in param_filters:
+ ret.update({k: v for k, v in params.items() if "in" in v and v["in"] == "body"})
+ if "array" in param_filters:
+ ret.update({k: v for k, v in params.items() if "in" in v and v["type"] == "array"})
+ if "enum" in param_filters:
+ ret.update({k: v for k, v in params.items() if "enum" in v})
+ return ret
+
+
+def unpack_param_without_schema(all_params: dict, this_param: dict, name: str, is_required: bool):
+ all_params[name] = {"required": is_required}
+
+ for attribute in ("in", "type"):
+ all_params[name][attribute] = this_param[attribute]
+
+ if "enum" in this_param:
+ all_params[name]["enum"] = this_param["enum"]
+
+ if "description" in this_param:
+ all_params[name]["description"] = this_param["description"]
+ elif is_required:
+ all_params[name]["description"] = "(required)"
+ else:
+ all_params[name]["description"] = this_param.get("description", "")
+
+ return all_params
+
+
+def unpack_param_with_schema(all_params: dict, this_param: dict):
+ keys = this_param["schema"]["properties"]
+
+ for k in keys:
+ if "required" in this_param["schema"] and k in this_param["schema"]["required"]:
+ all_params[k] = {"required": True}
+ else:
+ all_params[k] = {"required": False}
+
+ all_params[k]["in"] = this_param["in"]
+
+ for attribute in ("type", "description"):
+ all_params[k][attribute] = keys[k][attribute]
+
+ if "enum" in keys[k]:
+ all_params[k]["enum"] = keys[k]["enum"]
+
+ if "example" in this_param["schema"] and k in this_param["schema"]["example"]:
+ all_params[k]["example"] = this_param["schema"]["example"][k]
+
+ return all_params
+
+
def organize_spec(paths, scopes):
operations = list() # list of operation IDs
for path, methods in paths.items():
diff --git a/generator/function_template.jinja2 b/generator/function_template.jinja2
index 24f72789..14b51eb9 100644
--- a/generator/function_template.jinja2
+++ b/generator/function_template.jinja2
@@ -10,11 +10,14 @@
{% if kwarg_line|length > 0 %}
{{ kwarg_line }}
- {% for safe_name, original_name in (renamed_params | default({})).items() %}
- if "{{ safe_name }}" in kwargs:
- kwargs["{{ original_name }}"] = kwargs.pop("{{ safe_name }}")
+
+ {% if renamed_params|length > 0 %}
+ {% for safe, orig in renamed_params.items() %}
+ if "{{ safe }}" in kwargs:
+ kwargs["{{ orig }}"] = kwargs.pop("{{ safe }}")
{% endfor %}
+ {% endif %}
{% endif %}
{% if assert_blocks|length > 0 %}
{% for param, values, nullable in assert_blocks %}
diff --git a/generator/generate_library.py b/generator/generate_library.py
index d1d4268b..812b6e57 100644
--- a/generator/generate_library.py
+++ b/generator/generate_library.py
@@ -7,16 +7,11 @@
import sys
import jinja2
-import requests
+import httpx
import common as common
+from common import REVERSE_PAGINATION, docs_url, check_python_version, return_params
from parser_v3 import parse_params_v3, clear_cache
-from generate_library_oasv2 import (
- REVERSE_PAGINATION,
- docs_url,
- check_python_version,
- return_params,
-)
from generate_stubs import generate_stub_modules
@@ -32,9 +27,8 @@ def safe_param_name(name: str) -> str:
def _write_generation_report(version_number: str, api_version_number: str, is_github_action: bool):
from datetime import date
- report_path = "docs/generation-report.md" if is_github_action else "docs/generation-report.md"
+ report_path = "docs/generation-report.md"
- # Deduplicate violations (same operation+param recorded from both standard and batch)
seen = set()
unique_violations = []
for v in _keyword_param_violations:
@@ -43,7 +37,6 @@ def _write_generation_report(version_number: str, api_version_number: str, is_gi
seen.add(key)
unique_violations.append(v)
- # Build the new entry
lines = []
lines.append(f"## {date.today().isoformat()} | Library v{version_number} | API {api_version_number}\n")
lines.append("")
@@ -66,7 +59,6 @@ def _write_generation_report(version_number: str, api_version_number: str, is_gi
new_entry = "\n".join(lines)
- # Read existing content (skip the title header if present)
existing = ""
header = "# Generation Report\n\n"
if os.path.isfile(report_path):
@@ -84,8 +76,8 @@ def _write_generation_report(version_number: str, api_version_number: str, is_gi
READ_ME = """
=== PREREQUISITES ===
-Include the jinja2 files in same directory as this script, and install Python requests
-pip[3] install requests
+Include the jinja2 files in same directory as this script, and install Python httpx
+pip[3] install httpx
=== DESCRIPTION ===
This script generates the Meraki Python library from the OpenAPI v3 specification.
@@ -99,7 +91,13 @@ def _write_generation_report(version_number: str, api_version_number: str, is_gi
def generate_library(
- spec: dict, version_number: str, api_version_number: str, is_github_action: bool, generate_stubs: bool = False
+ spec: dict,
+ version_number: str,
+ api_version_number: str,
+ is_github_action: bool,
+ generate_stubs: bool = False,
+ local_source: bool = False,
+ source_branch: str = "master",
):
# Clear parser cache at entry
clear_cache()
@@ -158,6 +156,7 @@ def generate_library(
# Check paths and create directories if needed
directories = [
"meraki",
+ "meraki/session",
"meraki/api",
"meraki/api/batch",
"meraki/aio",
@@ -173,22 +172,33 @@ def generate_library(
"_version.py",
"config.py",
"common.py",
+ "encoding.py",
"exceptions.py",
"response_handler.py",
- "rest_session.py",
+ "session/__init__.py",
+ "session/base.py",
+ "session/sync.py",
+ "session/async_.py",
"api/__init__.py",
"aio/__init__.py",
- "aio/rest_session.py",
"aio/api/__init__.py",
"api/batch/__init__.py",
+ "smart_flow.py",
]
- base_url = "https://raw.githubusercontent.com/meraki/dashboard-api-python/master/meraki/"
+ if local_source:
+ repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ local_meraki = os.path.join(repo_root, "meraki")
+ else:
+ base_url = f"https://raw.githubusercontent.com/meraki/dashboard-api-python/{source_branch}/meraki/"
for file in non_generated:
- response = requests.get(f"{base_url}{file}")
- with open(f"meraki/{file}", "w+", encoding="utf-8", newline=None) as fp:
+ if local_source:
+ with open(os.path.join(local_meraki, file), encoding="utf-8") as src:
+ contents = src.read()
+ else:
+ response = httpx.get(f"{base_url}{file}")
contents = response.text
+ with open(f"meraki/{file}", "w+", encoding="utf-8", newline=None) as fp:
if file == "_version.py":
- # replace library version
start = contents.find("__version__ = ")
end = contents.find("\n", start)
contents = f"{contents[:start]}__version__ = '{version_number}'{contents[end:]}"
@@ -222,7 +232,8 @@ def generate_library(
print("Generating .pyi type stubs...")
generate_stub_modules(spec, scopes, jinja_env, template_dir)
# Write py.typed marker for PEP 561
- open("meraki/py.typed", "w").close()
+ repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ open(os.path.join(repo_root, "meraki", "py.typed"), "w").close()
print("Type stubs and py.typed marker created.")
# Format generated code with ruff
@@ -240,12 +251,11 @@ def generate_modules(spec, batchable_actions, jinja_env, scopes, template_dir):
section = scopes[scope]
# Generate the standard module
- with open(f"meraki/api/{scope}.py", "w", encoding="utf-8", newline=None) as output:
- # Open module file for Asyncio API libraries
- async_output = open(f"meraki/aio/api/{scope}.py", "w", encoding="utf-8", newline=None)
- # Open module file for Action Batch API libraries
- batch_output = open(f"meraki/api/batch/{scope}.py", "w", encoding="utf-8", newline=None)
-
+ with (
+ open(f"meraki/api/{scope}.py", "w", encoding="utf-8", newline=None) as output,
+ open(f"meraki/aio/api/{scope}.py", "w", encoding="utf-8", newline=None) as async_output,
+ open(f"meraki/api/batch/{scope}.py", "w", encoding="utf-8", newline=None) as batch_output,
+ ):
modules = [
{"template_name": "class_template.jinja2", "module_output": output},
{
@@ -382,6 +392,10 @@ def generate_standard_and_async_functions(
if operation == "getNetworkEvents":
definition += ", event_log_end_time=None"
+ # call_line is bound per-method below; initialize to fail loudly if a
+ # method slips through without setting it (rather than raising NameError).
+ call_line = None
+
# Function body for GET endpoints
query_params = array_params = body_params = path_params = {}
if method == "get":
@@ -389,8 +403,8 @@ def generate_standard_and_async_functions(
array_params = return_params(operation, all_params, ["array"])
path_params = return_params(operation, all_params, ["path"])
- # Function body for POST/PUT endpoints
- elif method == "post" or method == "put":
+ # Function body for POST/PUT/PATCH endpoints
+ elif method == "post" or method == "put" or method == "patch":
body_params = return_params(operation, all_params, ["body"])
path_params = return_params(operation, all_params, ["path"])
@@ -437,7 +451,7 @@ def generate_standard_and_async_functions(
else:
call_line = "return self._session.get(metadata, resource)"
- elif method == "post" or method == "put":
+ elif method == "post" or method == "put" or method == "patch":
if body_params:
call_line = f"return self._session.{method}(metadata, resource, payload)"
else:
@@ -449,6 +463,8 @@ def generate_standard_and_async_functions(
else:
call_line = "return self._session.delete(metadata, resource)"
+ assert call_line is not None, f"call_line was not set for {operation} (method={method})"
+
# Ensure all URL-referenced params get quote lines in the template
for p in re.findall(r"\{(\w+)\}", path):
if p not in path_params:
@@ -720,9 +736,11 @@ def main(inputs):
api_version_number = "custom"
is_github_action = False
generate_stubs_flag = False
+ local_source = False
+ source_branch = "master"
try:
- opts, args = getopt.getopt(inputs, "ho:k:v:a:g:s")
+ opts, args = getopt.getopt(inputs, "ho:k:v:a:g:slb:")
except getopt.GetoptError:
print_help()
sys.exit(2)
@@ -743,6 +761,10 @@ def main(inputs):
is_github_action = True
elif opt == "-s":
generate_stubs_flag = True
+ elif opt == "-l":
+ local_source = True
+ elif opt == "-b":
+ source_branch = arg
check_python_version()
@@ -752,19 +774,19 @@ def main(inputs):
print_help()
sys.exit(2)
else:
- response = requests.get(
+ response = httpx.get(
f"https://api.meraki.com/api/v1/organizations/{org_id}/openapiSpec",
headers={"Authorization": f"Bearer {api_key}"},
params={"version": 3},
)
- if response.ok:
+ if response.status_code == 200:
spec = response.json()
else:
print_help()
sys.exit(f"API key provided does not have access to org {org_id}")
else:
- response = requests.get("https://api.meraki.com/api/v1/openapiSpec", params={"version": 3})
- if response.ok:
+ response = httpx.get("https://api.meraki.com/api/v1/openapiSpec", params={"version": 3})
+ if response.status_code == 200:
spec = response.json()
print("Successfully pulled Meraki dashboard API OpenAPI v3 spec.")
else:
@@ -774,7 +796,15 @@ def main(inputs):
"If this continues for more than an hour, please contact Meraki support."
)
- generate_library(spec, version_number, api_version_number, is_github_action, generate_stubs=generate_stubs_flag)
+ generate_library(
+ spec,
+ version_number,
+ api_version_number,
+ is_github_action,
+ generate_stubs=generate_stubs_flag,
+ local_source=local_source,
+ source_branch=source_branch,
+ )
if __name__ == "__main__":
diff --git a/generator/generate_library_oasv2.py b/generator/generate_library_oasv2.py
deleted file mode 100644
index f46784c3..00000000
--- a/generator/generate_library_oasv2.py
+++ /dev/null
@@ -1,816 +0,0 @@
-import getopt
-import json
-import os
-import platform
-import re
-import subprocess
-import sys
-import warnings
-
-import jinja2
-import requests
-
-import common as common
-
-if __name__ == "__main__" or "generate_library_oasv2" in sys.argv[0]:
- warnings.warn(
- "generate_library_oasv2.py is deprecated and will be removed in v1.2. Use generate_library.py instead.",
- DeprecationWarning,
- stacklevel=2,
- )
-
-READ_ME = """
-=== PREREQUISITES ===
-Include the jinja2 files in same directory as this script, and install Python requests
-pip[3] install requests
-
-=== DESCRIPTION ===
-This script generates the Meraki Python library using either the public OpenAPI specification, or, with an API key & org
-ID as inputs, a specific dashboard org's OpenAPI spec.
-
-=== USAGE === python[3] generate_library.py [-o ] [-k ] [-v ] [-a
-] [-g ]
-
-API key can, and is recommended to, be set as an environment variable named MERAKI_DASHBOARD_API_KEY."""
-
-REVERSE_PAGINATION = ["getNetworkEvents", "getOrganizationConfigurationChanges"]
-
-
-# Helper function to return pagination parameters depending on endpoint
-def generate_pagination_parameters(operation: str):
- ret = {
- "total_pages": {
- "type": "integer or string",
- "description": 'use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages',
- },
- "direction": {
- "type": "string",
- "description": 'direction to paginate, either "next" or "prev" (default) page'
- if operation in REVERSE_PAGINATION
- else 'direction to paginate, either "next" (default) or "prev" page',
- },
- }
- if operation == "getNetworkEvents":
- ret["event_log_end_time"] = {
- "type": "string",
- "description": "ISO8601 Zulu/UTC time, to use in conjunction with startingAfter, "
- "to retrieve events within a time window",
- }
- return ret
-
-
-def check_python_version():
- # Check minimum Python version
- version_warning_string = (
- f"This library generator requires Python 3.10 at minimum. "
- f"Your interpreter version is: {platform.python_version()}. "
- f"Please consult the readme at your convenience: "
- f"https://github.com/meraki/dashboard-api-python/blob/main/generator/readme.md "
- f"Additional details: "
- f"python_version_tuple()[0] = {platform.python_version_tuple()[0]}; "
- f"python_version_tuple()[1] = {platform.python_version_tuple()[1]} "
- )
-
- if not (int(platform.python_version_tuple()[0]) == 3 and int(platform.python_version_tuple()[1]) >= 10):
- sys.exit(version_warning_string)
-
-
-# Returns full link to endpoint's documentation on Developer Hub
-# Note: updates to the documentation site may impact these URLs.
-def docs_url(operation: str):
- base_url = "https://developer.cisco.com/meraki/api-v1/#!"
- ret = ""
- for letter in operation:
- if letter.islower():
- ret += letter
- else:
- ret += f"-{letter.lower()}"
- return base_url + ret
-
-
-# Helper function to return the right params; used in parse_params
-def return_params(operation: str, params: dict, param_filters):
- # Return parameters based on matching input filters
- if not param_filters:
- return params
- else:
- ret = {}
- if "required" in param_filters:
- ret.update({k: v for k, v in params.items() if "required" in v and v["required"]})
- if "pagination" in param_filters:
- ret.update(generate_pagination_parameters(operation) if "perPage" in params else {})
- if "optional" in param_filters:
- ret.update({k: v for k, v in params.items() if "required" in v and not v["required"]})
- if "path" in param_filters:
- ret.update({k: v for k, v in params.items() if "in" in v and v["in"] == "path"})
- if "query" in param_filters:
- ret.update({k: v for k, v in params.items() if "in" in v and v["in"] == "query"})
- if "body" in param_filters:
- ret.update({k: v for k, v in params.items() if "in" in v and v["in"] == "body"})
- if "array" in param_filters:
- ret.update({k: v for k, v in params.items() if "in" in v and v["type"] == "array"})
- if "enum" in param_filters:
- ret.update({k: v for k, v in params.items() if "enum" in v})
- return ret
-
-
-def unpack_param_without_schema(all_params: dict, this_param: dict, name: str, is_required: bool):
- # Set required attribute
- all_params[name] = {"required": is_required}
-
- # Assign relevant attributes
- for attribute in ("in", "type"):
- all_params[name][attribute] = this_param[attribute]
-
- # Capture the enum if available
- if "enum" in this_param:
- all_params[name]["enum"] = this_param["enum"]
-
- # Assign the description to the parameter if it's available
- if "description" in this_param:
- all_params[name]["description"] = this_param["description"]
-
- # Fall back to required if there is no description
- elif is_required:
- all_params[name]["description"] = "(required)"
-
- # Fall back to whatever the description is otherwise
- else:
- all_params[name]["description"] = this_param["description"]
-
- return all_params
-
-
-def unpack_param_with_schema(all_params: dict, this_param: dict):
- # the parameter will have a top-level object 'schema' and within that, 'properties' in OASv2
- # in OASv3, the parameter will only have this for query and path parameters, and requestBody params
- # will be in a separate key
- keys = this_param["schema"]["properties"]
-
- # parse the properties and assign types and descriptions
- for k in keys:
- # if required, set required true
- if "required" in this_param["schema"] and k in this_param["schema"]["required"]:
- all_params[k] = {"required": True}
- else:
- all_params[k] = {"required": False}
-
- # identify whether the parameter is in the path or query, or for OASv2, in the body
- all_params[k]["in"] = this_param["in"]
-
- # assign the right data type/description to the parameter per the schema
- for attribute in ("type", "description"):
- all_params[k][attribute] = keys[k][attribute]
-
- # capture schema enum if available
- if "enum" in keys[k]:
- all_params[k]["enum"] = keys[k]["enum"]
-
- # capture schema example if available
- if "example" in this_param["schema"] and k in this_param["schema"]["example"]:
- all_params[k]["example"] = this_param["schema"]["example"][k]
-
- return all_params
-
-
-def unpack_params(operation: str, parameters: dict, param_filters):
- # Create dict with information on endpoint's parameters
- unpacked_params = dict()
-
- # Iterate through the endpoint's parameters
- for p in parameters:
- # Name the parameter
- name = p["name"]
-
- # Consult the schema if there is one and it has properties (object-type params)
- if "schema" in p and "properties" in p["schema"]:
- unpacked_params.update(unpack_param_with_schema(unpacked_params, p))
-
- # Schema exists but no properties (simple type like string/integer)
- elif "schema" in p:
- is_required = p.get("required", False)
- flat_param = {**p, "type": p["schema"].get("type", "string")}
- if "enum" in p["schema"]:
- flat_param["enum"] = p["schema"]["enum"]
- unpacked_params.update(unpack_param_without_schema(unpacked_params, flat_param, name, is_required))
-
- # If there is no schema, then consult the required attribute if it exists
- elif "required" in p and p["required"]:
- unpacked_params.update(unpack_param_without_schema(unpacked_params, p, name, True))
-
- # Otherwise, the parameter is not required
- else:
- unpacked_params.update(unpack_param_without_schema(unpacked_params, p, name, False))
-
- # Add custom library parameters to handle pagination
- if "perPage" in unpacked_params:
- unpacked_params.update(generate_pagination_parameters(operation))
-
- # Return parameters based on matching input filters
- return return_params(operation, unpacked_params, param_filters)
-
-
-# Helper function to return parameters within OAS spec, optionally based on list of input filters
-def parse_params(operation: str, parameters: dict, param_filters=None):
- if param_filters is None:
- param_filters = list()
- if parameters is None:
- return {}
-
- return unpack_params(operation, parameters, param_filters)
-
-
-def generate_library(spec: dict, version_number: str, api_version_number: str, is_github_action: bool):
- # Supported scopes list will include organizations, networks, devices, and all product types.
- supported_scopes = [
- "organizations",
- "networks",
- "devices",
- "appliance",
- "camera",
- "cellularGateway",
- "insight",
- "sm",
- "switch",
- "wireless",
- "sensor",
- "administered",
- "licensing",
- "secureConnect",
- "wirelessController",
- "campusGateway",
- "spaces",
- "nac",
- ]
- # legacy scopes = ['organizations', 'networks', 'devices', 'appliance', 'camera', 'cellularGateway', 'insight',
- # 'sm', 'switch', 'wireless']
- tags = spec["tags"]
- paths = spec["paths"]
- # Scopes used when generating the library will depend on the provided version of the API spec.
- scopes = {tag["name"]: {} for tag in tags if tag["name"] in supported_scopes}
-
- batchable_actions = spec["x-batchable-actions"]
-
- # Set template_dir if a GitHub action is invoking it
- if is_github_action:
- template_dir = "generator/"
- else:
- template_dir = ""
-
- # Check paths and create directories if needed
- directories = [
- "meraki",
- "meraki/api",
- "meraki/api/batch",
- "meraki/aio",
- "meraki/aio/api",
- "meraki/api/batch",
- ]
- for directory in directories:
- if not os.path.isdir(directory):
- os.mkdir(directory)
-
- # Files that are not generated
- non_generated = [
- "__init__.py",
- "_version.py",
- "config.py",
- "common.py",
- "exceptions.py",
- "response_handler.py",
- "rest_session.py",
- "api/__init__.py",
- "aio/__init__.py",
- "aio/rest_session.py",
- "aio/api/__init__.py",
- "api/batch/__init__.py",
- ]
- base_url = "https://raw.githubusercontent.com/meraki/dashboard-api-python/master/meraki/"
- for file in non_generated:
- response = requests.get(f"{base_url}{file}")
- with open(f"meraki/{file}", "w+", encoding="utf-8", newline=None) as fp:
- contents = response.text
- if file == "_version.py":
- # replace library version
- start = contents.find("__version__ = ")
- end = contents.find("\n", start)
- contents = f"{contents[:start]}__version__ = '{version_number}'{contents[end:]}"
- elif file == "__init__.py":
- # replace API version
- start = contents.find("__api_version__ = ")
- end = contents.find("\n", start)
- contents = f"{contents[:start]}__api_version__ = '{api_version_number}'{contents[end:]}"
- fp.write(contents)
-
- # Organize data from OpenAPI specification
- operations, scopes = common.organize_spec(paths, scopes)
-
- # Inform the user how many operations were found
- print(f"Total of {len(operations)} endpoints found from OpenAPI spec...")
-
- # Generate API libraries
- # We will use newline=None to ensure that line breaks are handled correctly, especially when generating
- # on Windows and using `git autocrlf true`
- jinja_env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True)
- jinja_env.filters["to_double_quote_list"] = lambda lst: json.dumps(lst)
-
- # Iterate through the scopes creating standard, asyncio and batch modules for each
- generate_modules(batchable_actions, jinja_env, scopes, template_dir)
-
- # Format generated code with ruff
- print("Formatting generated code with ruff...")
- subprocess.run(["ruff", "check", "--fix", "--quiet", "meraki/"], check=False)
- subprocess.run(["ruff", "format", "--quiet", "meraki/"], check=False)
-
-
-def generate_modules(batchable_actions, jinja_env, scopes, template_dir):
- for scope in scopes:
- print(f"...generating {scope}")
- section = scopes[scope]
-
- # Generate the standard module
- with open(f"meraki/api/{scope}.py", "w", encoding="utf-8", newline=None) as output:
- # Open module file for Asyncio API libraries
- async_output = open(f"meraki/aio/api/{scope}.py", "w", encoding="utf-8", newline=None)
- # Open module file for Action Batch API libraries
- batch_output = open(f"meraki/api/batch/{scope}.py", "w", encoding="utf-8", newline=None)
-
- modules = [
- {"template_name": "class_template.jinja2", "module_output": output},
- {
- "template_name": "async_class_template.jinja2",
- "module_output": async_output,
- },
- {
- "template_name": "batch_class_template.jinja2",
- "module_output": batch_output,
- },
- ]
-
- # Generate modules
- for module in modules:
- render_class_template(
- jinja_env,
- template_dir,
- module["template_name"],
- module["module_output"],
- scope,
- )
-
- # Generate API & Asyncio API functions
- generate_standard_and_async_functions(jinja_env, template_dir, section, output, async_output)
-
- # Generate API action batch functions
- generate_action_batch_functions(
- jinja_env,
- template_dir,
- section,
- batch_output,
- batchable_actions,
- )
-
-
-def generate_standard_and_async_functions(
- jinja_env: jinja2.Environment,
- template_dir: str,
- section: dict,
- output: open,
- async_output: open,
-):
- for path, methods in section.items():
- for method, endpoint in methods.items():
- # Get metadata
- tags = endpoint["tags"]
- operation = endpoint["operationId"]
- description = endpoint["summary"]
-
- # will need updating for OASv3
- parameters = endpoint["parameters"] if "parameters" in endpoint else None
-
- # Function definition
- definition = ""
- defined_params = set()
- if parameters:
- for p, values in parse_params(operation, parameters, "required").items():
- defined_params.add(p)
- if values["type"] == "array":
- definition += f", {p}: list"
- elif values["type"] == "number":
- definition += f", {p}: float"
- elif values["type"] == "integer":
- definition += f", {p}: int"
- elif values["type"] == "boolean":
- definition += f", {p}: bool"
- elif values["type"] == "object":
- definition += f", {p}: dict"
- elif values["type"] == "string":
- definition += f", {p}: str"
-
- # Path params must be in the signature for URL construction
- for p, values in parse_params(operation, parameters, "path").items():
- if p not in defined_params:
- defined_params.add(p)
- if values["type"] == "array":
- definition += f", {p}: list"
- elif values["type"] == "number":
- definition += f", {p}: float"
- elif values["type"] == "integer":
- definition += f", {p}: int"
- elif values["type"] == "boolean":
- definition += f", {p}: bool"
- elif values["type"] == "object":
- definition += f", {p}: dict"
- elif values["type"] == "string":
- definition += f", {p}: str"
-
- # Catch params referenced in the URL but not declared as path params
- for p in re.findall(r"\{(\w+)\}", path):
- if p not in defined_params:
- defined_params.add(p)
- definition += f", {p}: str"
-
- if "perPage" in parse_params(operation, parameters):
- if operation in REVERSE_PAGINATION:
- definition += ", total_pages=1, direction='prev'"
- else:
- definition += ", total_pages=1, direction='next'"
- if operation == "getNetworkEvents":
- definition += ", event_log_end_time=None"
-
- if parse_params(operation, parameters, ["optional"]):
- definition += ", **kwargs"
-
- # Docstring
- param_descriptions = list()
- all_params = parse_params(operation, parameters, ["required", "pagination", "optional"])
- if all_params:
- for p, values in all_params.items():
- param_descriptions.append(f"{p} ({values['type']}): {values['description']}")
-
- # Combine keyword args with locals
- kwarg_line = ""
- if parse_params(operation, parameters, ["optional"]):
- kwarg_line = "kwargs.update(locals())"
- elif parse_params(operation, parameters, ["query", "array", "body"]):
- kwarg_line = "kwargs = locals()"
-
- # Assert valid values for enum
- enum_params = parse_params(operation, parameters, ["enum"])
- assert_blocks = list()
- if enum_params:
- for p, values in enum_params.items():
- assert_blocks.append((p, values["enum"]))
-
- # Function body for GET endpoints
- query_params = array_params = body_params = path_params = {}
- if method == "get":
- array_params, call_line, path_params, query_params = parse_get_params(operation, parameters)
-
- # Function body for POST/PUT endpoints
- elif method == "post" or method == "put":
- body_params, call_line, path_params = parse_post_and_put_params(method, operation, parameters)
-
- # Function body for DELETE endpoints
- elif method == "delete":
- call_line, path_params, query_params = parse_delete_params(operation, parameters)
-
- # Ensure all URL-referenced params get quote lines in the template
- for p in re.findall(r"\{(\w+)\}", path):
- if p not in path_params:
- path_params[p] = {"type": "string", "in": "path"}
-
- # Add function to files
- with open(
- f"{template_dir}function_template.jinja2",
- encoding="utf-8",
- newline=None,
- ) as fp:
- function_template = fp.read()
- template = jinja_env.from_string(function_template)
- output.write(
- "\n\n"
- + template.render(
- operation=operation,
- function_definition=definition,
- description=description,
- doc_url=docs_url(operation),
- descriptions=param_descriptions,
- kwarg_line=kwarg_line,
- all_params=list(all_params.keys()),
- assert_blocks=assert_blocks,
- tags=tags,
- resource=path,
- query_params=query_params,
- array_params=array_params,
- body_params=body_params,
- path_params=path_params,
- call_line=call_line,
- )
- )
- async_output.write(
- "\n\n"
- + template.render(
- operation=operation,
- function_definition=definition,
- description=description,
- doc_url=docs_url(operation),
- descriptions=param_descriptions,
- kwarg_line=kwarg_line,
- all_params=list(all_params.keys()),
- assert_blocks=assert_blocks,
- tags=tags,
- resource=path,
- query_params=query_params,
- array_params=array_params,
- body_params=body_params,
- path_params=path_params,
- call_line=call_line,
- )
- )
-
-
-def parse_get_params(operation: str, parameters: dict):
- query_params = parse_params(operation, parameters, "query")
- array_params = parse_params(operation, parameters, "array")
- path_params = parse_params(operation, parameters, "path")
- pagination_params = parse_params(operation, parameters, "pagination")
- if query_params or array_params:
- if pagination_params:
- if operation == "getNetworkEvents":
- call_line = (
- "return self._session.get_pages(metadata, resource, params, total_pages, direction, event_log_end_time)"
- )
- else:
- call_line = "return self._session.get_pages(metadata, resource, params, total_pages, direction)"
- else:
- call_line = "return self._session.get(metadata, resource, params)"
- else:
- call_line = "return self._session.get(metadata, resource)"
- return array_params, call_line, path_params, query_params
-
-
-def parse_post_and_put_params(method: str, operation: str, parameters: dict):
- body_params = parse_params(operation, parameters, "body")
- path_params = parse_params(operation, parameters, "path")
- if body_params:
- call_line = f"return self._session.{method}(metadata, resource, payload)"
- else:
- call_line = f"return self._session.{method}(metadata, resource)"
- return body_params, call_line, path_params
-
-
-def parse_delete_params(operation: str, parameters: dict):
- query_params = parse_params(operation, parameters, "query")
- path_params = parse_params(operation, parameters, "path")
-
- if query_params:
- call_line = "return self._session.delete(metadata, resource, params)"
- else:
- call_line = "return self._session.delete(metadata, resource)"
- return call_line, path_params, query_params
-
-
-def generate_action_batch_functions(
- jinja_env: jinja2.Environment,
- template_dir: str,
- section: dict,
- batch_output: open,
- batchable_actions: list,
-):
- for path, methods in section.items():
- for method, endpoint in methods.items():
- batchable_action_summaries = [action["summary"] for action in batchable_actions]
- if endpoint["description"] in batchable_action_summaries:
- # Get metadata
- tags = endpoint["tags"]
- operation = endpoint["operationId"]
- description = endpoint["description"]
- summary = endpoint["summary"]
-
- this_action = [
- action for action in batchable_actions if action["summary"] == description or action["summary"] == summary
- ][0]
-
- batch_operation = this_action["operation"]
-
- # May need update for OASv3
- parameters = endpoint["parameters"] if "parameters" in endpoint else None
-
- # Function body for GET endpoints
- query_params = array_params = body_params = {}
- path_params = parse_params(operation, parameters, "path")
-
- # Ensure all URL-referenced params get quote lines in the template
- for p in re.findall(r"\{(\w+)\}", path):
- if p not in path_params:
- path_params[p] = {"type": "string", "in": "path"}
-
- # Function body for POST/PUT endpoints
- if method == "post" or method == "put":
- # will need update for OASv3
- body_params = parse_params(operation, parameters, "body")
-
- # Function body for DELETE endpoints is empty (HTTP 204)
-
- # Function definition
- definition = ""
- defined_params = set()
- if parameters:
- for p, values in parse_params(operation, parameters, "required").items():
- defined_params.add(p)
- # Match OAS schema types to Python types
- match values["type"]:
- case "array":
- definition += f", {p}: list"
- case "number":
- definition += f", {p}: float"
- case "integer":
- definition += f", {p}: int"
- case "boolean":
- definition += f", {p}: bool"
- case "object":
- definition += f", {p}: dict"
- case "string":
- definition += f", {p}: str"
-
- # Path params must be in the signature for URL construction
- for p, values in parse_params(operation, parameters, "path").items():
- if p not in defined_params:
- defined_params.add(p)
- match values["type"]:
- case "array":
- definition += f", {p}: list"
- case "number":
- definition += f", {p}: float"
- case "integer":
- definition += f", {p}: int"
- case "boolean":
- definition += f", {p}: bool"
- case "object":
- definition += f", {p}: dict"
- case "string":
- definition += f", {p}: str"
-
- # Catch params referenced in the URL but not declared as path params
- for p in re.findall(r"\{(\w+)\}", path):
- if p not in defined_params:
- defined_params.add(p)
- definition += f", {p}: str"
-
- if "perPage" in parse_params(operation, parameters):
- if operation in REVERSE_PAGINATION:
- definition += ", total_pages=1, direction='prev'"
- else:
- definition += ", total_pages=1, direction='next'"
- if operation == "getNetworkEvents":
- definition += ", event_log_end_time=None"
-
- if parse_params(operation, parameters, ["optional"]):
- definition += ", **kwargs"
-
- # Docstring
- param_descriptions = list()
- all_params = parse_params(operation, parameters, ["required", "pagination", "optional"])
- if all_params:
- for p, values in all_params.items():
- param_descriptions.append(f"{p} ({values['type']}): {values['description']}")
-
- # Combine keyword args with locals
- kwarg_line = ""
- if parse_params(operation, parameters, ["optional"]):
- kwarg_line = "kwargs.update(locals())"
-
- # will need update for OASv3
- elif parse_params(operation, parameters, ["query", "array", "body"]):
- kwarg_line = "kwargs = locals()"
-
- # Assert valid values for enum
- enum_params = parse_params(operation, parameters, ["enum"])
- assert_blocks = list()
- if enum_params:
- for p, values in enum_params.items():
- assert_blocks.append((p, values["enum"]))
-
- # Function return statement
- call_line = "return action"
-
- # Add function to files
- with open(
- f"{template_dir}batch_function_template.jinja2",
- encoding="utf-8",
- newline=None,
- ) as fp:
- function_template = fp.read()
- template = jinja_env.from_string(function_template)
- batch_output.write(
- "\n\n"
- + template.render(
- operation=operation,
- function_definition=definition,
- description=description,
- doc_url=docs_url(operation),
- descriptions=param_descriptions,
- kwarg_line=kwarg_line,
- all_params=list(all_params.keys()),
- assert_blocks=assert_blocks,
- tags=tags,
- resource=path,
- query_params=query_params,
- array_params=array_params,
- body_params=body_params,
- path_params=path_params,
- call_line=call_line,
- batch_operation=batch_operation,
- )
- )
-
-
-def render_class_template(
- jinja_env: jinja2.Environment,
- template_dir: str,
- template_name: str,
- output: open,
- scope: str,
-):
- with open(f"{template_dir}{template_name}", encoding="utf-8", newline=None) as fp:
- class_template = fp.read()
- template = jinja_env.from_string(class_template)
- output.write(
- template.render(
- class_name=scope[0].upper() + scope[1:],
- )
- )
-
-
-# Prints a READ_ME help message for user to read
-def print_help():
- lines = READ_ME.split("\n")
- for line in lines:
- print(f"# {line}")
-
-
-# Parse command line arguments
-def main(inputs):
- api_key = os.environ.get("MERAKI_DASHBOARD_API_KEY")
- org_id = None
- version_number = "custom"
- api_version_number = "custom"
- is_github_action = False
-
- try:
- opts, args = getopt.getopt(inputs, "ho:k:v:a:g:")
- except getopt.GetoptError:
- print_help()
- sys.exit(2)
- for opt, arg in opts:
- if opt == "-h":
- print_help()
- sys.exit(2)
- elif opt == "-o":
- org_id = arg
- elif opt == "-k" and api_key is None:
- api_key = arg
- elif opt == "-v":
- version_number = arg
- elif opt == "-a":
- api_version_number = arg
- elif opt == "-g":
- if arg.lower() == "true":
- is_github_action = True
-
- check_python_version()
-
- # Retrieve the latest OpenAPI specification
- if org_id:
- if not api_key:
- print_help()
- sys.exit(2)
- else:
- response = requests.get(
- f"https://api.meraki.com/api/v1/organizations/{org_id}/openapiSpec",
- headers={"Authorization": f"Bearer {api_key}"},
- )
- if response.ok:
- spec = response.json()
- else:
- print_help()
- sys.exit(f"API key provided does not have access to org {org_id}")
- else:
- response = requests.get("https://api.meraki.com/api/v1/openapiSpec")
- # Validate that the spec pulled successfully before trying to generate the library.
- if response.ok:
- spec = response.json()
- print("Successfully pulled Meraki dashboard API OpenAPI spec.")
- else:
- print_help()
- sys.exit(
- "There was an HTTP error pulling the OpenAPI specification. Please try again in a few minutes. "
- "If this continues for more than an hour, please contact Meraki support and mention that "
- '"HTTP GET https://api.meraki.com/api/v1/openapiSpec" is failing.'
- )
-
- generate_library(spec, version_number, api_version_number, is_github_action)
-
-
-if __name__ == "__main__":
- main(sys.argv[1:])
diff --git a/generator/generate_snippets.py b/generator/generate_snippets.py
index a5000fea..5cb2f80b 100644
--- a/generator/generate_snippets.py
+++ b/generator/generate_snippets.py
@@ -1,9 +1,10 @@
import os
import sys
-import requests
+import httpx
from jinja2 import Template
import common as common
+from parser_v3 import parse_params_v3, clear_cache
CALL_TEMPLATE = Template(
"""import meraki
@@ -39,108 +40,16 @@ def snakify(param):
return ret
-# Helper function to return pagination parameters depending on endpoint
-def generate_pagination_parameters(operation):
- ret = {
- "total_pages": {
- "type": "integer or string",
- "description": 'total number of pages to retrieve, -1 or "all" for all pages',
- },
- "direction": {
- "type": "string",
- "description": 'direction to paginate, either "next" or "prev" (default) page'
- if operation in REVERSE_PAGINATION
- else 'direction to paginate, either "next" (default) or "prev" page',
- },
- }
- return ret
-
-
-# Helper function to return parameters within OAS spec, optionally based on list of input filters
-def parse_params(operation, parameters, param_filters=[]):
- if parameters is None:
- return {}
-
- # Create dict with information on endpoint's parameters
- params = {}
- for p in parameters:
- name = p["name"]
- if "schema" in p:
- keys = p["schema"]["properties"]
- for k in keys:
- if "required" in p["schema"] and k in p["schema"]["required"]:
- params[k] = {"required": True}
- else:
- params[k] = {"required": False}
- params[k]["in"] = p["in"]
- params[k]["type"] = keys[k]["type"]
- params[k]["description"] = keys[k]["description"]
- if "enum" in keys[k]:
- params[k]["enum"] = keys[k]["enum"]
- if "example" in p["schema"] and k in p["schema"]["example"]:
- params[k]["example"] = p["schema"]["example"][k]
- elif "required" in p and p["required"]:
- params[name] = {"required": True}
- params[name]["in"] = p["in"]
- params[name]["type"] = p["type"]
- if "description" in p:
- params[name]["description"] = p["description"]
- else:
- params[name]["description"] = "(required)"
- if "enum" in p:
- params[name]["enum"] = p["enum"]
- else:
- params[name] = {"required": False}
- params[name]["in"] = p["in"]
- params[name]["type"] = p["type"]
- params[name]["description"] = p["description"]
- if "enum" in p:
- params[name]["enum"] = p["enum"]
-
- # Add custom library parameters to handle pagination
- if "perPage" in params:
- params.update(generate_pagination_parameters(operation))
-
- # Return parameters based on matching input filters
- if not param_filters:
- return params
- else:
- ret = {}
- if "required" in param_filters:
- ret.update(
- {k: v for k, v in params.items() if "required" in v and v["required"]}
- )
- if "pagination" in param_filters:
- ret.update(
- generate_pagination_parameters(operation) if "perPage" in params else {}
- )
- if "optional" in param_filters:
- ret.update(
- {
- k: v
- for k, v in params.items()
- if "required" in v and not v["required"]
- }
- )
- if "path" in param_filters:
- ret.update(
- {k: v for k, v in params.items() if "in" in v and v["in"] == "path"}
- )
- if "query" in param_filters:
- ret.update(
- {k: v for k, v in params.items() if "in" in v and v["in"] == "query"}
- )
- if "body" in param_filters:
- ret.update(
- {k: v for k, v in params.items() if "in" in v and v["in"] == "body"}
- )
- if "array" in param_filters:
- ret.update(
- {k: v for k, v in params.items() if "in" in v and v["type"] == "array"}
- )
- if "enum" in param_filters:
- ret.update({k: v for k, v in params.items() if "enum" in v})
- return ret
+# Helper function to return parameters within the OASv3 spec, optionally based on
+# a list of input filters. Delegates parsing/$ref-resolution/requestBody handling to
+# parser_v3.parse_params_v3 (the same parser used by the library/stub generators) so
+# snippets stay consistent with generated code. parse_params_v3 applies the filters via
+# common.return_params and injects pagination params when perPage is present.
+def parse_params(endpoint, path_item, spec, param_filters=None):
+ if param_filters is None:
+ param_filters = []
+ params, _metadata = parse_params_v3(endpoint, path_item, spec, param_filters)
+ return params
# Generate text for parameter assignments
@@ -175,8 +84,13 @@ def process_assignments(parameters):
def main():
- # Get latest OpenAPI specification
- spec = requests.get("https://api.meraki.com/api/v1/openapiSpec").json()
+ # Get the latest OpenAPI v3 specification (version=3 selects OASv3 over the legacy v2 shape)
+ spec = httpx.get(
+ "https://api.meraki.com/api/v1/openapiSpec", params={"version": 3}
+ ).json()
+
+ # Reset parser_v3's $ref cache at entry, matching the library generator
+ clear_cache()
# Supported scopes list will include organizations, networks, devices, and all product types.
supported_scopes = [
@@ -206,8 +120,17 @@ def main():
# Scopes used when generating the library will depend on the provided version of the API spec.
scopes = {tag["name"]: {} for tag in tags if tag["name"] in supported_scopes}
+ # Filter paths to remove the path-level "parameters" key before organize_spec, which
+ # expects only HTTP method keys. The original path_item (incl. path-level params) is
+ # passed to parse_params_v3 separately via spec["paths"][path].
+ filtered_paths = {}
+ for path, path_item in paths.items():
+ filtered_paths[path] = {
+ k: v for k, v in path_item.items() if k in ["get", "post", "put", "delete", "patch"]
+ }
+
# Organize data from OpenAPI specification
- operations, scopes = common.organize_spec(paths, scopes)
+ operations, scopes = common.organize_spec(filtered_paths, scopes)
# Generate API libraries
for scope in scopes:
@@ -219,25 +142,25 @@ def main():
# Get metadata
tags = endpoint["tags"]
operation = endpoint["operationId"]
- description = endpoint["summary"]
- parameters = (
- endpoint["parameters"] if "parameters" in endpoint else None
- )
- responses = endpoint[
- "responses"
- ] # not actually used here for library generation
+ description = endpoint.get("summary", endpoint.get("description", ""))
+
+ # Full path_item (incl. path-level parameters) for parse_params_v3
+ path_item = spec["paths"][path]
+
+ # An endpoint contributes params if it declares parameters or a requestBody
+ has_params = "parameters" in endpoint or "requestBody" in endpoint
required = {}
optional = {}
- if parameters:
- if "perPage" in parse_params(operation, parameters):
+ if has_params:
+ if "perPage" in parse_params(endpoint, path_item, spec):
pagination = True
else:
pagination = False
for p, values in parse_params(
- operation, parameters, "required"
+ endpoint, path_item, spec, ["required"]
).items():
if "example" in values:
required[p] = values["example"]
@@ -261,7 +184,7 @@ def main():
elif values["type"] == "string":
required[p] = "str"
else:
- sys.exit(p, values)
+ sys.exit(f"Unhandled param type for {p}: {values}")
if pagination:
if operation not in REVERSE_PAGINATION:
@@ -270,7 +193,7 @@ def main():
optional["total_pages"] = 3
for p, values in parse_params(
- operation, parameters, "optional"
+ endpoint, path_item, spec, ["optional"]
).items():
if "example" in values:
optional[p] = values["example"]
diff --git a/generator/generate_stubs.py b/generator/generate_stubs.py
index 50aca231..923ddddb 100644
--- a/generator/generate_stubs.py
+++ b/generator/generate_stubs.py
@@ -5,10 +5,11 @@
"""
import keyword
+import os
import re
import jinja2
from parser_v3 import parse_params_v3
-from generate_library_oasv2 import return_params, REVERSE_PAGINATION
+from common import return_params, REVERSE_PAGINATION
def _safe_param_name(name: str) -> str:
@@ -71,7 +72,8 @@ def generate_stub_modules(spec: dict, scopes: dict, jinja_env: jinja2.Environmen
for scope in scopes:
section = scopes[scope]
- stub_path = f"meraki/api/{scope}.pyi"
+ repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ stub_path = os.path.join(repo_root, "meraki", "api", f"{scope}.pyi")
with open(stub_path, "w", encoding="utf-8", newline=None) as stub_output:
# Render class header
with open(f"{template_dir}stub_template.jinja2", encoding="utf-8", newline=None) as fp:
diff --git a/generator/parser_v3.py b/generator/parser_v3.py
index dc05ef41..7bb7bbd5 100644
--- a/generator/parser_v3.py
+++ b/generator/parser_v3.py
@@ -8,7 +8,7 @@
Spec passed as argument to all functions.
"""
-from generate_library_oasv2 import generate_pagination_parameters, return_params
+from common import generate_pagination_parameters, return_params
# Module-level cache for resolved $ref pointers (D-01)
_ref_cache: dict[str, dict] = {}
diff --git a/meraki/__init__.py b/meraki/__init__.py
index 83fc9508..f97c9c37 100644
--- a/meraki/__init__.py
+++ b/meraki/__init__.py
@@ -24,6 +24,8 @@
# Config import
from meraki.config import (
API_KEY_ENVIRONMENT_VARIABLE,
+ MERAKI_APP_ID,
+ MERAKI_APP_BEARER_TOKEN,
DEFAULT_BASE_URL,
SINGLE_REQUEST_TIMEOUT,
CERTIFICATE_PATH,
@@ -46,13 +48,20 @@
MERAKI_PYTHON_SDK_CALLER,
USE_ITERATOR_FOR_GET_PAGES,
VALIDATE_KWARGS,
+ SMART_FLOW_ENABLED,
+ SMART_FLOW_ORG_RATE,
+ SMART_FLOW_GLOBAL_RATE,
+ SMART_FLOW_CACHE_MODE,
+ SMART_FLOW_CACHE_PATH,
+ SMART_FLOW_CACHE_TTL,
+ SMART_FLOW_LOGGING,
)
-from meraki.rest_session import RestSession
+from meraki.session.sync import RestSession
from meraki.exceptions import APIError, APIKeyError, APIResponseError, AsyncAPIError
from meraki._version import __version__ # noqa: F401
from datetime import datetime
-__api_version__ = "1.72.0"
+__api_version__ = "1.72.0-beta.1"
__all__ = [
"APIError",
@@ -68,6 +77,8 @@ class DashboardAPI(object):
**Creates a persistent Meraki dashboard API session**
- api_key (string): API key generated in dashboard; can also be set as an environment variable MERAKI_DASHBOARD_API_KEY
+ - meraki_app_id (string): optional Meraki app ID; can also be set as an environment variable MERAKI_APP_ID
+ - meraki_app_bearer_token (string): optional Meraki app bearer token; can also be set as an environment variable MERAKI_APP_BEARER_TOKEN
- base_url (string): preceding all endpoint resources
- single_request_timeout (integer): maximum number of seconds for each API call
- certificate_path (string): path for TLS/SSL certificate verification if behind local proxy
@@ -90,11 +101,18 @@ class DashboardAPI(object):
- caller (string): optional identifier for API usage tracking; can also be set as an environment variable MERAKI_PYTHON_SDK_CALLER
- use_iterator_for_get_pages (boolean): list* methods will return an iterator with each object instead of a complete list with all items
- validate_kwargs (boolean): log warnings when unrecognized kwargs are passed to API methods
+ - smart_flow_enabled (boolean): enable per-org proactive smart flow via token buckets?
+ - smart_flow_org_rate (float): max requests per second per org (Meraki default: 10)
+ - smart_flow_global_rate (float): max requests per second across all orgs (source IP limit, Meraki default: 100)
+ - smart_flow_cache_mode (string): "lazy" (default) or "eager" - how org/network/device mappings are loaded
+ - smart_flow_cache_path (string): path to persist smart flow mapping cache across sessions
"""
def __init__(
self,
api_key=None,
+ meraki_app_id=MERAKI_APP_ID,
+ meraki_app_bearer_token=MERAKI_APP_BEARER_TOKEN,
base_url=DEFAULT_BASE_URL,
single_request_timeout=SINGLE_REQUEST_TIMEOUT,
certificate_path=CERTIFICATE_PATH,
@@ -117,21 +135,29 @@ def __init__(
use_iterator_for_get_pages=USE_ITERATOR_FOR_GET_PAGES,
inherit_logging_config=INHERIT_LOGGING_CONFIG,
validate_kwargs=VALIDATE_KWARGS,
+ smart_flow_enabled=SMART_FLOW_ENABLED,
+ smart_flow_org_rate=SMART_FLOW_ORG_RATE,
+ smart_flow_global_rate=SMART_FLOW_GLOBAL_RATE,
+ smart_flow_cache_mode=SMART_FLOW_CACHE_MODE,
+ smart_flow_cache_path=SMART_FLOW_CACHE_PATH,
+ smart_flow_cache_ttl=SMART_FLOW_CACHE_TTL,
+ smart_flow_logging=SMART_FLOW_LOGGING,
):
# Check API key
api_key = api_key or os.environ.get(API_KEY_ENVIRONMENT_VARIABLE)
if not api_key:
raise APIKeyError()
+ # Pull the Meraki app ID and bearer token from environment variables if present
+ meraki_app_id = meraki_app_id or os.environ.get("MERAKI_APP_ID")
+ meraki_app_bearer_token = meraki_app_bearer_token or os.environ.get("MERAKI_APP_BEARER_TOKEN")
+
# Pull the BE GEO ID from an environment variable if present
be_geo_id = be_geo_id or os.environ.get("BE_GEO_ID")
# Pull the caller from an environment variable if present
caller = caller or os.environ.get("MERAKI_PYTHON_SDK_CALLER")
- use_iterator_for_get_pages = use_iterator_for_get_pages
- inherit_logging_config = inherit_logging_config
-
# Configure logging
if not suppress_logging:
self._logger = logging.getLogger(__name__)
@@ -167,6 +193,8 @@ def __init__(
self._session = RestSession(
logger=self._logger,
api_key=api_key,
+ meraki_app_id=meraki_app_id,
+ meraki_app_bearer_token=meraki_app_bearer_token,
base_url=base_url,
single_request_timeout=single_request_timeout,
certificate_path=certificate_path,
@@ -183,6 +211,13 @@ def __init__(
caller=caller,
use_iterator_for_get_pages=use_iterator_for_get_pages,
validate_kwargs=validate_kwargs,
+ smart_flow_enabled=smart_flow_enabled,
+ smart_flow_org_rate=smart_flow_org_rate,
+ smart_flow_global_rate=smart_flow_global_rate,
+ smart_flow_cache_mode=smart_flow_cache_mode,
+ smart_flow_cache_path=smart_flow_cache_path,
+ smart_flow_cache_ttl=smart_flow_cache_ttl,
+ smart_flow_logging=smart_flow_logging,
)
# API endpoints by section
@@ -205,3 +240,41 @@ def __init__(
# Batch definitions
self.batch = Batch()
+
+ # Eager load smart limit cache if enabled (skip if disk cache was fresh)
+ if smart_flow_enabled and smart_flow_cache_mode == "eager":
+ limiter = self._session._smart_flow
+ if limiter and not limiter.cache_fresh:
+ self._eager_load_rate_limit_cache()
+
+ def _eager_load_rate_limit_cache(self) -> None:
+ """Populate the smart flow's org/network/device cache at startup."""
+ rate_limiter = self._session._smart_flow
+ if not rate_limiter:
+ return
+
+ try:
+ orgs = self.organizations.getOrganizations()
+ except Exception:
+ return
+
+ for org in orgs:
+ org_id = org["id"]
+ rate_limiter.register_org(org_id)
+
+ try:
+ networks = self.organizations.getOrganizationNetworks(org_id, total_pages="all", perPage=1000)
+ for net in networks:
+ rate_limiter.register_network(net["id"], org_id)
+ except Exception:
+ pass
+
+ try:
+ devices = self.organizations.getOrganizationInventoryDevices(org_id, total_pages="all", perPage=1000)
+ for device in devices:
+ if device.get("serial"):
+ rate_limiter.register_device(device["serial"], org_id)
+ except Exception:
+ pass
+
+ rate_limiter.save_cache()
diff --git a/meraki/_version.py b/meraki/_version.py
index 88c513ea..ad6c0d7d 100644
--- a/meraki/_version.py
+++ b/meraki/_version.py
@@ -1 +1 @@
-__version__ = "3.3.0"
+__version__ = "4.3.0b1"
diff --git a/meraki/aio/__init__.py b/meraki/aio/__init__.py
index 6e8ed150..17b61d2a 100644
--- a/meraki/aio/__init__.py
+++ b/meraki/aio/__init__.py
@@ -17,7 +17,7 @@
from meraki.aio.api.switch import AsyncSwitch
from meraki.aio.api.wireless import AsyncWireless
from meraki.aio.api.wirelessController import AsyncWirelessController
-from meraki.aio.rest_session import AsyncRestSession
+from meraki.session.async_ import AsyncRestSession
from meraki.exceptions import APIKeyError
from datetime import datetime
@@ -27,6 +27,8 @@
# Config import
from meraki.config import (
API_KEY_ENVIRONMENT_VARIABLE,
+ MERAKI_APP_ID,
+ MERAKI_APP_BEARER_TOKEN,
DEFAULT_BASE_URL,
SINGLE_REQUEST_TIMEOUT,
CERTIFICATE_PATH,
@@ -50,6 +52,13 @@
USE_ITERATOR_FOR_GET_PAGES,
AIO_MAXIMUM_CONCURRENT_REQUESTS,
VALIDATE_KWARGS,
+ SMART_FLOW_ENABLED,
+ SMART_FLOW_ORG_RATE,
+ SMART_FLOW_GLOBAL_RATE,
+ SMART_FLOW_CACHE_MODE,
+ SMART_FLOW_CACHE_PATH,
+ SMART_FLOW_CACHE_TTL,
+ SMART_FLOW_LOGGING,
)
@@ -58,6 +67,8 @@ class AsyncDashboardAPI:
**Creates a persistent Meraki dashboard API session**
- api_key (string): API key generated in dashboard; can also be set as an environment variable MERAKI_DASHBOARD_API_KEY
+ - meraki_app_id (string): optional Meraki app ID; can also be set as an environment variable MERAKI_APP_ID
+ - meraki_app_bearer_token (string): optional Meraki app bearer token; can also be set as an environment variable MERAKI_APP_BEARER_TOKEN
- base_url (string): preceding all endpoint resources
- single_request_timeout (integer): maximum number of seconds for each API call
- certificate_path (string): path for TLS/SSL certificate verification if behind local proxy
@@ -81,11 +92,18 @@ class AsyncDashboardAPI:
- caller (string): optional identifier for API usage tracking; can also be set as an environment variable MERAKI_PYTHON_SDK_CALLER
- use_iterator_for_get_pages (boolean): list* methods will return an iterator with each object instead of a complete list with all items
- validate_kwargs (boolean): log warnings when unrecognized kwargs are passed to API methods
+ - smart_flow_enabled (boolean): enable per-org proactive smart flow via token buckets?
+ - smart_flow_org_rate (float): max requests per second per org (Meraki default: 10)
+ - smart_flow_global_rate (float): max requests per second across all orgs (source IP limit, Meraki default: 100)
+ - smart_flow_cache_mode (string): "lazy" (default) or "eager" - how org/network/device mappings are loaded
+ - smart_flow_cache_path (string): path to persist smart flow mapping cache across sessions
"""
def __init__(
self,
api_key=None,
+ meraki_app_id=MERAKI_APP_ID,
+ meraki_app_bearer_token=MERAKI_APP_BEARER_TOKEN,
base_url=DEFAULT_BASE_URL,
single_request_timeout=SINGLE_REQUEST_TIMEOUT,
certificate_path=CERTIFICATE_PATH,
@@ -109,21 +127,29 @@ def __init__(
inherit_logging_config=INHERIT_LOGGING_CONFIG,
maximum_concurrent_requests=AIO_MAXIMUM_CONCURRENT_REQUESTS,
validate_kwargs=VALIDATE_KWARGS,
+ smart_flow_enabled=SMART_FLOW_ENABLED,
+ smart_flow_org_rate=SMART_FLOW_ORG_RATE,
+ smart_flow_global_rate=SMART_FLOW_GLOBAL_RATE,
+ smart_flow_cache_mode=SMART_FLOW_CACHE_MODE,
+ smart_flow_cache_path=SMART_FLOW_CACHE_PATH,
+ smart_flow_cache_ttl=SMART_FLOW_CACHE_TTL,
+ smart_flow_logging=SMART_FLOW_LOGGING,
):
# Check API key
api_key = api_key or os.environ.get(API_KEY_ENVIRONMENT_VARIABLE)
if not api_key:
raise APIKeyError()
+ # Pull the Meraki app ID and bearer token from environment variables if present
+ meraki_app_id = meraki_app_id or os.environ.get("MERAKI_APP_ID")
+ meraki_app_bearer_token = meraki_app_bearer_token or os.environ.get("MERAKI_APP_BEARER_TOKEN")
+
# Pull the BE GEO ID from an environment variable if present
be_geo_id = be_geo_id or os.environ.get("BE_GEO_ID")
# Pull the caller from an environment variable if present
caller = caller or os.environ.get("MERAKI_PYTHON_SDK_CALLER")
- use_iterator_for_get_pages = use_iterator_for_get_pages
- inherit_logging_config = inherit_logging_config
-
# Configure logging
if not suppress_logging:
self._logger = logging.getLogger(__name__)
@@ -159,6 +185,8 @@ def __init__(
self._session = AsyncRestSession(
logger=self._logger,
api_key=api_key,
+ meraki_app_id=meraki_app_id,
+ meraki_app_bearer_token=meraki_app_bearer_token,
base_url=base_url,
single_request_timeout=single_request_timeout,
certificate_path=certificate_path,
@@ -176,8 +204,19 @@ def __init__(
use_iterator_for_get_pages=use_iterator_for_get_pages,
maximum_concurrent_requests=maximum_concurrent_requests,
validate_kwargs=validate_kwargs,
+ smart_flow_enabled=smart_flow_enabled,
+ smart_flow_org_rate=smart_flow_org_rate,
+ smart_flow_global_rate=smart_flow_global_rate,
+ smart_flow_cache_mode=smart_flow_cache_mode,
+ smart_flow_cache_path=smart_flow_cache_path,
+ smart_flow_cache_ttl=smart_flow_cache_ttl,
+ smart_flow_logging=smart_flow_logging,
)
+ # Store for eager load access
+ self._smart_flow_enabled = smart_flow_enabled
+ self._smart_flow_cache_mode = smart_flow_cache_mode
+
# API endpoints by section
self.administered = AsyncAdministered(self._session)
self.organizations = AsyncOrganizations(self._session)
@@ -200,7 +239,50 @@ def __init__(
self.batch = Batch()
async def __aenter__(self):
+ if self._smart_flow_enabled and self._smart_flow_cache_mode == "eager":
+ limiter = self._session._smart_flow
+ if limiter and not limiter.cache_fresh:
+ await self._eager_load_rate_limit_cache()
return self
async def __aexit__(self, exc_type, exc, tb):
+ # Drain/cancel in-flight background resolve/hydrate + flush tasks and
+ # persist the cache BEFORE closing the httpx client. Closing first would
+ # cause those background tasks to fail with "client has been closed".
+ # shutdown() performs the final save itself, so it is called instead of
+ # save_cache() to keep the persist exactly once.
+ if self._session._smart_flow:
+ await self._session._smart_flow.shutdown()
await self._session.close()
+
+ async def _eager_load_rate_limit_cache(self) -> None:
+ """Populate the smart flow's org/network/device cache at startup."""
+ rate_limiter = self._session._smart_flow
+ if not rate_limiter:
+ return
+
+ try:
+ orgs = await self.organizations.getOrganizations()
+ except Exception:
+ return
+
+ for org in orgs:
+ org_id = org["id"]
+ rate_limiter.register_org(org_id)
+
+ try:
+ networks = await self.organizations.getOrganizationNetworks(org_id, total_pages="all", perPage=1000)
+ for net in networks:
+ rate_limiter.register_network(net["id"], org_id)
+ except Exception:
+ pass
+
+ try:
+ devices = await self.organizations.getOrganizationInventoryDevices(org_id, total_pages="all", perPage=1000)
+ for device in devices:
+ if device.get("serial"):
+ rate_limiter.register_device(device["serial"], org_id)
+ except Exception:
+ pass
+
+ await rate_limiter.save_cache()
diff --git a/meraki/aio/api/administered.py b/meraki/aio/api/administered.py
index 86a44296..05b1663a 100644
--- a/meraki/aio/api/administered.py
+++ b/meraki/aio/api/administered.py
@@ -67,3 +67,36 @@ def revokeAdministeredIdentitiesMeApiKeys(self, suffix: str):
resource = f"/administered/identities/me/api/keys/{suffix}/revoke"
return self._session.post(metadata, resource)
+
+ def getAdministeredSearchLive(self, query: str, organizationId: str, networkId: str, **kwargs):
+ """
+ **List the appropriate results for a given global search utilizing live_search_react**
+ https://developer.cisco.com/meraki/api-v1/#!get-administered-search-live
+
+ - query (string): Search keywords
+ - organizationId (string): Id of Organization you want to search with
+ - networkId (string): Id of NodeGroup you want to seach with
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["administered", "configure", "search", "live"],
+ "operation": "getAdministeredSearchLive",
+ }
+ resource = "/administered/search/live"
+
+ query_params = [
+ "query",
+ "organizationId",
+ "networkId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getAdministeredSearchLive: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
diff --git a/meraki/aio/api/appliance.py b/meraki/aio/api/appliance.py
index 09c98051..d3dcfdb7 100644
--- a/meraki/aio/api/appliance.py
+++ b/meraki/aio/api/appliance.py
@@ -34,10 +34,21 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
- personality (object): Describes the port's configurability
- uplink (object): The port's settings when in WAN mode
- downlink (object): The port's VLAN settings when in LAN mode
+ - speed (string): Link speed for the port, in Mbps
+ - duplex (string): Duplex configuration for the port
"""
kwargs.update(locals())
+ if "speed" in kwargs and kwargs["speed"] is not None:
+ options = ["10", "100", "1000", "10000", "2500", "25000", "5000", "auto"]
+ assert kwargs["speed"] in options, f'''"speed" cannot be "{kwargs["speed"]}", & must be set to one of: {options}'''
+ if "duplex" in kwargs and kwargs["duplex"] is not None:
+ options = ["auto", "full", "half"]
+ assert kwargs["duplex"] in options, (
+ f'''"duplex" cannot be "{kwargs["duplex"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
"tags": ["appliance", "configure", "interfaces", "ports", "update"],
"operation": "createDeviceApplianceInterfacesPortsUpdate",
@@ -51,6 +62,8 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
"personality",
"uplink",
"downlink",
+ "speed",
+ "duplex",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -64,6 +77,58 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
return self._session.post(metadata, resource, payload)
+ def updateDeviceApplianceInterfacesPort(self, serial: str, number: str, **kwargs):
+ """
+ **Update configurations for an appliance's specified port**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-appliance-interfaces-port
+
+ - serial (string): Serial
+ - number (string): Number
+ - enabled (boolean): Indicates whether the port is enabled
+ - personality (object): Describes the port's configurability
+ - uplink (object): The port's settings when in WAN mode
+ - downlink (object): The port's VLAN settings when in LAN mode
+ - speed (string): Link speed for the port, in Mbps
+ - duplex (string): Duplex configuration for the port
+ """
+
+ kwargs.update(locals())
+
+ if "speed" in kwargs and kwargs["speed"] is not None:
+ options = ["10", "100", "1000", "10000", "2500", "25000", "5000", "auto"]
+ assert kwargs["speed"] in options, f'''"speed" cannot be "{kwargs["speed"]}", & must be set to one of: {options}'''
+ if "duplex" in kwargs and kwargs["duplex"] is not None:
+ options = ["auto", "full", "half"]
+ assert kwargs["duplex"] in options, (
+ f'''"duplex" cannot be "{kwargs["duplex"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["appliance", "configure", "interfaces", "ports"],
+ "operation": "updateDeviceApplianceInterfacesPort",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/devices/{serial}/appliance/interfaces/ports/{number}"
+
+ body_params = [
+ "enabled",
+ "personality",
+ "uplink",
+ "downlink",
+ "speed",
+ "duplex",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceApplianceInterfacesPort: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getDeviceAppliancePerformance(self, serial: str, **kwargs):
"""
**Return the performance score for a single Secure Appliance or Secure Router**
@@ -1087,6 +1152,7 @@ def createNetworkApplianceInterfacesL3(self, networkId: str, ipv4: dict, **kwarg
- networkId (string): Network ID
- ipv4 (object): IPv4 configuration
- port (object): Port configuration
+ - vrf (object): VRF assignment for the L3 interface
"""
kwargs.update(locals())
@@ -1101,6 +1167,7 @@ def createNetworkApplianceInterfacesL3(self, networkId: str, ipv4: dict, **kwarg
body_params = [
"port",
"ipv4",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1121,6 +1188,7 @@ def updateNetworkApplianceInterfacesL3(self, networkId: str, interfaceId: str, *
- interfaceId (string): Interface ID
- port (object): Port configuration
- ipv4 (object): IPv4 configuration
+ - vrf (object): VRF assignment for the L3 interface
"""
kwargs.update(locals())
@@ -1136,6 +1204,7 @@ def updateNetworkApplianceInterfacesL3(self, networkId: str, interfaceId: str, *
body_params = [
"port",
"ipv4",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1215,6 +1284,8 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs):
- vlan (integer): Native VLAN when the port is in Trunk mode. Access VLAN when the port is in Access mode.
- allowedVlans (string): Comma-delimited list of VLAN IDs (e.g. '2,15') for all devices. Secure Routers also support VLAN ranges (e.g. '2-10,15'). Use 'all' to permit all VLANs on the port.
- accessPolicy (string): The name of the policy. Only applicable to Access ports. Valid values are: 'open', '8021x-radius', 'mac-radius', 'hybris-radius' for MX64 or Z3 or any MX supporting the per port authentication feature. Otherwise, 'open' is the only valid value and 'open' is the default value if the field is missing.
+ - peerSgtCapable (boolean): If true, Peer SGT is enabled for traffic through this port. Applicable to trunk port only, not access port.
+ - adaptivePolicyGroupId (string): Adaptive policy group ID that all traffic originating from this port is assigned to.
- sgt (object): Security Group Tag settings for the port.
"""
@@ -1235,6 +1306,8 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs):
"vlan",
"allowedVlans",
"accessPolicy",
+ "peerSgtCapable",
+ "adaptivePolicyGroupId",
"sgt",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1618,6 +1691,7 @@ def updateNetworkApplianceSecurityIntrusion(self, networkId: str, **kwargs):
- networkId (string): Network ID
- mode (string): Set mode to 'disabled'/'detection'/'prevention' (optional - omitting will leave current config unchanged)
- idsRulesets (string): Set the detection ruleset 'connectivity'/'balanced'/'security' (optional - omitting will leave current config unchanged). Default value is 'balanced' if none currently saved
+ - policy (object): Set a custom intrusion policy by id (optional - omitting will leave current config unchanged)
- protectedNetworks (object): Set the included/excluded networks from the intrusion engine (optional - omitting will leave current config unchanged). This is available only in 'passthrough' mode
"""
@@ -1642,6 +1716,7 @@ def updateNetworkApplianceSecurityIntrusion(self, networkId: str, **kwargs):
body_params = [
"mode",
"idsRulesets",
+ "policy",
"protectedNetworks",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1804,6 +1879,7 @@ def updateNetworkApplianceSingleLan(self, networkId: str, **kwargs):
- applianceIp (string): The appliance IP address of the single LAN
- ipv6 (object): IPv6 configuration on the VLAN
- mandatoryDhcp (object): Mandatory DHCP will enforce that clients connecting to this LAN must use the IP address assigned by the DHCP server. Clients who use a static IP address won't be able to associate. Only available on firmware versions 17.0 and above
+ - vrf (object): VRF configuration on the Single LAN. Omit this field to preserve the current VRF.
"""
kwargs.update(locals())
@@ -1820,6 +1896,7 @@ def updateNetworkApplianceSingleLan(self, networkId: str, **kwargs):
"applianceIp",
"ipv6",
"mandatoryDhcp",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1963,6 +2040,7 @@ def createNetworkApplianceStaticRoute(self, networkId: str, name: str, subnet: s
- subnet (string): Subnet of the route
- gatewayIp (string): Gateway IP address (next hop)
- gatewayVlanId (integer): Gateway VLAN ID
+ - vrf (object): VRF settings for the static route.
"""
kwargs.update(locals())
@@ -1979,6 +2057,7 @@ def createNetworkApplianceStaticRoute(self, networkId: str, name: str, subnet: s
"subnet",
"gatewayIp",
"gatewayVlanId",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2023,6 +2102,7 @@ def updateNetworkApplianceStaticRoute(self, networkId: str, staticRouteId: str,
- enabled (boolean): Whether the route should be enabled or not
- fixedIpAssignments (object): Fixed DHCP IP assignments on the route
- reservedIpRanges (array): DHCP reserved IP ranges
+ - vrf (object): VRF settings for the static route.
"""
kwargs.update(locals())
@@ -2043,6 +2123,7 @@ def updateNetworkApplianceStaticRoute(self, networkId: str, staticRouteId: str,
"enabled",
"fixedIpAssignments",
"reservedIpRanges",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2431,6 +2512,7 @@ def updateNetworkApplianceTrafficShapingVpnExclusions(self, networkId: str, **kw
- networkId (string): Network ID
- custom (array): Custom VPN exclusion rules. Pass an empty array to clear existing rules.
- majorApplications (array): Major Application based VPN exclusion rules. Pass an empty array to clear existing rules.
+ - applications (array): NBAR Application based VPN exclusion rules. Available for networks on >=19.2 firmware
"""
kwargs.update(locals())
@@ -2445,6 +2527,7 @@ def updateNetworkApplianceTrafficShapingVpnExclusions(self, networkId: str, **kw
body_params = [
"custom",
"majorApplications",
+ "applications",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2508,6 +2591,23 @@ def disconnectNetworkApplianceUmbrellaAccount(self, networkId: str):
return self._session.post(metadata, resource)
+ def disableNetworkApplianceUmbrellaProtection(self, networkId: str):
+ """
+ **Disable umbrella protection for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!disable-network-appliance-umbrella-protection
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella"],
+ "operation": "disableNetworkApplianceUmbrellaProtection",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/disableProtection"
+
+ return self._session.delete(metadata, resource)
+
def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs):
"""
**Specify one or more domain names to be excluded from being routed to Cisco Umbrella.**
@@ -2541,6 +2641,54 @@ def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: lis
return self._session.put(metadata, resource, payload)
+ def enableNetworkApplianceUmbrellaProtection(self, networkId: str):
+ """
+ **Enable umbrella protection for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!enable-network-appliance-umbrella-protection
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella"],
+ "operation": "enableNetworkApplianceUmbrellaProtection",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/enableProtection"
+
+ return self._session.post(metadata, resource)
+
+ def policiesNetworkApplianceUmbrella(self, networkId: str, policyIds: list, **kwargs):
+ """
+ **Update umbrella policies applied to MX network.**
+ https://developer.cisco.com/meraki/api-v1/#!policies-network-appliance-umbrella
+
+ - networkId (string): Network ID
+ - policyIds (array): Array of umbrella policy IDs
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella"],
+ "operation": "policiesNetworkApplianceUmbrella",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/policies"
+
+ body_params = [
+ "policyIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"policiesNetworkApplianceUmbrella: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs):
"""
**Add one Cisco Umbrella DNS security policy to an MX network by policy ID**
@@ -2746,6 +2894,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
- dhcpBootNextServer (string): DHCP boot option to direct boot clients to the server to load the boot file from
- dhcpBootFilename (string): DHCP boot option for boot filename
- dhcpOptions (array): The list of DHCP options that will be included in DHCP responses. Each object in the list should have "code", "type", and "value" properties.
+ - adaptivePolicyGroupId (string): Adaptive policy group ID this VLAN is assigned to.
- sgt (object): Security Group Tag settings for the VLAN.
- vrf (object): VRF configuration on the VLAN.
- uplinks (array): Per-uplink NAT exception override configuration on the VLAN. Applicable only for networks that support NAT exceptions.
@@ -2794,6 +2943,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
"dhcpBootNextServer",
"dhcpBootFilename",
"dhcpOptions",
+ "adaptivePolicyGroupId",
"sgt",
"vrf",
"uplinks",
@@ -2902,6 +3052,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
- mask (integer): Mask used for the subnet of all bound to the template networks. Applicable only for template network.
- ipv6 (object): IPv6 configuration on the VLAN
- mandatoryDhcp (object): Mandatory DHCP will enforce that clients connecting to this VLAN must use the IP address assigned by the DHCP server. Clients who use a static IP address won't be able to associate. Only available on firmware versions 17.0 and above
+ - adaptivePolicyGroupId (string): Adaptive policy group ID that all traffic originating from this VLAN is assigned to.
- sgt (object): Security Group Tag settings for the VLAN.
- vrf (object): VRF configuration on the VLAN.
- uplinks (array): Per-uplink NAT exception override configuration on the VLAN. Applicable only for networks that support NAT exceptions.
@@ -2954,6 +3105,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
"mask",
"ipv6",
"mandatoryDhcp",
+ "adaptivePolicyGroupId",
"sgt",
"vrf",
"uplinks",
@@ -3013,12 +3165,22 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
- enabled (boolean): Boolean value to enable or disable the BGP configuration. When BGP is enabled, the asNumber (ASN) will be autopopulated with the preconfigured ASN at other Hubs or a default value if there is no ASN configured.
- asNumber (integer): An Autonomous System Number (ASN) is required if you are to run BGP and peer with another BGP Speaker outside of the Auto VPN domain. This ASN will be applied to the entire Auto VPN domain and is only configurable for Auto VPN BGP networks. The entire 4-byte ASN range is supported. So, the ASN must be an integer between 1 and 4294967295. When absent, this field is not updated. If no value exists then it defaults to 64512.
- ibgpHoldTimer (integer): The iBGP holdtimer in seconds. The iBGP holdtimer must be an integer between 12 and 240. When absent, this field is not updated. If no value exists then it defaults to 240.
+ - ipv6 (object): Settings for IPv6 configurations on the organization.
+ - tunnelDownTermination (object): Settings for tunnel down termination on the organization.
+ - vpnAsNumber (integer): Network specific number of the Autonomous System to which the appliance belongs. This field is only configurable for Independent BGP networks.
+ - priorityRoute (string): Sets the priority route between eBGP and Auto VPN.
- routerId (string): The router ID of the appliance
- neighbors (array): List of BGP neighbors. This list replaces the existing set of neighbors. When absent, this field is not updated.
"""
kwargs.update(locals())
+ if "priorityRoute" in kwargs and kwargs["priorityRoute"] is not None:
+ options = ["Auto VPN", "eBGP"]
+ assert kwargs["priorityRoute"] in options, (
+ f'''"priorityRoute" cannot be "{kwargs["priorityRoute"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
"tags": ["appliance", "configure", "vpn", "bgp"],
"operation": "updateNetworkApplianceVpnBgp",
@@ -3030,6 +3192,10 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
"enabled",
"asNumber",
"ibgpHoldTimer",
+ "ipv6",
+ "tunnelDownTermination",
+ "vpnAsNumber",
+ "priorityRoute",
"routerId",
"neighbors",
]
@@ -3043,6 +3209,41 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkApplianceVpnSiteToSiteHubVrfs(self, networkId: str, hubNetworkId: str, _json: list, **kwargs):
+ """
+ **Update the VRF mappings for a source network and hub pair.**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-appliance-vpn-site-to-site-hub-vrfs
+
+ - networkId (string): Network ID
+ - hubNetworkId (string): Hub network ID
+ - _json (array): The list of VRFs for this source and hub mapping.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "vpn", "siteToSite", "hubs", "vrfs"],
+ "operation": "updateNetworkApplianceVpnSiteToSiteHubVrfs",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ hubNetworkId = urllib.parse.quote(str(hubNetworkId), safe="")
+ resource = f"/networks/{networkId}/appliance/vpn/siteToSite/hubs/{hubNetworkId}/vrfs"
+
+ body_params = [
+ "_json",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkApplianceVpnSiteToSiteHubVrfs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkApplianceVpnSiteToSiteVpn(self, networkId: str):
"""
**Return the site-to-site VPN settings of a network**
@@ -3069,6 +3270,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw
- mode (string): The site-to-site VPN mode. Can be one of 'none', 'spoke' or 'hub'
- hubs (array): The list of VPN hubs, in order of preference. In spoke mode, at least 1 hub is required.
- subnets (array): The list of subnets and their VPN presence.
+ - peerSgtCapable (boolean): Whether or not Peer SGT is enabled for traffic to this VPN peer.
- sgt (object): Security Group Tag settings for the VPN peer.
- subnet (object): Configuration of subnet features
- hostTranslations (array): The list of VPN host translations. Host translations are supported starting from MX firmware version 26.1.2
@@ -3091,6 +3293,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw
"mode",
"hubs",
"subnets",
+ "peerSgtCapable",
"sgt",
"subnet",
"hostTranslations",
@@ -3382,6 +3585,68 @@ def getOrganizationApplianceDevicesRedundancyByNetwork(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationApplianceDevicesSystemUtilizationByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return the appliance utilization history for devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-devices-system-utilization-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 2 hours.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 1200. The default is 1200.
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): Optional parameter to filter device utilization history by device serial numbers
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "devices", "system", "utilization", "byInterval"],
+ "operation": "getOrganizationApplianceDevicesSystemUtilizationByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/devices/system/utilization/byInterval"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceDevicesSystemUtilizationByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApplianceDnsLocalProfiles(self, organizationId: str, **kwargs):
"""
**Fetch the local DNS profiles used in the organization**
@@ -4167,6 +4432,55 @@ def updateOrganizationApplianceRoutingVrfsSettings(self, organizationId: str, en
return self._session.put(metadata, resource, payload)
+ def getOrganizationApplianceSdwanInternetPolicies(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get the SDWAN internet traffic preferences for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-sdwan-internet-policies
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 200. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - wanTrafficUplinkPreferences (array): policies with respective traffic filters for an MX network
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "sdwan", "internetPolicies"],
+ "operation": "getOrganizationApplianceSdwanInternetPolicies",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/sdwan/internetPolicies"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "wanTrafficUplinkPreferences",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "wanTrafficUplinkPreferences",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSdwanInternetPolicies: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApplianceSecurityEvents(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List the security events for an organization**
@@ -4220,6 +4534,58 @@ def getOrganizationApplianceSecurityEvents(self, organizationId: str, total_page
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def httpsiOrganizationApplianceSecurity(self, organizationId: str):
+ """
+ **Retrieve the HTTPS Inspection state for all security appliances in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!httpsi-organization-appliance-security
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security"],
+ "operation": "httpsiOrganizationApplianceSecurity",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/httpsi"
+
+ return self._session.get(metadata, resource)
+
+ def certificatesOrganizationApplianceSecurityHttpsi(self, organizationId: str, contents: str, serials: list, **kwargs):
+ """
+ **Upload an HTTPS Inspection certificate to MX devices in the same organization**
+ https://developer.cisco.com/meraki/api-v1/#!certificates-organization-appliance-security-httpsi
+
+ - organizationId (string): Organization ID
+ - contents (string): The private key and certificate used to inspect HTTPS traffic. The certificate must be in .pem format.
+ - serials (array): Serial numbers of the security appliances that will receive the new HTTPS certificate for HTTPS Inspection
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "httpsi"],
+ "operation": "certificatesOrganizationApplianceSecurityHttpsi",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/httpsi/certificates"
+
+ body_params = [
+ "contents",
+ "serials",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"certificatesOrganizationApplianceSecurityHttpsi: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getOrganizationApplianceSecurityIntrusion(self, organizationId: str):
"""
**Returns all supported intrusion settings for an organization**
@@ -4270,30 +4636,841 @@ def updateOrganizationApplianceSecurityIntrusion(self, organizationId: str, allo
return self._session.put(metadata, resource, payload)
- def getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork(
+ def getOrganizationApplianceSecurityIntrusionPolicies(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Display VPN exclusion rules for MX networks.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-traffic-shaping-vpn-exclusions-by-network
+ **List the intrusion policies configured for an organization along with base policies.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-policies
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter the results by network IDs
+ - mode (string): Controls which policy set is returned.
+ - policyIds (array): Identifiers of policies to filter
+ - search (string): Filter policies by case-insensitive partial match on name or description.
"""
kwargs.update(locals())
+ if "mode" in kwargs:
+ options = ["base", "intrusion"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
metadata = {
- "tags": ["appliance", "configure", "trafficShaping", "vpnExclusions", "byNetwork"],
- "operation": "getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork",
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "getOrganizationApplianceSecurityIntrusionPolicies",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/appliance/trafficShaping/vpnExclusions/byNetwork"
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "mode",
+ "policyIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionPolicies: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, **kwargs):
+ """
+ **Create a new intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policy (object): Attributes for the intrusion policy
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "createOrganizationApplianceSecurityIntrusionPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApplianceSecurityIntrusionPolicy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationApplianceSecurityIntrusionPoliciesOverviews(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List counts for the intrusion and base policies configured for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-policies-overviews
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Identifiers of policies to filter
+ - search (string): Filter policy overviews by case-insensitive partial match on policy name or description.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "overviews"],
+ "operation": "getOrganizationApplianceSecurityIntrusionPoliciesOverviews",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/overviews"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionPoliciesOverviews: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, policyId: str, policy: dict, **kwargs):
+ """
+ **Update a single intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - policy (object): Attributes for the intrusion policy
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "updateOrganizationApplianceSecurityIntrusionPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApplianceSecurityIntrusionPolicy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, policyId: str):
+ """
+ **Delete a single intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "deleteOrganizationApplianceSecurityIntrusionPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}"
+
+ return self._session.delete(metadata, resource)
+
+ def declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides(
+ self, organizationId: str, policyId: str, items: list, **kwargs
+ ):
+ """
+ **Declare the desired rule group overrides for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!declare-organization-appliance-security-intrusion-policy-rule-groups-overrides
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - items (array): Desired overrides state
+ - mode (string): Controls how the configuration payload in the request body is applied to the resource. This parameter dictates the declarative mode:
+
+ * **`complete`**: The request body represents the entire desired configuration for this resource. Any existing configurations that are not included in the payload will be removed.
+ * **`partial` (default)**: The request body contains only the configurations to be created or modified. Existing configurations that are not specified in the payload will be preserved.
+
+ - recursive (boolean): Controls how the configuration payload in the request body applies to the rule group hierarchy. When true, the API applies each declared override to the rule group itself and its descendants unless the payload explicitly sets a descendant override. When false (default), the API applies overrides only to the rule groups listed in the payload.
+
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["complete", "partial"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "ruleGroups", "overrides"],
+ "operation": "declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/overrides/declare"
+ )
+
+ body_params = [
+ "mode",
+ "recursive",
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride(
+ self, organizationId: str, policyId: str, ruleGroupId: str, override: dict, **kwargs
+ ):
+ """
+ **Create a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy-rule-group-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleGroupId (string): Rule group ID
+ - override (object): Attributes for the override for a rule group in a intrusion policy
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "ruleGroups", "override"],
+ "operation": "createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleGroupId = urllib.parse.quote(str(ruleGroupId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/{ruleGroupId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride(
+ self, organizationId: str, policyId: str, ruleGroupId: str, override: dict, **kwargs
+ ):
+ """
+ **Update a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy-rule-group-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleGroupId (string): Rule group ID
+ - override (object): Attributes for the override for a rule group in a intrusion policy
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "ruleGroups", "override"],
+ "operation": "updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleGroupId = urllib.parse.quote(str(ruleGroupId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/{ruleGroupId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides(
+ self, organizationId: str, policyId: str, items: list, **kwargs
+ ):
+ """
+ **Declare the desired rule overrides for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!declare-organization-appliance-security-intrusion-policy-rules-overrides
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - items (array): Desired overrides state
+ - mode (string): Controls how the configuration payload in the request body is applied to the resource. This parameter dictates the declarative mode:
+
+ * **`complete`**: The request body represents the entire desired configuration for this resource. Any existing configurations that are not included in the payload will be removed. This effectively performs a full replacement or overwrite of the resource's configuration.
+ * **`partial` (default)**: The request body contains only the configurations to be created or modified. Existing configurations that are not specified in the payload will be preserved. This performs a merge or partial update, applying only the changes specified.
+
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["complete", "partial"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "rules", "overrides"],
+ "operation": "declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/overrides/declare"
+
+ body_params = [
+ "mode",
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationApplianceSecurityIntrusionPolicyRuleOverride(
+ self, organizationId: str, policyId: str, ruleId: str, override: dict, **kwargs
+ ):
+ """
+ **Create a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy-rule-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - override (object): Rule override to create
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "rules", "override"],
+ "operation": "createOrganizationApplianceSecurityIntrusionPolicyRuleOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/{ruleId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApplianceSecurityIntrusionPolicyRuleOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride(
+ self, organizationId: str, policyId: str, ruleId: str, override: dict, **kwargs
+ ):
+ """
+ **Update a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy-rule-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - override (object): Override attributes
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "rules", "override"],
+ "operation": "updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/{ruleId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationApplianceSecurityIntrusionRuleGroups(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the rule groups that belong to a security policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rule-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Collection of base or intrusion policy identifiers to filter results by
+ - parentRuleGroupIds (array): Filter results to rule groups whose parent matches any of the provided identifiers
+ - search (string): Case-insensitive text filter applied to rule group name and description
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRuleGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "parentRuleGroupIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ "parentRuleGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRuleGroups: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceSecurityIntrusionRuleGroupsOverrides(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the rule group overrides configured for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rule-groups-overrides
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Collection of intrusion policy identifiers to filter the overrides by.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups", "overrides"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRuleGroupsOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overrides"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRuleGroupsOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationApplianceSecurityIntrusionRuleGroupsOverride(self, organizationId: str, overrideId: str):
+ """
+ **Delete a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-rule-groups-override
+
+ - organizationId (string): Organization ID
+ - overrideId (string): Override ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups", "overrides"],
+ "operation": "deleteOrganizationApplianceSecurityIntrusionRuleGroupsOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ overrideId = urllib.parse.quote(str(overrideId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overrides/{overrideId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationApplianceSecurityIntrusionRuleGroupsOverviews(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List counts for the child rule groups and rules for each rule group in a security policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rule-groups-overviews
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Collection of base or intrusion policy identifiers to filter results by
+ - parentRuleGroupIds (array): Filter results to rule groups whose parent matches any of the provided identifiers
+ - search (string): Case-insensitive text filter applied to rule group name and description
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups", "overviews"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRuleGroupsOverviews",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overviews"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "parentRuleGroupIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ "parentRuleGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRuleGroupsOverviews: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceSecurityIntrusionRules(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the rules that belong to a security policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Identifiers of the base or intrusion policies to query
+ - parentRuleGroupIds (array): Filter results to rules that belong to any of the specified rule groups
+ - search (string): Case-insensitive text filter applied to rule name and description
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "rules"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "parentRuleGroupIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ "parentRuleGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceSecurityIntrusionRulesOverrides(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the rule overrides configured for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rules-overrides
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Identifiers of intrusion policies to filter
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "rules", "overrides"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRulesOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules/overrides"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRulesOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationApplianceSecurityIntrusionRulesOverride(self, organizationId: str, overrideId: str):
+ """
+ **Delete a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-rules-override
+
+ - organizationId (string): Organization ID
+ - overrideId (string): Override ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "rules", "overrides"],
+ "operation": "deleteOrganizationApplianceSecurityIntrusionRulesOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ overrideId = urllib.parse.quote(str(overrideId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules/overrides/{overrideId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Display VPN exclusion rules for MX networks.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-traffic-shaping-vpn-exclusions-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter the results by network IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "trafficShaping", "vpnExclusions", "byNetwork"],
+ "operation": "getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/trafficShaping/vpnExclusions/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceUmbrellaPoliciesByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List Umbrella policy IDs applied to MX networks in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-umbrella-policies-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Filter results to only the given network IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella", "policies", "byNetwork"],
+ "operation": "getOrganizationApplianceUmbrellaPoliciesByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/umbrella/policies/byNetwork"
query_params = [
"perPage",
@@ -4316,7 +5493,7 @@ def getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationApplianceUmbrellaPoliciesByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
@@ -4506,6 +5683,282 @@ def getOrganizationApplianceUplinksUsageByNetwork(self, organizationId: str, **k
return self._session.get(metadata, resource, params)
+ def getOrganizationApplianceVlans(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the VLANs for an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vlans
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "vlans"],
+ "operation": "getOrganizationApplianceVlans",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vlans"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationApplianceVlans: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceVpnConnectivityVpnPeersByNetwork(self, organizationId: str, **kwargs):
+ """
+ **Summarizes by-device vpn peers for the organization in the given interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-connectivity-vpn-peers-by-network
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 3600, 14400, 86400. The default is 3600. Interval is calculated if time params are provided.
+ - networkIds (array): Filter results by network.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "connectivity", "vpnPeers", "byNetwork"],
+ "operation": "getOrganizationApplianceVpnConnectivityVpnPeersByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/connectivity/vpnPeers/byNetwork"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnConnectivityVpnPeersByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnRemoteAccessSecureClientAuthenticationByClient(self, organizationId: str, **kwargs):
+ """
+ **Get authentication for all clients in organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-remote-access-secure-client-authentication-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "remoteAccess", "secureClient", "authentication", "byClient"],
+ "operation": "getOrganizationApplianceVpnRemoteAccessSecureClientAuthenticationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/remoteAccess/secureClient/authentication/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnRemoteAccessSecureClientAuthenticationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnRemoteAccessSecureClientIpAssignmentByClient(self, organizationId: str, **kwargs):
+ """
+ **Get IP assignment for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-remote-access-secure-client-ip-assignment-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "remoteAccess", "secureClient", "ipAssignment", "byClient"],
+ "operation": "getOrganizationApplianceVpnRemoteAccessSecureClientIpAssignmentByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/remoteAccess/secureClient/ipAssignment/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnRemoteAccessSecureClientIpAssignmentByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnRemoteAccessSecureClientTunnelCreationByClient(self, organizationId: str, **kwargs):
+ """
+ **Get tunnel creation events for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-remote-access-secure-client-tunnel-creation-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "remoteAccess", "secureClient", "tunnelCreation", "byClient"],
+ "operation": "getOrganizationApplianceVpnRemoteAccessSecureClientTunnelCreationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/remoteAccess/secureClient/tunnelCreation/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnRemoteAccessSecureClientTunnelCreationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnSiteToSiteHubsVrfs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return source-to-hub VRF mappings for site-to-site VPN within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-site-to-site-hubs-vrfs
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter source-to-hub mappings by source network IDs.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "vpn", "siteToSite", "hubs", "vrfs"],
+ "operation": "getOrganizationApplianceVpnSiteToSiteHubsVrfs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/siteToSite/hubs/vrfs"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnSiteToSiteHubsVrfs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApplianceVpnSiteToSiteIpsecPeersSlas(self, organizationId: str):
"""
**Get the list of available IPsec SLA policies for an organization**
diff --git a/meraki/aio/api/assistant.py b/meraki/aio/api/assistant.py
new file mode 100644
index 00000000..3dfece69
--- /dev/null
+++ b/meraki/aio/api/assistant.py
@@ -0,0 +1,491 @@
+import urllib
+
+
+class AsyncAssistant:
+ def __init__(self, session):
+ super().__init__()
+ self._session = session
+
+ def getOrganizationAssistantCapabilities(self, organizationId: str):
+ """
+ **List the AI assistant's available capabilities and agents for this organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-capabilities
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "capabilities"],
+ "operation": "getOrganizationAssistantCapabilities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/capabilities"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationAssistantChatCompletion(self, organizationId: str, **kwargs):
+ """
+ **Create a chat completion with the AI assistant**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-completion
+
+ - organizationId (string): Organization ID
+ - query (string): Simple text question or instruction to send to the AI assistant. Provide either 'query' for text-only requests or 'content' for multi-modal input.
+ - content (array): List of multi-modal content blocks. Use instead of 'query' to send text or images. Supports text and image types only; for audio and file support, use the messages endpoint. Maximum 8 parts.
+ - threadId (string): An existing thread ID to continue a conversation. If omitted, a new thread is created.
+ - networkId (string): Optional network ID to scope the query to a specific network. Defaults to the user's last visited network.
+ - platform (string): Platform identifier. Defaults to MERAKI when omitted. Case-insensitive.
+ - language (string): Optional language override. Defaults to the user's preferred language.
+ - country (string): Optional country override. Defaults to the user's country.
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs:
+ options = ["DIGITAL_TWIN", "DNAC", "MERAKI", "digital_twin", "dnac", "meraki"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "completions"],
+ "operation": "createOrganizationAssistantChatCompletion",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/completions"
+
+ body_params = [
+ "query",
+ "content",
+ "threadId",
+ "networkId",
+ "platform",
+ "language",
+ "country",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatCompletion: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantChatThreads(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List all active conversation threads for the authenticated user.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-threads
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of entries per page. Defaults to 100. Maximum 1000.
+ - sort (string): Field to sort results by. Defaults to dateModified.
+ - sortOrder (string): Sort direction for results. Defaults to desc.
+ - from (string): Filter threads modified after this timestamp.
+ - to (string): Filter threads modified before this timestamp.
+ """
+
+ kwargs.update(locals())
+
+ if "sort" in kwargs:
+ options = ["dateModified", "id", "name"]
+ assert kwargs["sort"] in options, f'''"sort" cannot be "{kwargs["sort"]}", & must be set to one of: {options}'''
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "getOrganizationAssistantChatThreads",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads"
+
+ query_params = [
+ "perPage",
+ "sort",
+ "sortOrder",
+ "from",
+ "to",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAssistantChatThreads: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationAssistantChatThread(self, organizationId: str, **kwargs):
+ """
+ **Create a new conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadName (string): Display name for the new thread.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "createOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads"
+
+ body_params = [
+ "threadName",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatThread: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantChatThread(self, organizationId: str, threadId: str):
+ """
+ **Return a single conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "getOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationAssistantChatThread(self, organizationId: str, threadId: str, threadName: str, **kwargs):
+ """
+ **Update the name of a conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - threadName (string): New display name for the thread.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "updateOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}"
+
+ body_params = [
+ "threadName",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationAssistantChatThread: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationAssistantChatThread(self, organizationId: str, threadId: str):
+ """
+ **Delete a conversation thread and all its messages.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "deleteOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationAssistantChatThreadMessages(
+ self, organizationId: str, threadId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List messages in a conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-messages
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of entries per page. Defaults to 100. Maximum 1000.
+ - sortOrder (string): Sort direction for results by timestamp. Defaults to asc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages"],
+ "operation": "getOrganizationAssistantChatThreadMessages",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages"
+
+ query_params = [
+ "perPage",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssistantChatThreadMessages: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationAssistantChatThreadMessage(self, organizationId: str, threadId: str, content: list, **kwargs):
+ """
+ **Create a new chat message in a thread.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-thread-message
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - content (array): List of message content parts. Supports text, image, audio, and file types. Maximum 8 parts.
+ - networkName (string): Name of the target network.
+ - networkId (string): Optional Meraki network ID for thread context.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages"],
+ "operation": "createOrganizationAssistantChatThreadMessage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages"
+
+ body_params = [
+ "content",
+ "networkName",
+ "networkId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatThreadMessage: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantChatThreadMessage(self, organizationId: str, threadId: str, messageId: str):
+ """
+ **Return a single message in a conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages"],
+ "operation": "getOrganizationAssistantChatThreadMessage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationAssistantChatThreadMessageArtifacts(self, organizationId: str, threadId: str, messageId: str):
+ """
+ **List artifacts attached to a specific message**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message-artifacts
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "artifacts"],
+ "operation": "getOrganizationAssistantChatThreadMessageArtifacts",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/artifacts"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationAssistantChatThreadMessageArtifact(
+ self, organizationId: str, threadId: str, messageId: str, artifactId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return a single artifact with its full content.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message-artifact
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ - artifactId (string): Artifact ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - page (integer): Page number for paginated artifact content, defaulting to 1
+ - perPage (integer): Number of entries per page. Defaults to 100. Maximum 1000.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "artifacts"],
+ "operation": "getOrganizationAssistantChatThreadMessageArtifact",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ artifactId = urllib.parse.quote(str(artifactId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/artifacts/{artifactId}"
+ )
+
+ query_params = [
+ "page",
+ "perPage",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssistantChatThreadMessageArtifact: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssistantChatThreadMessageFeedback(self, organizationId: str, threadId: str, messageId: str):
+ """
+ **Return all feedback entries previously submitted for a specific message in a thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message-feedback
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "feedback"],
+ "operation": "getOrganizationAssistantChatThreadMessageFeedback",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/feedback"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationAssistantChatThreadMessageFeedback(
+ self, organizationId: str, threadId: str, messageId: str, vote: bool, **kwargs
+ ):
+ """
+ **Submit or replace feedback for a specific assistant message.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-thread-message-feedback
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ - vote (boolean): True for positive, false for negative.
+ - reason (string): Optional free-text reason for the feedback (e.g., 'inaccurate', 'incomplete', 'helpful'). Not constrained to a fixed set of values.
+ - comment (string): Optional free-text comment providing additional detail.
+ - message (string): The assistant message text the feedback refers to. Captured for analytics; not required.
+ - prompt (string): The user prompt that produced the assistant message. Captured for analytics; not required.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "feedback"],
+ "operation": "createOrganizationAssistantChatThreadMessageFeedback",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/feedback"
+
+ body_params = [
+ "vote",
+ "reason",
+ "comment",
+ "message",
+ "prompt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatThreadMessageFeedback: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantQueryLimits(self, organizationId: str):
+ """
+ **Get query limits for the AI assistant for this organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-query-limits
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "queryLimits"],
+ "operation": "getOrganizationAssistantQueryLimits",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/queryLimits"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/aio/api/camera.py b/meraki/aio/api/camera.py
index 98e5c8ac..8d29b25b 100644
--- a/meraki/aio/api/camera.py
+++ b/meraki/aio/api/camera.py
@@ -739,6 +739,97 @@ def getNetworkCameraSchedules(self, networkId: str):
return self._session.get(metadata, resource)
+ def createNetworkCameraVideoWall(self, networkId: str, name: str, tiles: list, **kwargs):
+ """
+ **Create a new video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - name (string): The name of the video wall.
+ - tiles (array): The tiles that should appear on the video wall.
+ - index (integer): The order that this wall should appear on the video wall list.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "createNetworkCameraVideoWall",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls"
+
+ body_params = [
+ "name",
+ "index",
+ "tiles",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkCameraVideoWall: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateNetworkCameraVideoWall(self, networkId: str, id: str, name: str, tiles: list, **kwargs):
+ """
+ **Update the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - id (string): ID
+ - name (string): The name of the video wall.
+ - tiles (array): The tiles that should appear on the video wall.
+ - index (integer): The order that this wall should appear on the video wall list.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "updateNetworkCameraVideoWall",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls/{id}"
+
+ body_params = [
+ "name",
+ "index",
+ "tiles",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkCameraVideoWall: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteNetworkCameraVideoWall(self, networkId: str, id: str):
+ """
+ **Delete the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "deleteNetworkCameraVideoWall",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls/{id}"
+
+ return self._session.delete(metadata, resource)
+
def createNetworkCameraWirelessProfile(self, networkId: str, name: str, ssid: dict, **kwargs):
"""
**Creates a new camera wireless profile for this network.**
@@ -1091,6 +1182,45 @@ def getOrganizationCameraDetectionsHistoryByBoundaryByInterval(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationCameraDevicesConfigurations(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Lists all the capabilities of cameras in this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-devices-configurations
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "devices", "configurations"],
+ "operation": "getOrganizationCameraDevicesConfigurations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/camera/devices/configurations"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCameraDevicesConfigurations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationCameraOnboardingStatuses(self, organizationId: str, **kwargs):
"""
**Fetch onboarding status of cameras**
@@ -1336,3 +1466,104 @@ def updateOrganizationCameraRole(self, organizationId: str, roleId: str, **kwarg
self._session._logger.warning(f"updateOrganizationCameraRole: ignoring unrecognized kwargs: {invalid}")
return self._session.put(metadata, resource, payload)
+
+ def getOrganizationCameraVideoWalls(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return a list of video walls.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-video-walls
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 10 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of network ids to filter video walls on
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "getOrganizationCameraVideoWalls",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/camera/videoWalls"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationCameraVideoWalls: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCameraVideoWall(self, organizationId: str, id: str):
+ """
+ **Return the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-video-wall
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "getOrganizationCameraVideoWall",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/camera/videoWalls/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationCameraVideoWallVideoLink(self, organizationId: str, id: str, **kwargs):
+ """
+ **Returns video wall link to the specified video wall id**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-video-wall-video-link
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - timestamp (string): [optional] The video link will start at this time. The timestamp should be a string in ISO8601 format. If no timestamp is specified, we will assume current time.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls", "videoLink"],
+ "operation": "getOrganizationCameraVideoWallVideoLink",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/camera/videoWalls/{id}/videoLink"
+
+ query_params = [
+ "timestamp",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCameraVideoWallVideoLink: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
diff --git a/meraki/aio/api/campusGateway.py b/meraki/aio/api/campusGateway.py
index ed7cee55..90e053a1 100644
--- a/meraki/aio/api/campusGateway.py
+++ b/meraki/aio/api/campusGateway.py
@@ -96,6 +96,150 @@ def updateNetworkCampusGatewayCluster(self, networkId: str, clusterId: str, **kw
return self._session.put(metadata, resource, payload)
+ def deleteNetworkCampusGatewayCluster(self, networkId: str, clusterId: str):
+ """
+ **Delete a cluster**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-campus-gateway-cluster
+
+ - networkId (string): Network ID
+ - clusterId (string): Cluster ID
+ """
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters"],
+ "operation": "deleteNetworkCampusGatewayCluster",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clusterId = urllib.parse.quote(str(clusterId), safe="")
+ resource = f"/networks/{networkId}/campusGateway/clusters/{clusterId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getNetworkCampusGatewaySsidMdns(self, networkId: str, number: str):
+ """
+ **List the currently configured mDNS settings for the SSID**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-campus-gateway-ssid-mdns
+
+ - networkId (string): Network ID
+ - number (string): Number
+ """
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "ssids", "mdns"],
+ "operation": "getNetworkCampusGatewaySsidMdns",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/campusGateway/ssids/{number}/mdns"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkCampusGatewaySsidMdns(self, networkId: str, number: str, **kwargs):
+ """
+ **Update the mDNS gateway settings and rules for a SSID and cluster**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-campus-gateway-ssid-mdns
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - enabled (boolean): If true, mDNS gateway is enabled for this SSID and cluster.
+ - rules (array): List of mDNS forwarding rules.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "ssids", "mdns"],
+ "operation": "updateNetworkCampusGatewaySsidMdns",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/campusGateway/ssids/{number}/mdns"
+
+ body_params = [
+ "enabled",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkCampusGatewaySsidMdns: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationCampusGatewayClientsUsageByNetworkByCluster(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns client usage details for campus gateway clusters within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clients-usage-by-network-by-cluster
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - networkIds (array): Filter results by a list of network IDs.
+ - networkGroupIds (array): Limit the results to clients that belong to one of the provided network groups.
+ - clusterIds (array): Filter results by a list of cluster IDs.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "monitor", "clients", "usage", "byNetwork", "byCluster"],
+ "operation": "getOrganizationCampusGatewayClientsUsageByNetworkByCluster",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clients/usage/byNetwork/byCluster"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "networkGroupIds",
+ "clusterIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "clusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClientsUsageByNetworkByCluster: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationCampusGatewayClusters(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Get the details of campus gateway clusters**
@@ -143,6 +287,556 @@ def getOrganizationCampusGatewayClusters(self, organizationId: str, total_pages=
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationCampusGatewayClustersFailoverTargets(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the details of a Failover Targets for a Campus Gateway cluster**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-failover-targets
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - clusterIds (array): Optional parameter to filter clusters. This filter uses multiple exact matches.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "failover", "targets"],
+ "operation": "getOrganizationCampusGatewayClustersFailoverTargets",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/failover/targets"
+
+ query_params = [
+ "networkIds",
+ "clusterIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "clusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersFailoverTargets: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayClustersFailoverTargetsByCluster(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get available backup cluster targets for campus gateway failover configuration**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-failover-targets-by-cluster
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Networks for which backup cluster targets should be gathered.
+ - clusterIds (array): Cluster IDs to filter backup cluster targets.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "failover", "targets", "byCluster"],
+ "operation": "getOrganizationCampusGatewayClustersFailoverTargetsByCluster",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/failover/targets/byCluster"
+
+ query_params = [
+ "networkIds",
+ "clusterIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "clusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersFailoverTargetsByCluster: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayClustersNetworksOverviews(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List networks tunneling through Campus Gateway clusters with their AP, ssids and client counts**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-networks-overviews
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - clusterIds (array): Optional parameter to filter by MCG cluster IDs. This filter uses multiple exact matches.
+ - siteIds (array): Optional parameter to filter by site IDs. This filter uses multiple exact matches.
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - tunnelingSources (array): Optional parameter to filter networks by tunneling source. 'configured' returns networks explicitly set up to tunnel through the campus gateway. 'roaming' returns networks tunneling due to AP roaming or disaster recovery. 'roaming' is only effective when 'clusterIds' is also provided; without 'clusterIds', the filter defaults to configured-only behavior. Defaults to 'configured' if omitted.
+ - search (string): Optional parameter to filter networks by wireless network name. This filter uses case-insensitive substring matching.
+ - sortBy (string): Optional parameter to sort results. Default is 'name'. Use 'siteName' to sort by site name.
+ - sortOrder (string): Optional parameter to specify sort direction. Default is 'asc'.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["clients", "clusterId", "connections", "name", "networkId", "siteName", "ssids"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "networks", "overviews"],
+ "operation": "getOrganizationCampusGatewayClustersNetworksOverviews",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/networks/overviews"
+
+ query_params = [
+ "clusterIds",
+ "siteIds",
+ "networkIds",
+ "tunnelingSources",
+ "search",
+ "sortBy",
+ "sortOrder",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clusterIds",
+ "siteIds",
+ "networkIds",
+ "tunnelingSources",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersNetworksOverviews: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def provisionOrganizationCampusGatewayClusters(
+ self,
+ organizationId: str,
+ clusterId: str,
+ network: dict,
+ name: str,
+ uplinks: list,
+ tunnels: list,
+ nameservers: dict,
+ portChannels: list,
+ **kwargs,
+ ):
+ """
+ **Provisions a cluster,adds campus gateways to it and associate/dissociate failover targets.**
+ https://developer.cisco.com/meraki/api-v1/#!provision-organization-campus-gateway-clusters
+
+ - organizationId (string): Organization ID
+ - clusterId (string): ID of the cluster to be provisioned
+ - network (object): Network to be provisioned
+ - name (string): Name of the new cluster
+ - uplinks (array): Uplink interface settings of the cluster
+ - tunnels (array): Tunnel interface settings of the cluster: Reuse uplink or specify tunnel interface
+ - nameservers (object): Nameservers of the cluster
+ - portChannels (array): Port channel settings of the cluster
+ - devices (array): Devices to be added to the cluster
+ - failover (object): Failover targets for the cluster
+ - notes (string): Notes about cluster with max size of 511 characters allowed
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters"],
+ "operation": "provisionOrganizationCampusGatewayClusters",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/provision"
+
+ body_params = [
+ "clusterId",
+ "network",
+ "name",
+ "uplinks",
+ "tunnels",
+ "nameservers",
+ "portChannels",
+ "devices",
+ "failover",
+ "notes",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"provisionOrganizationCampusGatewayClusters: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationCampusGatewayClustersSsids(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List SSIDs tunneling through Campus Gateway clusters**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-ssids
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - clusterIds (array): Optional parameter to filter by MCG cluster IDs. This filter uses multiple exact matches.
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - search (string): Optional parameter to filter SSIDs by name. This filter uses case-insensitive starts with string matching.
+ - sortBy (string): Optional parameter to sort results. Default is 'networkId'.
+ - sortOrder (string): Optional parameter to specify sort direction. Default is 'asc'.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["clusterId", "name", "networkId", "ssidId"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "ssids"],
+ "operation": "getOrganizationCampusGatewayClustersSsids",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/ssids"
+
+ query_params = [
+ "clusterIds",
+ "networkIds",
+ "search",
+ "sortBy",
+ "sortOrder",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clusterIds",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersSsids: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayClustersTunnelingByClusterByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all the MCG cluster-network tunnel settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-tunneling-by-cluster-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - clusterIds (array): Optional parameter to filter MCG clusters. This filter uses multiple exact matches
+ - dataEncryptionEnabled (boolean): Optional parameter to filter cluster-network tunnel settings by data encryption configuration
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "tunneling", "byCluster", "byNetwork"],
+ "operation": "getOrganizationCampusGatewayClustersTunnelingByClusterByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/tunneling/byCluster/byNetwork"
+
+ query_params = [
+ "clusterIds",
+ "dataEncryptionEnabled",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clusterIds",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersTunnelingByClusterByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate(self, organizationId: str, **kwargs):
+ """
+ **Update MCG cluster-network tunnel settings for multiple networks**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-campus-gateway-clusters-tunneling-by-cluster-by-network-update
+
+ - organizationId (string): Organization ID
+ - items (array): MCG cluster-network tunnel settings
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "tunneling", "byCluster", "byNetwork"],
+ "operation": "batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/tunneling/byCluster/byNetwork/batchUpdate"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationCampusGatewayConnections(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the details of APs tunneling through the Campus Gateway clusters**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-connections
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter connections(APs) by its own serials. This filter uses multiple exact matches.
+ - campusGatewaySerials (array): Optional parameter to filter connections(APs) by MCG serials. This filter uses multiple exact matches.
+ - campusGatewayClusterIds (array): Optional parameter to filter connections(APs) by MCG cluster IDs. This filter uses multiple exact matches.
+ - campusGatewayTunnelStatuses (array): Optional parameter to filter connections(APs) by tunnel statuses. This filter uses multiple exact matches.
+ - search (string): Optional parameter to filter connections(APs) on AP name, serial, MAC address, network name, or interface IP address. This filter uses partial string matching (ILIKE).
+ - models (array): Optional parameter to filter connections(APs) by device model names. This filter uses multiple exact matches.
+ - dataEncryptionStatuses (array): Optional parameter to filter connections(APs) by data encryption status. This filter uses multiple exact matches.
+ - sortBy (string): Optional parameter to sort results. Available options: name, serial, status, interfaces, clients, dataEncryption, networkName. Default is 'serial'.
+ - sortOrder (string): Optional parameter to specify sort direction. Default is 'asc'.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["clients", "dataEncryption", "interfaces", "name", "networkName", "serial", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "connections"],
+ "operation": "getOrganizationCampusGatewayConnections",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/connections"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "search",
+ "models",
+ "dataEncryptionStatuses",
+ "sortBy",
+ "sortOrder",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "models",
+ "dataEncryptionStatuses",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayConnections: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayConnectionsOverview(self, organizationId: str, **kwargs):
+ """
+ **List the count of connections(APs) with tunneling status up and down through the Campus Gateway clusters**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-connections-overview
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter connections(APs) by its own serials. This filter uses multiple exact matches.
+ - campusGatewaySerials (array): Optional parameter to filter connections(APs) by Campus Gateway serials. This filter uses multiple exact matches.
+ - campusGatewayClusterIds (array): Optional parameter to filter connections(APs) by Campus Gateway cluster IDs. This filter uses multiple exact matches.
+ - campusGatewayTunnelStatuses (array): Optional parameter to filter connections(APs) by tunnel statuses. This filter uses multiple exact matches.
+ - search (string): Optional setting that lets you filter access points (APs) by name, serial number, MAC address, network name, or interface IP address. The filter matches partial text, not just exact values (uses ILIKE matching).
+ - models (array): Optional parameter to filter connections(APs) by device model names. This filter uses multiple exact matches.
+ - dataEncryptionStatuses (array): Optional parameter to filter connections(APs) by data encryption status. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "connections", "overview"],
+ "operation": "getOrganizationCampusGatewayConnectionsOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/connections/overview"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "search",
+ "models",
+ "dataEncryptionStatuses",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "models",
+ "dataEncryptionStatuses",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayConnectionsOverview: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
def getOrganizationCampusGatewayDevicesUplinksLocalOverridesByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
diff --git a/meraki/aio/api/devices.py b/meraki/aio/api/devices.py
index f07f3436..3e24199b 100644
--- a/meraki/aio/api/devices.py
+++ b/meraki/aio/api/devices.py
@@ -232,6 +232,56 @@ def createDeviceCellularUplinksBandsMasksUpdate(self, serial: str, slot: str, ty
return self._session.post(metadata, resource, payload)
+ def revokeDeviceCertificate(self, serial: str, certificateSerial: str, **kwargs):
+ """
+ **Revoke a device certificate**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-device-certificate
+
+ - serial (string): Serial
+ - certificateSerial (string): Certificate serial
+ - reason (string): Revocation reason per RFC 5280; omit to use `unspecified`
+ """
+
+ kwargs.update(locals())
+
+ if "reason" in kwargs:
+ options = [
+ "aACompromise",
+ "affiliationChanged",
+ "cACompromise",
+ "certificateHold",
+ "cessationOfOperation",
+ "keyCompromise",
+ "privilegeWithdrawn",
+ "removeFromCRL",
+ "superseded",
+ "unspecified",
+ ]
+ assert kwargs["reason"] in options, (
+ f'''"reason" cannot be "{kwargs["reason"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["devices", "configure", "certificates"],
+ "operation": "revokeDeviceCertificate",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ certificateSerial = urllib.parse.quote(str(certificateSerial), safe="")
+ resource = f"/devices/{serial}/certificates/{certificateSerial}/revoke"
+
+ body_params = [
+ "reason",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"revokeDeviceCertificate: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
def getDeviceClients(self, serial: str, **kwargs):
"""
**List the clients of a device, up to a maximum of a month ago**
@@ -265,6 +315,56 @@ def getDeviceClients(self, serial: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def createDeviceLiveToolsAclHitCount(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform an ACL hit count for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-acl-hit-count
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "aclHitCount"],
+ "operation": "createDeviceLiveToolsAclHitCount",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/aclHitCount"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsAclHitCount: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsAclHitCount(self, serial: str, id: str):
+ """
+ **Return an ACL hit count live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-acl-hit-count
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "aclHitCount"],
+ "operation": "getDeviceLiveToolsAclHitCount",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/aclHitCount/{id}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsArpTable(self, serial: str, **kwargs):
"""
**Enqueue a job to perform a ARP table request for the device**
@@ -367,6 +467,75 @@ def getDeviceLiveToolsCableTest(self, serial: str, id: str):
return self._session.get(metadata, resource)
+ def getDeviceLiveToolsClientsDisconnect(self, serial: str, id: str):
+ """
+ **Return a client disconnect job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-clients-disconnect
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "clients", "disconnect"],
+ "operation": "getDeviceLiveToolsClientsDisconnect",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/clients/disconnect/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsDhcpLease(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a DHCP leases request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-dhcp-lease
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "dhcpLeases"],
+ "operation": "createDeviceLiveToolsDhcpLease",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/dhcpLeases"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsDhcpLease: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsDhcpLease(self, serial: str, dhcpLeasesId: str):
+ """
+ **Return a DHCP leases live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-dhcp-lease
+
+ - serial (string): Serial
+ - dhcpLeasesId (string): Dhcp leases ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "dhcpLeases"],
+ "operation": "getDeviceLiveToolsDhcpLease",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ dhcpLeasesId = urllib.parse.quote(str(dhcpLeasesId), safe="")
+ resource = f"/devices/{serial}/liveTools/dhcpLeases/{dhcpLeasesId}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsLedsBlink(self, serial: str, duration: int, **kwargs):
"""
**Enqueue a job to blink LEDs on a device**
@@ -425,6 +594,7 @@ def createDeviceLiveToolsMacTable(self, serial: str, **kwargs):
https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-mac-table
- serial (string): Serial
+ - mac (string): Optional parameter to filter MAC table entries by MAC address. Must be a colon-delimited six-octet MAC address, for example '00:11:22:a0:b1:c2'. Matching is case-insensitive.
- callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
"""
@@ -438,6 +608,7 @@ def createDeviceLiveToolsMacTable(self, serial: str, **kwargs):
resource = f"/devices/{serial}/liveTools/macTable"
body_params = [
+ "mac",
"callback",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -521,6 +692,56 @@ def getDeviceLiveToolsMulticastRouting(self, serial: str, multicastRoutingId: st
return self._session.get(metadata, resource)
+ def createDeviceLiveToolsOspfNeighbor(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a OSPF neighbors request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ospf-neighbor
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "ospfNeighbors"],
+ "operation": "createDeviceLiveToolsOspfNeighbor",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/ospfNeighbors"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsOspfNeighbor: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsOspfNeighbor(self, serial: str, ospfNeighborsId: str):
+ """
+ **Return an OSPF neighbors live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ospf-neighbor
+
+ - serial (string): Serial
+ - ospfNeighborsId (string): Ospf neighbors ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "ospfNeighbors"],
+ "operation": "getDeviceLiveToolsOspfNeighbor",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ ospfNeighborsId = urllib.parse.quote(str(ospfNeighborsId), safe="")
+ resource = f"/devices/{serial}/liveTools/ospfNeighbors/{ospfNeighborsId}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsPing(self, serial: str, target: str, **kwargs):
"""
**Enqueue a job to ping a target host from the device**
@@ -779,6 +1000,89 @@ def getDeviceLiveToolsPowerUsage(self, serial: str, jobId: str):
return self._session.get(metadata, resource)
+ def createDeviceLiveToolsReboot(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to reboot a device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-reboot
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "reboot"],
+ "operation": "createDeviceLiveToolsReboot",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/reboot"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsReboot: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsReboot(self, serial: str, rebootId: str):
+ """
+ **Return a reboot job**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-reboot
+
+ - serial (string): Serial
+ - rebootId (string): Reboot ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "reboot"],
+ "operation": "getDeviceLiveToolsReboot",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ rebootId = urllib.parse.quote(str(rebootId), safe="")
+ resource = f"/devices/{serial}/liveTools/reboot/{rebootId}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsRoutingTable(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a routing table request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table
+
+ - serial (string): Serial
+ - destination (object): Optional destination filter used to return routes containing the supplied destination.
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "routingTable"],
+ "operation": "createDeviceLiveToolsRoutingTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/routingTable"
+
+ body_params = [
+ "destination",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsRoutingTable: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs):
"""
**Enqueue a job to perform a routing table lookup request for a device**
@@ -911,6 +1215,81 @@ def getDeviceLiveToolsRoutingTableSummary(self, serial: str, id: str):
return self._session.get(metadata, resource)
+ def getDeviceLiveToolsRoutingTable(self, serial: str, id: str):
+ """
+ **Return an routing table live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-routing-table
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "routingTable"],
+ "operation": "getDeviceLiveToolsRoutingTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/routingTable/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsSpeedTest(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to execute a speed test from a device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-speed-test
+
+ - serial (string): Serial
+ - interface (string): Optional filter for a specific WAN interface. Valid interfaces are wan1, wan2, wan3, wan4. Default will return wan1.
+ """
+
+ kwargs.update(locals())
+
+ if "interface" in kwargs:
+ options = ["wan1", "wan2", "wan3", "wan4"]
+ assert kwargs["interface"] in options, (
+ f'''"interface" cannot be "{kwargs["interface"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["devices", "liveTools", "speedTest"],
+ "operation": "createDeviceLiveToolsSpeedTest",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/speedTest"
+
+ body_params = [
+ "interface",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsSpeedTest: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsSpeedTest(self, serial: str, id: str):
+ """
+ **Returns a speed test result in megabits per second**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-speed-test
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "speedTest"],
+ "operation": "getDeviceLiveToolsSpeedTest",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/speedTest/{id}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsThroughputTest(self, serial: str, **kwargs):
"""
**Enqueue a job to test a device throughput, the test will run for 10 secs to test throughput**
@@ -961,6 +1340,110 @@ def getDeviceLiveToolsThroughputTest(self, serial: str, throughputTestId: str):
return self._session.get(metadata, resource)
+ def createDeviceLiveToolsTraceRoute(self, serial: str, target: str, sourceInterface: str, **kwargs):
+ """
+ **Enqueue a job to run trace route in the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-trace-route
+
+ - serial (string): Serial
+ - target (string): Destination Host name or address
+ - sourceInterface (string): Source Interface IP address
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "traceRoute"],
+ "operation": "createDeviceLiveToolsTraceRoute",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/traceRoute"
+
+ body_params = [
+ "target",
+ "sourceInterface",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsTraceRoute: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsTraceRoute(self, serial: str, traceRouteId: str):
+ """
+ **Return a trace route job**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-trace-route
+
+ - serial (string): Serial
+ - traceRouteId (string): Trace route ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "traceRoute"],
+ "operation": "getDeviceLiveToolsTraceRoute",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ traceRouteId = urllib.parse.quote(str(traceRouteId), safe="")
+ resource = f"/devices/{serial}/liveTools/traceRoute/{traceRouteId}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsVrrpTable(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a VRRP table request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-vrrp-table
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "vrrpTable"],
+ "operation": "createDeviceLiveToolsVrrpTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/vrrpTable"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsVrrpTable: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsVrrpTable(self, serial: str, vrrpTableId: str):
+ """
+ **Return an VRRP table live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-vrrp-table
+
+ - serial (string): Serial
+ - vrrpTableId (string): Vrrp table ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "vrrpTable"],
+ "operation": "getDeviceLiveToolsVrrpTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ vrrpTableId = urllib.parse.quote(str(vrrpTableId), safe="")
+ resource = f"/devices/{serial}/liveTools/vrrpTable/{vrrpTableId}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsWakeOnLan(self, serial: str, vlanId: int, mac: str, **kwargs):
"""
**Enqueue a job to send a Wake-on-LAN packet from the device**
diff --git a/meraki/aio/api/insight.py b/meraki/aio/api/insight.py
index 98345d24..eab3e2a9 100644
--- a/meraki/aio/api/insight.py
+++ b/meraki/aio/api/insight.py
@@ -64,6 +64,95 @@ def getOrganizationInsightApplications(self, organizationId: str):
return self._session.get(metadata, resource)
+ def createOrganizationInsightApplication(self, organizationId: str, counterSetRuleId: int, **kwargs):
+ """
+ **Add an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - counterSetRuleId (integer): The id of the counter set rule
+ - enableSmartThresholds (boolean): Enable Smart Thresholds
+ - thresholds (object): Thresholds defined by a user for each application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "applications"],
+ "operation": "createOrganizationInsightApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications"
+
+ body_params = [
+ "counterSetRuleId",
+ "enableSmartThresholds",
+ "thresholds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationInsightApplication: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationInsightApplication(self, organizationId: str, applicationId: str, **kwargs):
+ """
+ **Update an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - applicationId (string): Application ID
+ - enableSmartThresholds (boolean): Enable Smart Thresholds
+ - thresholds (object): Thresholds defined by a user for each application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "applications"],
+ "operation": "updateOrganizationInsightApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ applicationId = urllib.parse.quote(str(applicationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications/{applicationId}"
+
+ body_params = [
+ "enableSmartThresholds",
+ "thresholds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationInsightApplication: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationInsightApplication(self, organizationId: str, applicationId: str):
+ """
+ **Delete an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - applicationId (string): Application ID
+ """
+
+ metadata = {
+ "tags": ["insight", "configure", "applications"],
+ "operation": "deleteOrganizationInsightApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ applicationId = urllib.parse.quote(str(applicationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications/{applicationId}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationInsightMonitoredMediaServers(self, organizationId: str):
"""
**List the monitored media servers for this organization**
@@ -194,3 +283,154 @@ def deleteOrganizationInsightMonitoredMediaServer(self, organizationId: str, mon
resource = f"/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}"
return self._session.delete(metadata, resource)
+
+ def getOrganizationInsightSpeedTestResults(self, organizationId: str, serials: list, **kwargs):
+ """
+ **List the speed tests for the given devices under this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-insight-speed-test-results
+
+ - organizationId (string): Organization ID
+ - serials (array): A list of serial numbers. The returned results will be filtered to only include these serials.
+ - timespan (integer): Amount of seconds ago to query for results. Only include timespan OR both t0 & t1.
+ - t0 (integer): Start time to query for results in epoch seconds. Only include timespan OR both t0 & t1.
+ - t1 (integer): End time to query for results in epoch seconds. Only include timespan OR both t0 & t1.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "speedTestResults"],
+ "operation": "getOrganizationInsightSpeedTestResults",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/speedTestResults"
+
+ query_params = [
+ "serials",
+ "timespan",
+ "t0",
+ "t1",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationInsightSpeedTestResults: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationInsightWebApps(self, organizationId: str):
+ """
+ **Lists all default web applications rules with counter set rule ids**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-insight-web-apps
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "getOrganizationInsightWebApps",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationInsightWebApp(self, organizationId: str, name: str, hostname: str, **kwargs):
+ """
+ **Add a custom web application for Insight to be able to track**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the Web Application
+ - hostname (string): The hostname of Web Application
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "createOrganizationInsightWebApp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps"
+
+ body_params = [
+ "name",
+ "hostname",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationInsightWebApp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationInsightWebApp(self, organizationId: str, customCounterSetRuleId: str, **kwargs):
+ """
+ **Update a custom web application for Insight to be able to track**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - customCounterSetRuleId (string): Custom counter set rule ID
+ - name (string): The name of the Web Application
+ - hostname (string): The hostname of Web Application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "updateOrganizationInsightWebApp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ customCounterSetRuleId = urllib.parse.quote(str(customCounterSetRuleId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps/{customCounterSetRuleId}"
+
+ body_params = [
+ "name",
+ "hostname",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationInsightWebApp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationInsightWebApp(self, organizationId: str, customCounterSetRuleId: str):
+ """
+ **Delete a custom web application by counter set rule id.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - customCounterSetRuleId (string): Custom counter set rule ID
+ """
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "deleteOrganizationInsightWebApp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ customCounterSetRuleId = urllib.parse.quote(str(customCounterSetRuleId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps/{customCounterSetRuleId}"
+
+ return self._session.delete(metadata, resource)
diff --git a/meraki/aio/api/licensing.py b/meraki/aio/api/licensing.py
index 962e7654..c8ba0f9f 100644
--- a/meraki/aio/api/licensing.py
+++ b/meraki/aio/api/licensing.py
@@ -45,6 +45,39 @@ def getAdministeredLicensingSubscriptionEntitlements(self, **kwargs):
return self._session.get(metadata, resource, params)
+ def batchAdministeredLicensingSubscriptionNetworksFeatureTiersUpdate(self, **kwargs):
+ """
+ **Batch change networks to their desired feature tier for specified product types**
+ https://developer.cisco.com/meraki/api-v1/#!batch-administered-licensing-subscription-networks-feature-tiers-update
+
+ - items (array): List of networks and corresponding product types to update. Maximum 500 networks
+ - isAtomic (boolean): Flag to determine if the operation should act atomically
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["licensing", "configure", "subscription", "featureTiers"],
+ "operation": "batchAdministeredLicensingSubscriptionNetworksFeatureTiersUpdate",
+ }
+ resource = "/administered/licensing/subscription/networks/featureTiers/batchUpdate"
+
+ body_params = [
+ "items",
+ "isAtomic",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchAdministeredLicensingSubscriptionNetworksFeatureTiersUpdate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getAdministeredLicensingSubscriptionSubscriptions(
self, organizationIds: list, total_pages=1, direction="next", **kwargs
):
diff --git a/meraki/aio/api/nac.py b/meraki/aio/api/nac.py
new file mode 100644
index 00000000..0dcad5ca
--- /dev/null
+++ b/meraki/aio/api/nac.py
@@ -0,0 +1,1151 @@
+import urllib
+
+
+class AsyncNac:
+ def __init__(self, session):
+ super().__init__()
+ self._session = session
+
+ def getOrganizationNacAuthorizationPolicies(self, organizationId: str, **kwargs):
+ """
+ **Get all nac authorization policies for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-authorization-policies
+
+ - organizationId (string): Organization ID
+ - policyIds (array): List of ids for specific authorization policies retrieval
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies"],
+ "operation": "getOrganizationNacAuthorizationPolicies",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies"
+
+ query_params = [
+ "policyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacAuthorizationPolicies: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def createOrganizationNacAuthorizationPolicyRule(
+ self, organizationId: str, policyId: str, name: str, rank: int, authorizationProfile: dict, **kwargs
+ ):
+ """
+ **Create a rule in an authorization policy set of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-authorization-policy-rule
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - name (string): Name of Authorization rule
+ - rank (integer): Rank of Authorization rule
+ - authorizationProfile (object): Authorization profile associated with the rule
+ - enabled (boolean): Enabled status of authorization rule. Default is False.
+ - sourcePolicyVersion (string): Source policy version of the policy set containing this rule
+ - condition (object): Condition of Authorization rule.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies", "rules"],
+ "operation": "createOrganizationNacAuthorizationPolicyRule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies/{policyId}/rules"
+
+ body_params = [
+ "name",
+ "rank",
+ "enabled",
+ "sourcePolicyVersion",
+ "authorizationProfile",
+ "condition",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacAuthorizationPolicyRule: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationNacAuthorizationPolicyRule(
+ self, organizationId: str, policyId: str, ruleId: str, name: str, rank: int, authorizationProfile: dict, **kwargs
+ ):
+ """
+ **Update an existing rule of an authorization policy set within an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-authorization-policy-rule
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - name (string): Name of Authorization rule
+ - rank (integer): Rank of Authorization rule
+ - authorizationProfile (object): Authorization profile associated with the rule
+ - enabled (boolean): Enabled status of authorization rule. Default is False.
+ - sourcePolicyVersion (string): Source policy version of the policy set containing this rule
+ - condition (object): Condition of Authorization rule.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies", "rules"],
+ "operation": "updateOrganizationNacAuthorizationPolicyRule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies/{policyId}/rules/{ruleId}"
+
+ body_params = [
+ "name",
+ "rank",
+ "enabled",
+ "sourcePolicyVersion",
+ "authorizationProfile",
+ "condition",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationNacAuthorizationPolicyRule: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationNacAuthorizationPolicyRule(self, organizationId: str, policyId: str, ruleId: str, **kwargs):
+ """
+ **Delete a rule in an authorization policy set of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-authorization-policy-rule
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - sourcePolicyVersion (string): Source policy version of the policy set containing this rule
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies", "rules"],
+ "operation": "deleteOrganizationNacAuthorizationPolicyRule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies/{policyId}/rules/{ruleId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationNacCertificates(self, organizationId: str, **kwargs):
+ """
+ **Gets all certificates for an organization and can filter by certificate status, expiry date and last used date**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates
+
+ - organizationId (string): Organization ID
+ - status (string): Status Parameter for GetAll request
+ - expiry (boolean): Boolean indicating whether to filter by expiry in one month
+ - lastUsed (boolean): Boolean indicating whether to filter by last used in over one month
+ """
+
+ kwargs.update(locals())
+
+ if "status" in kwargs:
+ options = ["Disabled", "Enabled"]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates"],
+ "operation": "getOrganizationNacCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates"
+
+ query_params = [
+ "status",
+ "expiry",
+ "lastUsed",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacCertificatesAuthoritiesCrls(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get all the organization's CRL.It's possible to filter results by CRL issuers (CA) or CRL's ID - see caIds and crlIds query parameters.This endpoint could be used for 'show' action when you specify a single CRL ID in crlIds parameter**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates-authorities-crls
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 5.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortBy (string): Optional parameter to specify the field used to sort results. (default: caId)
+ - sortOrder (string): Optional parameter to specify the sort order. (default: asc)
+ - crlIds (array): A list of CRL ids. The returned CRLs will be filtered to only include these ids
+ - caIds (array): When ca Ids are provided, only CRLs associated to the given CA will be returned. Otherwise, all the CRLs created for an organization will be returned.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["caId", "createdAt", "lastUpdatedAt"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls"],
+ "operation": "getOrganizationNacCertificatesAuthoritiesCrls",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortBy",
+ "sortOrder",
+ "crlIds",
+ "caIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "crlIds",
+ "caIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacCertificatesAuthoritiesCrls: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNacCertificatesAuthoritiesCrl(
+ self, organizationId: str, caId: str, content: str, isDelta: bool, **kwargs
+ ):
+ """
+ **Create a new CRL (either base or delta) for an existing CA**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-certificates-authorities-crl
+
+ - organizationId (string): Organization ID
+ - caId (string): ID of the CRL issuer
+ - content (string): CRL content in PEM format
+ - isDelta (boolean): Whether it's a delta CRL or not
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls"],
+ "operation": "createOrganizationNacCertificatesAuthoritiesCrl",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls"
+
+ body_params = [
+ "caId",
+ "content",
+ "isDelta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacCertificatesAuthoritiesCrl: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNacCertificatesAuthoritiesCrlsDescriptors(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get all the organization's CRL descriptors (metadata only - revocation list data is excluded)**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates-authorities-crls-descriptors
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortBy (string): Optional parameter to specify the field used to sort results. (default: caId)
+ - sortOrder (string): Optional parameter to specify the sort order. (default: asc)
+ - caIds (array): When ca Ids are provided, only CRLs associated to the given CA will be returned. Otherwise, all the CRLs created for an organization will be returned.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["caId", "createdAt", "lastUpdatedAt"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls", "descriptors"],
+ "operation": "getOrganizationNacCertificatesAuthoritiesCrlsDescriptors",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls/descriptors"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortBy",
+ "sortOrder",
+ "caIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "caIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacCertificatesAuthoritiesCrlsDescriptors: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationNacCertificatesAuthoritiesCrl(self, organizationId: str, crlId: str):
+ """
+ **Deletes a whole CRL, including all its deltas (in case of base CRL removal)**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-certificates-authorities-crl
+
+ - organizationId (string): Organization ID
+ - crlId (string): Crl ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls"],
+ "operation": "deleteOrganizationNacCertificatesAuthoritiesCrl",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ crlId = urllib.parse.quote(str(crlId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls/{crlId}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationNacCertificatesImport(self, organizationId: str, contents: str, **kwargs):
+ """
+ **Import certificate for this organization or validate without persisting**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-certificates-import
+
+ - organizationId (string): Organization ID
+ - contents (string): Certificate content in valid PEM format
+ - dryRun (boolean): If true, validates the certificate without persisting it
+ - profile (object): Profile object containing certificate config fields
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "import"],
+ "operation": "createOrganizationNacCertificatesImport",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/import"
+
+ body_params = [
+ "contents",
+ "dryRun",
+ "profile",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacCertificatesImport: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNacCertificatesOverview(self, organizationId: str):
+ """
+ **Get counts of Enabled, Disabled, Expired and Last Used certificates for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates-overview
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "overview"],
+ "operation": "getOrganizationNacCertificatesOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/overview"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationNacCertificate(self, organizationId: str, certificateId: str, profile: dict, **kwargs):
+ """
+ **Update certificate configuration by certificateId for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-certificate
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ - profile (object): Profile object containing certificate config fields
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates"],
+ "operation": "updateOrganizationNacCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/{certificateId}"
+
+ body_params = [
+ "profile",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNacCertificate: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationNacClients(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get all known clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-clients
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - sortOrder (string): Query parameter for specifying the direction of sorting to use for the given sortKey.
+ - sortKey (string): Query parameter to sort the clients by the value of the specified key.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): Optional parameter to fuzzy search on clients.
+ - clientIds (array): List of ids for specific client retrieval
+ - groupIds (array): List of group ids for client retrieval by group
+ - lastNetworkName (array): List of network names for client retrieval by last login network name
+ - ssid (array): List of SSID's to filter
+ - classification (object): Classification filters for client retrieval
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ASC", "DESC"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = ["mac"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "getOrganizationNacClients",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients"
+
+ query_params = [
+ "sortOrder",
+ "sortKey",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "clientIds",
+ "groupIds",
+ "lastNetworkName",
+ "ssid",
+ "classification",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clientIds",
+ "groupIds",
+ "lastNetworkName",
+ "ssid",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacClients: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNacClient(self, organizationId: str, mac: str, **kwargs):
+ """
+ **Create a client for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-client
+
+ - organizationId (string): Organization ID
+ - mac (string): The MAC address of the client
+ - type (string): Type describes if the network client belongs to an individual user or corporate
+ - owner (string): The username of the owner of the client
+ - description (string): User provided description for the client
+ - uuid (string): Universally unique identifier of the client
+ - userDetails (array): List of users of this network client
+ - oui (object): Organizationally unique identifier assigned to a vendor of the client
+ - groups (array): List of group members associated with the client
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["BYOD", "corporate"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "createOrganizationNacClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients"
+
+ body_params = [
+ "type",
+ "owner",
+ "mac",
+ "description",
+ "uuid",
+ "userDetails",
+ "oui",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNacClient: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def bulkOrganizationNacClientsDelete(self, organizationId: str, clientIds: list, **kwargs):
+ """
+ **Delete existing client(s) for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-nac-clients-delete
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of ids for specific client retrieval
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "bulkOrganizationNacClientsDelete",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkDelete"
+
+ body_params = [
+ "clientIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"bulkOrganizationNacClientsDelete: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationNacClientsBulkEdit(self, organizationId: str, clientIds: list, **kwargs):
+ """
+ **Bulk Update of existing clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-bulk-edit
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of clients ids to apply the bulk edit operation on.
+ - description (string): User provided description to be applied on the list of clients provided
+ - groups (object): Client group information to be applied on the list of clients provided
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "bulkEdit"],
+ "operation": "createOrganizationNacClientsBulkEdit",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkEdit"
+
+ body_params = [
+ "clientIds",
+ "description",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNacClientsBulkEdit: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationNacClientsBulkUpload(
+ self, organizationId: str, contents: str, updateClients: bool, createClientGroups: bool, **kwargs
+ ):
+ """
+ **Bulk upload of clients, client groups and their associations for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-bulk-upload
+
+ - organizationId (string): Organization ID
+ - contents (string): CSV file content in Base64 encoded string format
+ - updateClients (boolean): The updateClients indicates whether existing clients must be updated with new data from the CSV
+ - createClientGroups (boolean): The createClientGroups indicates whether new client groups must be created or not
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "bulkUpload"],
+ "operation": "createOrganizationNacClientsBulkUpload",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkUpload"
+
+ body_params = [
+ "contents",
+ "updateClients",
+ "createClientGroups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacClientsBulkUpload: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNacClientsGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get all known client groups for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-clients-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - sortOrder (string): Query parameter for specifying the direction of sorting to use for the given sortKey.
+ - sortKey (string): Query parameter to sort the client groups by the value of the specified key.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): Optional parameter to fuzzy search on client groups.
+ - groupIds (array): List of ids for specific group retrieval
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ASC", "DESC"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = ["name"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "getOrganizationNacClientsGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups"
+
+ query_params = [
+ "sortOrder",
+ "sortKey",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "groupIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "groupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacClientsGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNacClientsGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a client group for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the group for access control model
+ - description (string): User provided description of the group
+ - members (array): List of client members associated with the group
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "createOrganizationNacClientsGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups"
+
+ body_params = [
+ "name",
+ "description",
+ "members",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNacClientsGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationNacClientsGroup(self, organizationId: str, groupId: str, **kwargs):
+ """
+ **Update an existing client group for the organization with bulk member operations**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - name (string): The name of the group for access control model
+ - description (string): User provided description of the group
+ - members (object): Bulk member operations with addList/removeList arrays
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "updateOrganizationNacClientsGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups/{groupId}"
+
+ body_params = [
+ "name",
+ "description",
+ "members",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNacClientsGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationNacClientsGroup(self, organizationId: str, groupId: str):
+ """
+ **Delete an existing client group for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "deleteOrganizationNacClientsGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups/{groupId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationNacClientsOverview(self, organizationId: str):
+ """
+ **Get overview data for all known clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-clients-overview
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "overview"],
+ "operation": "getOrganizationNacClientsOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/overview"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationNacClient(self, organizationId: str, clientId: str, mac: str, **kwargs):
+ """
+ **Update an existing client for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-client
+
+ - organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - mac (string): The MAC address of the client
+ - type (string): Type describes if the network client belongs to an individual user or corporate
+ - owner (string): The username of the owner of the client
+ - description (string): User provided description for the client
+ - uuid (string): Universally unique identifier of the client
+ - userDetails (array): List of users of this network client
+ - oui (object): Organizationally unique identifier assigned to a vendor of the client
+ - groups (object): Client group membership changes
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["BYOD", "corporate"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "updateOrganizationNacClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/{clientId}"
+
+ body_params = [
+ "type",
+ "owner",
+ "mac",
+ "description",
+ "uuid",
+ "userDetails",
+ "oui",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNacClient: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationNacDictionaries(self, organizationId: str):
+ """
+ **Get all NAC dictionaries**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-dictionaries
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "dictionaries"],
+ "operation": "getOrganizationNacDictionaries",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/dictionaries"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationNacDictionaryAttributes(self, organizationId: str, dictionaryId: str, **kwargs):
+ """
+ **Get all attributes by dictionary ID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-dictionary-attributes
+
+ - organizationId (string): Organization ID
+ - dictionaryId (string): Dictionary ID
+ - networkIds (array): An optional list of network IDs to filter the 'enum' field. Only enum values applicable to the specified networks will be returned.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "dictionaries", "attributes"],
+ "operation": "getOrganizationNacDictionaryAttributes",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ dictionaryId = urllib.parse.quote(str(dictionaryId), safe="")
+ resource = f"/organizations/{organizationId}/nac/dictionaries/{dictionaryId}/attributes"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacDictionaryAttributes: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacDictionaryAttributeValues(
+ self, organizationId: str, dictionaryId: str, attributeName: str, **kwargs
+ ):
+ """
+ **Search allowed values for a dictionary attribute**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-dictionary-attribute-values
+
+ - organizationId (string): Organization ID
+ - dictionaryId (string): Dictionary ID
+ - attributeName (string): Attribute name
+ - search (string): Optional search string for contains-match filtering of allowed values
+ - networkIds (array): An optional list of network IDs to filter the allowed values.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "dictionaries", "attributes", "values"],
+ "operation": "getOrganizationNacDictionaryAttributeValues",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ dictionaryId = urllib.parse.quote(str(dictionaryId), safe="")
+ attributeName = urllib.parse.quote(str(attributeName), safe="")
+ resource = f"/organizations/{organizationId}/nac/dictionaries/{dictionaryId}/attributes/{attributeName}/values"
+
+ query_params = [
+ "search",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacDictionaryAttributeValues: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacLicenseUsage(self, organizationId: str, startDate: str, **kwargs):
+ """
+ **Returns license usage data for a specific organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-license-usage
+
+ - organizationId (string): Organization ID
+ - startDate (string): Start date for the usage data in UTC timezone
+ - endDate (string): End date for the usage data in UTC timezone
+ - networkIds (array): List of locale and node group ids
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "license", "usage"],
+ "operation": "getOrganizationNacLicenseUsage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/license/usage"
+
+ query_params = [
+ "startDate",
+ "endDate",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacLicenseUsage: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacSessionsHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the NAC Sessions for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-sessions-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 hour.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "sessions", "history"],
+ "operation": "getOrganizationNacSessionsHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/sessions/history"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacSessionsHistory: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationNacSessionDetails(self, organizationId: str, sessionId: str):
+ """
+ **Return the details of selected NAC Sessions**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-session-details
+
+ - organizationId (string): Organization ID
+ - sessionId (string): Session ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "sessions", "details"],
+ "operation": "getOrganizationNacSessionDetails",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ sessionId = urllib.parse.quote(str(sessionId), safe="")
+ resource = f"/organizations/{organizationId}/nac/sessions/{sessionId}/details"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/aio/api/networks.py b/meraki/aio/api/networks.py
index 83c085c0..e995d1df 100644
--- a/meraki/aio/api/networks.py
+++ b/meraki/aio/api/networks.py
@@ -855,6 +855,23 @@ def vmxNetworkDevicesClaim(self, networkId: str, size: str, **kwargs):
return self._session.post(metadata, resource, payload)
+ def getNetworkDevicesJson(self, networkId: str):
+ """
+ **Extraction of the legacy nodes JSON endpoint for a network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-devices-json
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "devices", "json"],
+ "operation": "getNetworkDevicesJson",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/devices/json"
+
+ return self._session.get(metadata, resource)
+
def removeNetworkDevices(self, networkId: str, serial: str, **kwargs):
"""
**Remove a single device**
@@ -1486,6 +1503,7 @@ def createNetworkFloorPlan(self, networkId: str, name: str, imageContents: str,
- topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan.
- topRightCorner (object): The longitude and latitude of the top right corner of your floor plan.
- floorNumber (number): The floor number of the floors within the building
+ - buildingId (string): The ID of the building that this floor belongs to.
"""
kwargs.update(locals())
@@ -1505,6 +1523,7 @@ def createNetworkFloorPlan(self, networkId: str, name: str, imageContents: str,
"topLeftCorner",
"topRightCorner",
"floorNumber",
+ "buildingId",
"imageContents",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1701,6 +1720,7 @@ def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
- topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan.
- topRightCorner (object): The longitude and latitude of the top right corner of your floor plan.
- floorNumber (number): The floor number of the floors within the building
+ - buildingId (string): The ID of the building that this floor belongs to.
- imageContents (string): The file contents (a base 64 encoded string) of your new image. Supported formats are PNG, GIF, and JPG. Note that all images are saved as PNG files, regardless of the format they are uploaded in. If you upload a new image, and you do NOT specify any new geolocation fields ('center, 'topLeftCorner', etc), the floor plan will be recentered with no rotation in order to maintain the aspect ratio of your new image.
"""
@@ -1722,6 +1742,7 @@ def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
"topLeftCorner",
"topRightCorner",
"floorNumber",
+ "buildingId",
"imageContents",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1949,6 +1970,106 @@ def getNetworkHealthAlerts(self, networkId: str):
return self._session.get(metadata, resource)
+ def getNetworkLocationScanning(self, networkId: str):
+ """
+ **Return scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-location-scanning
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning"],
+ "operation": "getNetworkLocationScanning",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkLocationScanning(self, networkId: str, **kwargs):
+ """
+ **Change scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-location-scanning
+
+ - networkId (string): Network ID
+ - analyticsEnabled (boolean): Collect location and scanning analytics
+ - scanningApiEnabled (boolean): Enable push API for scanning events, analytics must be enabled
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning"],
+ "operation": "updateNetworkLocationScanning",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning"
+
+ body_params = [
+ "analyticsEnabled",
+ "scanningApiEnabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkLocationScanning: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getNetworkLocationScanningHttpServers(self, networkId: str):
+ """
+ **Return list of scanning API receivers**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-location-scanning-http-servers
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning", "httpServers"],
+ "operation": "getNetworkLocationScanningHttpServers",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning/httpServers"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkLocationScanningHttpServers(self, networkId: str, endpoints: list, **kwargs):
+ """
+ **Set the list of scanning API receivers**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-location-scanning-http-servers
+
+ - networkId (string): Network ID
+ - endpoints (array): A set of http server configurations
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning", "httpServers"],
+ "operation": "updateNetworkLocationScanningHttpServers",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning/httpServers"
+
+ body_params = [
+ "endpoints",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkLocationScanningHttpServers: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkMerakiAuthUsers(self, networkId: str):
"""
**List the authorized users configured under Meraki Authentication for a network (splash guest or RADIUS users for a wireless network, or client VPN users for a MX network)**
@@ -2106,14 +2227,17 @@ def updateNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **k
return self._session.put(metadata, resource, payload)
- def getNetworkMqttBrokers(self, networkId: str):
+ def getNetworkMqttBrokers(self, networkId: str, **kwargs):
"""
**List the MQTT brokers for this network**
https://developer.cisco.com/meraki/api-v1/#!get-network-mqtt-brokers
- networkId (string): Network ID
+ - productTypes (array): Optional parameter to filter MQTT brokers by product type. If multiple types are provided, the query will return brokers that match any of the provided types.
"""
+ kwargs.update(locals())
+
metadata = {
"tags": ["networks", "configure", "mqttBrokers"],
"operation": "getNetworkMqttBrokers",
@@ -2121,7 +2245,26 @@ def getNetworkMqttBrokers(self, networkId: str):
networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/mqttBrokers"
- return self._session.get(metadata, resource)
+ query_params = [
+ "productTypes",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getNetworkMqttBrokers: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: int, **kwargs):
"""
@@ -2134,10 +2277,17 @@ def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: in
- port (integer): Host port though which the MQTT broker can be reached.
- security (object): Security settings of the MQTT broker.
- authentication (object): Authentication settings of the MQTT broker
+ - productType (string): The product type for which the MQTT broker is being created.
"""
kwargs.update(locals())
+ if "productType" in kwargs:
+ options = ["camera", "wireless"]
+ assert kwargs["productType"] in options, (
+ f'''"productType" cannot be "{kwargs["productType"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
"tags": ["networks", "configure", "mqttBrokers"],
"operation": "createNetworkMqttBroker",
@@ -2151,6 +2301,7 @@ def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: in
"port",
"security",
"authentication",
+ "productType",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2637,6 +2788,7 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
- remoteStatusPageEnabled (boolean): Enables / disables access to the device status page (http://[device's LAN IP]). Optional. Can only be set if localStatusPageEnabled is set to true
- localStatusPage (object): A hash of Local Status page(s)' authentication options applied to the Network.
- securePort (object): A hash of SecureConnect options applied to the Network.
+ - fips (object): A hash of FIPS options applied to the Network
- namedVlans (object): A hash of Named VLANs options applied to the Network.
"""
@@ -2654,6 +2806,7 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
"remoteStatusPageEnabled",
"localStatusPage",
"securePort",
+ "fips",
"namedVlans",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2666,6 +2819,93 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def createNetworkSitesBuilding(self, networkId: str, name: str, **kwargs):
+ """
+ **Create a new building**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sites-building
+
+ - networkId (string): Network ID
+ - name (string): The name of the building
+ - floors (array): The floors of the building
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["networks", "configure", "sites", "buildings"],
+ "operation": "createNetworkSitesBuilding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings"
+
+ body_params = [
+ "name",
+ "floors",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSitesBuilding: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteNetworkSitesBuilding(self, networkId: str, buildingId: str):
+ """
+ **Delete a building**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-sites-building
+
+ - networkId (string): Network ID
+ - buildingId (string): Building ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "sites", "buildings"],
+ "operation": "deleteNetworkSitesBuilding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ buildingId = urllib.parse.quote(str(buildingId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings/{buildingId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateNetworkSitesBuilding(self, networkId: str, buildingId: str, **kwargs):
+ """
+ **Update a building**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-sites-building
+
+ - networkId (string): Network ID
+ - buildingId (string): Building ID
+ - name (string): The name of the building
+ - floors (array): The floors of the building
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["networks", "configure", "sites", "buildings"],
+ "operation": "updateNetworkSitesBuilding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ buildingId = urllib.parse.quote(str(buildingId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings/{buildingId}"
+
+ body_params = [
+ "name",
+ "floors",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSitesBuilding: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSnmp(self, networkId: str):
"""
**Return the SNMP settings for a network**
@@ -2728,6 +2968,47 @@ def updateNetworkSnmp(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkSnmpTraps(self, networkId: str, **kwargs):
+ """
+ **Update the SNMP trap configuration for the specified network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-snmp-traps
+
+ - networkId (string): Network ID
+ - mode (string): SNMP trap protocol version
+ - receiver (object): Stores the port and address
+ - v2 (object): V2 mode
+ - v3 (object): V3 mode
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["disabled", "v1/v2c", "v3"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["networks", "configure", "snmp", "traps"],
+ "operation": "updateNetworkSnmpTraps",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/snmp/traps"
+
+ body_params = [
+ "mode",
+ "receiver",
+ "v2",
+ "v3",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSnmpTraps: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSplashLoginAttempts(self, networkId: str, **kwargs):
"""
**List the splash login attempts for a network**
@@ -3040,9 +3321,10 @@ def createNetworkVlanProfile(self, networkId: str, name: str, vlanNames: list, v
- vlanNames (array): An array of named VLANs
- vlanGroups (array): An array of VLAN groups
- iname (string): IName of the profile
+ - allowedVlans (string): The VLANs allowed on the VLAN profile. Only applicable to trunk ports. The given range must be inclusive of all named VLANs.
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
"tags": ["networks", "configure", "vlanProfiles"],
@@ -3053,6 +3335,7 @@ def createNetworkVlanProfile(self, networkId: str, name: str, vlanNames: list, v
body_params = [
"name",
+ "allowedVlans",
"vlanNames",
"vlanGroups",
"iname",
@@ -3188,9 +3471,10 @@ def updateNetworkVlanProfile(self, networkId: str, iname: str, name: str, vlanNa
- name (string): Name of the profile, string length must be from 1 to 255 characters
- vlanNames (array): An array of named VLANs
- vlanGroups (array): An array of VLAN groups
+ - allowedVlans (string): The VLANs allowed on the VLAN profile. Only applicable to trunk ports. The given range must be inclusive of all named VLANs.
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
"tags": ["networks", "configure", "vlanProfiles"],
@@ -3202,6 +3486,7 @@ def updateNetworkVlanProfile(self, networkId: str, iname: str, name: str, vlanNa
body_params = [
"name",
+ "allowedVlans",
"vlanNames",
"vlanGroups",
]
diff --git a/meraki/aio/api/organizations.py b/meraki/aio/api/organizations.py
index 8b8edcc3..178a9e7d 100644
--- a/meraki/aio/api/organizations.py
+++ b/meraki/aio/api/organizations.py
@@ -1083,6 +1083,329 @@ def deleteOrganizationAlertsProfile(self, organizationId: str, alertConfigId: st
return self._session.delete(metadata, resource)
+ def getOrganizationApiPushProfiles(self, organizationId: str, **kwargs):
+ """
+ **List the push profiles in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-push-profiles
+
+ - organizationId (string): Organization ID
+ - inames (array): Optional parameter to filter the result set by the included set of push profile inames
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "getOrganizationApiPushProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles"
+
+ query_params = [
+ "inames",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "inames",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationApiPushProfiles: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def createOrganizationApiPushProfile(self, organizationId: str, iname: str, topic: dict, receiver: dict, **kwargs):
+ """
+ **Create a new push profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Immutable name of the resource. Must be unique within resources of this type.
+ - topic (object): Push topic
+ - receiver (object): Push receiver profile
+ - name (string): Name of push profile
+ - description (string): Description of push profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "createOrganizationApiPushProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles"
+
+ body_params = [
+ "iname",
+ "name",
+ "description",
+ "topic",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationApiPushProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationApiPushProfile(self, organizationId: str, iname: str, **kwargs):
+ """
+ **Update a push profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ - name (string): Name of push profile
+ - description (string): Description of push profile
+ - topic (object): Push topic
+ - receiver (object): Push receiver profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "updateOrganizationApiPushProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles/{iname}"
+
+ body_params = [
+ "name",
+ "description",
+ "topic",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationApiPushProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationApiPushProfile(self, organizationId: str, iname: str):
+ """
+ **Delete a push profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "deleteOrganizationApiPushProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles/{iname}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationApiPushReceiversProfiles(self, organizationId: str):
+ """
+ **List the push receiver profiles in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-push-receivers-profiles
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "getOrganizationApiPushReceiversProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str, receiver: dict, **kwargs):
+ """
+ **Create a new push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Immutable name of the resource. Must be unique within resources of this type.
+ - receiver (object): Webhook receiver
+ - name (string): Name of receiver profile
+ - description (string): Description of receiver profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "createOrganizationApiPushReceiversProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles"
+
+ body_params = [
+ "iname",
+ "name",
+ "description",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApiPushReceiversProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str):
+ """
+ **Delete a push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "deleteOrganizationApiPushReceiversProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles/{iname}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str, **kwargs):
+ """
+ **Update a push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ - name (string): Name of the receiver profile
+ - description (string): Description of the receiver profile
+ - receiver (object): API Push Receiver details
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "updateOrganizationApiPushReceiversProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles/{iname}"
+
+ body_params = [
+ "name",
+ "description",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApiPushReceiversProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationApiPushTopics(self, organizationId: str):
+ """
+ **List of push topics**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-push-topics
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "topics"],
+ "operation": "getOrganizationApiPushTopics",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/topics"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationApiRestProvisioningPipelines(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List pipelines with operation and status metadata, sorted by pipeline ID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-rest-provisioning-pipelines
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'descending'.
+ - status (string): If provided, filters pipelines by status. If omitted, pipelines of all statuses are returned. `pending` pipelines have not started, `active` pipelines have started but not finished, `success` pipelines completed successfully, and `error` pipelines failed.
+ - timespan (integer): Created-at lookback for matching pipelines, in seconds. Defaults to 7200 seconds. The maximum is 30 days.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "status" in kwargs:
+ options = ["active", "error", "pending", "success"]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "rest", "provisioning", "pipelines"],
+ "operation": "getOrganizationApiRestProvisioningPipelines",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/rest/provisioning/pipelines"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ "status",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRestProvisioningPipelines: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApiRestProvisioningPipelinesJobs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List pipeline jobs, with optional status filtering**
@@ -1369,47 +1692,195 @@ def getOrganizationApiRequestsOverviewResponseCodesByInterval(self, organization
return self._session.get(metadata, resource, params)
- def getOrganizationAssuranceAlerts(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationApiRequestsResponseCodesHistoryByAdmin(self, organizationId: str, **kwargs):
"""
- **Return all health alerts for an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-alerts
+ **Lists API request response codes and their counts aggregated by admin**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-admin
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 4 - 300. Default is 30.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
- - networkId (string): Optional parameter to filter alerts by network ids.
- - severity (string): Optional parameter to filter by severity type.
- - types (array): Optional parameter to filter by alert type.
- - tsStart (string): Optional parameter to filter by starting timestamp
- - tsEnd (string): Optional parameter to filter by end timestamp
- - category (string): Optional parameter to filter by category.
- - sortBy (string): Optional parameter to set column to sort by.
- - serials (array): Optional parameter to filter by primary device serial
- - deviceTypes (array): Optional parameter to filter by device types
- - deviceTags (array): Optional parameter to filter by device tags
- - active (boolean): Optional parameter to filter by active alerts defaults to true
- - dismissed (boolean): Optional parameter to filter by dismissed alerts defaults to false
- - resolved (boolean): Optional parameter to filter by resolved alerts defaults to false
- - suppressAlertsForOfflineNodes (boolean): When set to true the api will only return connectivity alerts for a given device if that device is in an offline state. This only applies to devices. This is ignored when resolved is true. Example: If a Switch has a VLan Mismatch and is Unreachable. only the Unreachable alert will be returned. Defaults to false.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
"""
kwargs.update(locals())
- if "sortOrder" in kwargs:
- options = ["ascending", "descending"]
- assert kwargs["sortOrder"] in options, (
- f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
- )
- if "category" in kwargs:
- options = ["configuration", "connectivity", "device_health", "experience_metrics", "insights"]
- assert kwargs["category"] in options, (
- f'''"category" cannot be "{kwargs["category"]}", & must be set to one of: {options}'''
- )
- if "sortBy" in kwargs:
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "byAdmin"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryByAdmin",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/byAdmin"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryByAdmin: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApiRequestsResponseCodesHistoryByApplication(self, organizationId: str, **kwargs):
+ """
+ **Lists API request response codes and their counts aggregated by application**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-application
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "byApplication"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryByApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/byApplication"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryByApplication: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApiRequestsResponseCodesHistoryByOperation(self, organizationId: str, **kwargs):
+ """
+ **Aggregates API usage data by operationId**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-operation
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "byOperation"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryByOperation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/byOperation"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryByOperation: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApiRequestsResponseCodesHistoryBySourceIp(self, organizationId: str, **kwargs):
+ """
+ **Aggregates API usage by source ip**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-source-ip
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "bySourceIp"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryBySourceIp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/bySourceIp"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryBySourceIp: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceAlerts(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return all health alerts for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-alerts
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 4 - 300. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
+ - networkId (string): Optional parameter to filter alerts by network ids.
+ - severity (string): Optional parameter to filter by severity type.
+ - types (array): Optional parameter to filter by alert type.
+ - tsStart (string): Optional parameter to filter by starting timestamp
+ - tsEnd (string): Optional parameter to filter by end timestamp
+ - category (string): Optional parameter to filter by category.
+ - sortBy (string): Optional parameter to set column to sort by.
+ - serials (array): Optional parameter to filter by primary device serial
+ - deviceTypes (array): Optional parameter to filter by device types
+ - deviceTags (array): Optional parameter to filter by device tags
+ - active (boolean): Optional parameter to filter by active alerts defaults to true
+ - dismissed (boolean): Optional parameter to filter by dismissed alerts defaults to false
+ - resolved (boolean): Optional parameter to filter by resolved alerts defaults to false
+ - suppressAlertsForOfflineNodes (boolean): When set to true the api will only return connectivity alerts for a given device if that device is in an offline state. This only applies to devices. This is ignored when resolved is true. Example: If a Switch has a VLan Mismatch and is Unreachable. only the Unreachable alert will be returned. Defaults to false.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "category" in kwargs:
+ options = ["configuration", "connectivity", "device_health", "experience_metrics", "insights"]
+ assert kwargs["category"] in options, (
+ f'''"category" cannot be "{kwargs["category"]}", & must be set to one of: {options}'''
+ )
+ if "sortBy" in kwargs:
options = ["category", "dismissedAt", "resolvedAt", "severity", "startedAt"]
assert kwargs["sortBy"] in options, (
f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
@@ -1908,170 +2379,2218 @@ def getOrganizationAssuranceAlert(self, organizationId: str, id: str):
return self._session.get(metadata, resource)
- def getOrganizationBrandingPolicies(self, organizationId: str):
+ def getOrganizationAssuranceClientsConnectedCountHistory(self, organizationId: str, networkId: str, **kwargs):
"""
- **List the branding policies of an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies
+ **Return combined wireless and wired connected client counts over time for a network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-connected-count-history
- organizationId (string): Organization ID
+ - networkId (string): Network ID to query.
+ - serials (array): A list of serials of wireless AP or wired switch devices
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssidNumbers (array): Filter results by SSID number
+ - deviceType (string): Filter connected client counts by device type.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 8 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600. The default is 600. Interval is calculated if time params are provided.
"""
+ kwargs.update(locals())
+
+ if "deviceType" in kwargs:
+ options = ["access_point", "switch"]
+ assert kwargs["deviceType"] in options, (
+ f'''"deviceType" cannot be "{kwargs["deviceType"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "getOrganizationBrandingPolicies",
+ "tags": ["organizations", "monitor", "clients", "connectedCountHistory"],
+ "operation": "getOrganizationAssuranceClientsConnectedCountHistory",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies"
+ resource = f"/organizations/{organizationId}/assurance/clients/connectedCountHistory"
- return self._session.get(metadata, resource)
+ query_params = [
+ "networkId",
+ "serials",
+ "bands",
+ "ssidNumbers",
+ "deviceType",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def createOrganizationBrandingPolicy(self, organizationId: str, name: str, **kwargs):
+ array_params = [
+ "serials",
+ "bands",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsConnectedCountHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceClientsEvents(self, organizationId: str, clientId: str, networkId: str, **kwargs):
"""
- **Add a new branding policy to an organization**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-branding-policy
+ **Given a client, get all alerts and events for a given timespan**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-events
- - organizationId (string): Organization ID
- - name (string): Name of the Dashboard branding policy.
- - enabled (boolean): Boolean indicating whether this policy is enabled.
- - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
- - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
- 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
- the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
- Dashboard; see the documentation for each property to see the allowed values.
- Each property defaults to 'default or inherit' when not provided.
- - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ - organizationId (string): Organization ID
+ - clientId (string): ID of client to query
+ - networkId (string): Network ID where client is connected
+ - filter (array): Optional parameter to filter by issue
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "createOrganizationBrandingPolicy",
+ "tags": ["organizations", "configure", "clients", "events"],
+ "operation": "getOrganizationAssuranceClientsEvents",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies"
+ resource = f"/organizations/{organizationId}/assurance/clients/events"
- body_params = [
- "name",
- "enabled",
- "adminSettings",
- "helpSettings",
- "customLogo",
+ query_params = [
+ "filter",
+ "clientId",
+ "networkId",
+ "t0",
+ "t1",
+ "timespan",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "filter",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"createOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsEvents: ignoring unrecognized kwargs: {invalid}"
+ )
- return self._session.post(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def getOrganizationBrandingPoliciesPriorities(self, organizationId: str):
+ def getOrganizationAssuranceClientsEventsCorrelated(
+ self, organizationId: str, clientId: str, category: str, networkId: str, timestamp: str, **kwargs
+ ):
"""
- **Return the branding policy IDs of an organization in priority order**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies-priorities
+ **Given a client, category, and timespan, return events that have a close connection to each other.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-events-correlated
- organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - category (string): Category of events
+ - networkId (string): Network used by the client
+ - timestamp (string): Timestamp for the event
+ - lookback (integer): Amount of time in minutes to look back
+ - lookforward (integer): Amount of time in minutes to look forwards
"""
+ kwargs.update(locals())
+
+ if "category" in kwargs:
+ options = ["application", "association", "authentication", "dhcp", "dns"]
+ assert kwargs["category"] in options, (
+ f'''"category" cannot be "{kwargs["category"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
- "operation": "getOrganizationBrandingPoliciesPriorities",
+ "tags": ["organizations", "configure", "clients", "events", "correlated"],
+ "operation": "getOrganizationAssuranceClientsEventsCorrelated",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+ resource = f"/organizations/{organizationId}/assurance/clients/events/correlated"
- return self._session.get(metadata, resource)
+ query_params = [
+ "clientId",
+ "category",
+ "networkId",
+ "timestamp",
+ "lookback",
+ "lookforward",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def updateOrganizationBrandingPoliciesPriorities(self, organizationId: str, **kwargs):
- """
- **Update the priority ordering of an organization's branding policies.**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policies-priorities
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsEventsCorrelated: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceClientsTopologyCurrent(self, organizationId: str, clientId: str, networkId: str, **kwargs):
+ """
+ **Given a client, return current topology**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-topology-current
+
+ - organizationId (string): Organization ID
+ - clientId (string): ID of client to query
+ - networkId (string): Network ID where client is connected
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "clients", "topology", "current"],
+ "operation": "getOrganizationAssuranceClientsTopologyCurrent",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/clients/topology/current"
+
+ query_params = [
+ "clientId",
+ "networkId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsTopologyCurrent: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceClientsTopologyNew(self, organizationId: str, clientIds: list, networkId: str, **kwargs):
+ """
+ **Given a client, return current topology**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-topology-new
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of IDs for client retrieval for a given network. Limited to 1 client for now
+ - networkId (string): Network ID where client is connected
+ - timestamp (string): Timestamp for client topology path
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "clients", "topology", "new"],
+ "operation": "getOrganizationAssuranceClientsTopologyNew",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/clients/topology/new"
+
+ query_params = [
+ "clientIds",
+ "networkId",
+ "timestamp",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clientIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsTopologyNew: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceDevicesStatusesOverview(self, organizationId: str, **kwargs):
+ """
+ **Returns counts of online, offline, and recovered devices by product type, along with offline intervals for impacted devices in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-devices-statuses-overview
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "statuses", "overview"],
+ "operation": "getOrganizationAssuranceDevicesStatusesOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/devices/statuses/overview"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceDevicesStatusesOverview: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceFetchTableQuery(self, organizationId: str, tableName: str, **kwargs):
+ """
+ **Returns the table data for a given timespan**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-fetch-table-query
+
+ - organizationId (string): Organization ID
+ - tableName (string): The table from which we want to get data
+ - t0 (string): The beginning of the timespan for the data.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 365 days, 5 hours, 49 minutes, and 12 seconds. The default is 30 days, 10 hours, 29 minutes, and 6 seconds.
+ - userEmail (string): The user email for whom we want to calculate lookback
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "fetchTableQuery"],
+ "operation": "getOrganizationAssuranceFetchTableQuery",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/fetchTableQuery"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "tableName",
+ "userEmail",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceFetchTableQuery: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServer(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServer"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServer"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServerByInterval(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server and by interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server-by-interval
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServer", "byInterval"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServerByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServer/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServerByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServerType(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server-type
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServerType"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServerType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServerType"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServerType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServerTypeByInterval(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server type and by interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server-type-by-interval
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServerType", "byInterval"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServerTypeByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServerType/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServerTypeByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def checkupOrganizationAssuranceOptimization(self, organizationId: str, **kwargs):
+ """
+ **Returns an array of checkup results for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!checkup-organization-assurance-optimization
+
+ - organizationId (string): Organization ID
+ - forceRefresh (boolean): Optional parameter to reassess best practices
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "optimization"],
+ "operation": "checkupOrganizationAssuranceOptimization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/optimization/checkup"
+
+ query_params = [
+ "forceRefresh",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"checkupOrganizationAssuranceOptimization: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceOptimizationCheckupByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns an array of checkup results for the networks**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-optimization-checkup-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 7.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter checkups by Network Id
+ - forceRefresh (boolean): Optional parameter to reassess best practices
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "optimization", "checkup", "byNetwork"],
+ "operation": "getOrganizationAssuranceOptimizationCheckupByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/optimization/checkup/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "forceRefresh",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceOptimizationCheckupByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceProductAnnouncements(self, organizationId: str, **kwargs):
+ """
+ **Gets relevant product announcements for a user**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-product-announcements
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 365 days, 5 hours, 49 minutes, and 12 seconds. The default is 91 days, 7 hours, 27 minutes, and 18 seconds.
+ - onlyRelevant (boolean): Limits product announcements that are considered relevant to this user when true
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "productAnnouncements"],
+ "operation": "getOrganizationAssuranceProductAnnouncements",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/productAnnouncements"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "onlyRelevant",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceProductAnnouncements: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceScores(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get network health scores for a list of networks.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-scores
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 2 hours and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "scores"],
+ "operation": "getOrganizationAssuranceScores",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/scores"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAssuranceScores: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceThousandEyesApplications(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Get a list of Thousand Eyes applications with their alerts.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-thousand-eyes-applications
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - clientId (string): Filter results by client.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "thousandEyes", "applications"],
+ "operation": "getOrganizationAssuranceThousandEyesApplications",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/thousandEyes/applications"
+
+ query_params = [
+ "networkIds",
+ "clientId",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceThousandEyesApplications: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wired connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarizes wired connection successes and failures by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientOs(self, organizationId: str, **kwargs):
+ """
+ **Summarizes wired connection successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wired connection successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": [
+ "organizations",
+ "configure",
+ "wired",
+ "experience",
+ "successfulConnections",
+ "byNetwork",
+ "byClientType",
+ ],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wired connection successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByInterval(self, organizationId: str, **kwargs):
+ """
+ **Time-series of wired connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "wired", "experience", "successfulConnections", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByServer(self, organizationId: str, **kwargs):
+ """
+ **Summarizes wired connection successes and failures by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-server
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byServer"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byServer"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWorkflows(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return workflows filtered by organization ID, network ID, type, and category**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-workflows
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
+ - networkIds (array): Optional parameter to filter by network ID
+ - types (array): Optional parameter to filter workflows by types
+ - categories (array): Optional parameter to filter workflows by categories
+ - scopeTypes (array): Optional parameter to filter workflows by scope types
+ - networkTags (array): Optional parameter to filter workflows by network tags
+ - clientTags (array): Optional parameter to filter workflows by client tags
+ - nodeTags (array): Optional parameter to filter workflows by node tags
+ - state (string): Optional parameter to filter workflows by state
+ - tsStart (string): Start time to filter workflows
+ - tsEnd (string): End time to filter workflows
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "workflows"],
+ "operation": "getOrganizationAssuranceWorkflows",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/workflows"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ "networkIds",
+ "types",
+ "categories",
+ "scopeTypes",
+ "networkTags",
+ "clientTags",
+ "nodeTags",
+ "state",
+ "tsStart",
+ "tsEnd",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "types",
+ "categories",
+ "scopeTypes",
+ "networkTags",
+ "clientTags",
+ "nodeTags",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAssuranceWorkflows: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAuthRadiusServers(self, organizationId: str):
+ """
+ **List the organization-wide RADIUS servers in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-auth-radius-servers
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "getOrganizationAuthRadiusServers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationAuthRadiusServer(self, organizationId: str, address: str, secret: str, **kwargs):
+ """
+ **Add an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - address (string): The IP address or FQDN of the RADIUS server
+ - secret (string): Shared secret of the RADIUS server
+ - name (string): The name of the RADIUS server
+ - modes (array): Available server modes
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "createOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers"
+
+ body_params = [
+ "name",
+ "address",
+ "modes",
+ "secret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationAuthRadiusServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAuthRadiusServersAssignments(self, organizationId: str):
+ """
+ **Return list of network and policies that organization-wide RADIUS servers are bing used**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-auth-radius-servers-assignments
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers", "assignments"],
+ "operation": "getOrganizationAuthRadiusServersAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/assignments"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationAuthRadiusServer(self, organizationId: str, serverId: str):
+ """
+ **Return an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "getOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationAuthRadiusServer(self, organizationId: str, serverId: str, **kwargs):
+ """
+ **Update an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ - name (string): The name of the RADIUS server
+ - address (string): The IP address or FQDN of the RADIUS server
+ - modes (array): Available server modes
+ - secret (string): Shared secret of the RADIUS server
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "updateOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ body_params = [
+ "name",
+ "address",
+ "modes",
+ "secret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationAuthRadiusServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationAuthRadiusServer(self, organizationId: str, serverId: str):
+ """
+ **Delete an organization-wide RADIUS server from a organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "deleteOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ return self._session.delete(metadata, resource)
+
+ def codeOrganizationAutomateIdentity(self, organizationId: str):
+ """
+ **Generate a single use short lived code that can be used to retrieve the identity of the current user in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!code-organization-automate-identity
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "automate", "identity"],
+ "operation": "codeOrganizationAutomateIdentity",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/automate/identity/code"
+
+ return self._session.post(metadata, resource)
+
+ def getOrganizationBrandingPolicies(self, organizationId: str):
+ """
+ **List the branding policies of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "getOrganizationBrandingPolicies",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationBrandingPolicy(self, organizationId: str, name: str, **kwargs):
+ """
+ **Add a new branding policy to an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the Dashboard branding policy.
+ - enabled (boolean): Boolean indicating whether this policy is enabled.
+ - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
+ - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
+ 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
+ the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
+ Dashboard; see the documentation for each property to see the allowed values.
+ Each property defaults to 'default or inherit' when not provided.
+ - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "createOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies"
+
+ body_params = [
+ "name",
+ "enabled",
+ "adminSettings",
+ "helpSettings",
+ "customLogo",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationBrandingPoliciesPriorities(self, organizationId: str):
+ """
+ **Return the branding policy IDs of an organization in priority order**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies-priorities
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
+ "operation": "getOrganizationBrandingPoliciesPriorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationBrandingPoliciesPriorities(self, organizationId: str, **kwargs):
+ """
+ **Update the priority ordering of an organization's branding policies.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policies-priorities
+
+ - organizationId (string): Organization ID
+ - brandingPolicyIds (array): An ordered list of branding policy IDs that determines the priority order of how to apply the policies
+
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
+ "operation": "updateOrganizationBrandingPoliciesPriorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+
+ body_params = [
+ "brandingPolicyIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationBrandingPoliciesPriorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ """
+ **Return a branding policy**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - brandingPolicyId (string): Branding policy ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "getOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str, name: str, **kwargs):
+ """
+ **Update a branding policy**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - brandingPolicyId (string): Branding policy ID
+ - name (string): Name of the Dashboard branding policy.
+ - enabled (boolean): Boolean indicating whether this policy is enabled.
+ - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
+ - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
+ 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
+ the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
+ Dashboard; see the documentation for each property to see the allowed values.
+
+ - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "updateOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+
+ body_params = [
+ "name",
+ "enabled",
+ "adminSettings",
+ "helpSettings",
+ "customLogo",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ """
+ **Delete a branding policy**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - brandingPolicyId (string): Branding policy ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "deleteOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationCertificates(self, organizationId: str, **kwargs):
+ """
+ **Gets all or specific certificates for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates
+
+ - organizationId (string): Organization ID
+ - certificateIds (array): List of ids for specific certificate retrieval
+ - certManagedBy (array): List of cert managed by types
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "getOrganizationCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates"
+
+ query_params = [
+ "certificateIds",
+ "certManagedBy",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateIds",
+ "certManagedBy",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationCertificatesAuthorities(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List certificate authorities for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - authorityIds (array): Feature certificate authority IDs to filter by (exact match on each id; duplicates are ignored)
+ - sortBy (string): Field to sort by (default: authorityId)
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["authorityId", "featureType", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "getOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ query_params = [
+ "authorityIds",
+ "sortBy",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "authorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationCertificatesAuthority(self, organizationId: str, featureType: str, **kwargs):
+ """
+ **Create a certificate authority for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-certificates-authority
+
+ - organizationId (string): Organization ID
+ - featureType (string): Feature this CA serves (e.g., radsec, openroaming, zigbee)
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "createOrganizationCertificatesAuthority",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ body_params = [
+ "featureType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationCertificatesAuthority: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, **kwargs):
+ """
+ **Trust a newly created certificate authority (transition from untrusted to trusted).**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the certificate authority to trust. The CA must currently be untrusted.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "updateOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ body_params = [
+ "authorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, name: str):
+ """
+ **Delete a certificate authority**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the certificate authority to delete
+ - name (string): Certificate authority name
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "deleteOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationCertificatesAuthoritiesJob(self, organizationId: str, jobId: str):
+ """
+ **Return the status and result of a certificate authority job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-authorities-job
+
+ - organizationId (string): Organization ID
+ - jobId (string): Job ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities", "jobs"],
+ "operation": "getOrganizationCertificatesAuthoritiesJob",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ jobId = urllib.parse.quote(str(jobId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities/jobs/{jobId}"
+
+ return self._session.get(metadata, resource)
+
+ def revokeOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, **kwargs):
+ """
+ **Revoke a trusted feature certificate authority.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the feature certificate authority to revoke
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "revokeOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities/revoke"
+
+ body_params = [
+ "authorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"revokeOrganizationCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def importOrganizationCertificates(self, organizationId: str, managedBy: str, contents: str, description: str, **kwargs):
+ """
+ **Import certificate for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!import-organization-certificates
+
+ - organizationId (string): Organization ID
+ - managedBy (string): Certificate managed by type [system_manager, mr, encrypted_syslog, grpc_dial_out]
+ - contents (string): Certificate content in valid PEM format
+ - description (string): Certificate description
+ """
+
+ kwargs = locals()
+
+ if "managedBy" in kwargs:
+ options = ["encrypted_syslog", "grpc_dial_out", "mr", "system_manager"]
+ assert kwargs["managedBy"] in options, (
+ f'''"managedBy" cannot be "{kwargs["managedBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "importOrganizationCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/import"
+
+ body_params = [
+ "managedBy",
+ "contents",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"importOrganizationCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationCertificatesMerakiAuthContents(self, organizationId: str):
+ """
+ **Download the public RADIUS certificate.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-meraki-auth-contents
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "monitor", "certificates", "merakiAuth", "contents"],
+ "operation": "getOrganizationCertificatesMerakiAuthContents",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/merakiAuth/contents"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationCertificatesRevocationLists(self, organizationId: str, **kwargs):
+ """
+ **Return full certificate revocation lists (CRLs) for the organization's certificate authorities**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-revocation-lists
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Optional filter: feature certificate authority IDs (base-10 integers). Every value must exist for this organization; otherwise the request fails. Omit to return CRLs for all feature CAs in the organization.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "revocationLists"],
+ "operation": "getOrganizationCertificatesRevocationLists",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/revocationLists"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCertificatesRevocationLists: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def deleteOrganizationCertificate(self, organizationId: str, certificateId: str):
+ """
+ **Delete a certificate for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-certificate
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "deleteOrganizationCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/{certificateId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationCertificate(self, organizationId: str, certificateId: str, **kwargs):
+ """
+ **Update a certificate's description for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-certificate
- organizationId (string): Organization ID
- - brandingPolicyIds (array): An ordered list of branding policy IDs that determines the priority order of how to apply the policies
+ - certificateId (string): Certificate ID
+ - description (string): Description of a certificate that already exist in your org
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "updateOrganizationCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/{certificateId}"
+
+ body_params = [
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationCertificate: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+ def getOrganizationCertificateContents(self, organizationId: str, certificateId: str, **kwargs):
+ """
+ **Download the trusted certificate by certificate id.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificate-contents
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ - chainId (string): chainId that represent which certificate chain is being requested
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
- "operation": "updateOrganizationBrandingPoliciesPriorities",
+ "tags": ["organizations", "configure", "certificates", "contents"],
+ "operation": "getOrganizationCertificateContents",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/{certificateId}/contents"
+
+ query_params = [
+ "chainId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationCertificateContents: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def claimIntoOrganization(self, organizationId: str, **kwargs):
+ """
+ **Claim a list of devices, licenses, and/or orders into an organization inventory**
+ https://developer.cisco.com/meraki/api-v1/#!claim-into-organization
+
+ - organizationId (string): Organization ID
+ - orders (array): The numbers of the orders that should be claimed
+ - serials (array): The serials of the devices that should be claimed
+ - licenses (array): The licenses that should be claimed
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure"],
+ "operation": "claimIntoOrganization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/claim"
body_params = [
- "brandingPolicyIds",
+ "orders",
+ "serials",
+ "licenses",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
if self._session._validate_kwargs:
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"claimIntoOrganization: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationClientsBandwidthUsageHistory(self, organizationId: str, **kwargs):
+ """
+ **Return data usage (in megabits per second) over time for all clients in the given organization within a given time range.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-bandwidth-usage-history
+
+ - organizationId (string): Organization ID
+ - networkTag (string): Match result to an exact network tag
+ - deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
+ - ssidName (string): Filter results by ssid name
+ - usageUplink (string): Filter results by usage uplink
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 186 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "clients", "bandwidthUsageHistory"],
+ "operation": "getOrganizationClientsBandwidthUsageHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/clients/bandwidthUsageHistory"
+
+ query_params = [
+ "networkTag",
+ "deviceTag",
+ "networkId",
+ "ssidName",
+ "usageUplink",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationBrandingPoliciesPriorities: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationClientsBandwidthUsageHistory: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def getOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ def getOrganizationClientsOverview(self, organizationId: str, **kwargs):
"""
- **Return a branding policy**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policy
+ **Return summary information around client data usage (in kb) across the given organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-overview
- organizationId (string): Organization ID
- - brandingPolicyId (string): Branding policy ID
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
"""
+ kwargs.update(locals())
+
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "getOrganizationBrandingPolicy",
+ "tags": ["organizations", "monitor", "clients", "overview"],
+ "operation": "getOrganizationClientsOverview",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+ resource = f"/organizations/{organizationId}/clients/overview"
- return self._session.get(metadata, resource)
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str, name: str, **kwargs):
- """
- **Update a branding policy**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policy
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationClientsOverview: ignoring unrecognized kwargs: {invalid}")
- - organizationId (string): Organization ID
- - brandingPolicyId (string): Branding policy ID
- - name (string): Name of the Dashboard branding policy.
- - enabled (boolean): Boolean indicating whether this policy is enabled.
- - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
- - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
- 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
- the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
- Dashboard; see the documentation for each property to see the allowed values.
+ return self._session.get(metadata, resource, params)
- - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ def getOrganizationClientsSearch(self, organizationId: str, mac: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return the client details in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-search
+
+ - organizationId (string): Organization ID
+ - mac (string): The MAC address of the client. Required.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5. Default is 5.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "updateOrganizationBrandingPolicy",
+ "tags": ["organizations", "configure", "clients", "search"],
+ "operation": "getOrganizationClientsSearch",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+ resource = f"/organizations/{organizationId}/clients/search"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "mac",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationClientsSearch: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def cloneOrganization(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a new organization by cloning the addressed organization**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the new organization
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure"],
+ "operation": "cloneOrganization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/clone"
body_params = [
"name",
- "enabled",
- "adminSettings",
- "helpSettings",
- "customLogo",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2079,53 +4598,109 @@ def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"updateOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"cloneOrganization: ignoring unrecognized kwargs: {invalid}")
- return self._session.put(metadata, resource, payload)
+ return self._session.post(metadata, resource, payload)
- def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ def getOrganizationCloudConnectivityRequirements(self, organizationId: str):
"""
- **Delete a branding policy**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-branding-policy
+ **List of source/destination traffic rules**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-cloud-connectivity-requirements
- organizationId (string): Organization ID
- - brandingPolicyId (string): Branding policy ID
"""
- metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "deleteOrganizationBrandingPolicy",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+ metadata = {
+ "tags": ["organizations", "monitor", "cloud", "connectivity", "requirements"],
+ "operation": "getOrganizationCloudConnectivityRequirements",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/cloud/connectivity/requirements"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationComputeApplicationDeployments(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the Application Deployment agent configurations for all hosts under this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-compute-application-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - developerNames (array): Filters deployments by application developer name
+ - applicationNames (array): Filters deployments by application name
+ - enabled (boolean): Filters deployments by their enabled status
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "compute", "application", "deployments"],
+ "operation": "getOrganizationComputeApplicationDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "developerNames",
+ "applicationNames",
+ "enabled",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "developerNames",
+ "applicationNames",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationComputeApplicationDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
- return self._session.delete(metadata, resource)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def claimIntoOrganization(self, organizationId: str, **kwargs):
+ def createOrganizationComputeApplicationDeploymentsBulkCreate(
+ self, organizationId: str, hosts: list, application: dict, enabled: bool, **kwargs
+ ):
"""
- **Claim a list of devices, licenses, and/or orders into an organization inventory**
- https://developer.cisco.com/meraki/api-v1/#!claim-into-organization
+ **Add Application Deployment agents for a list of hosts**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-compute-application-deployments-bulk-create
- organizationId (string): Organization ID
- - orders (array): The numbers of the orders that should be claimed
- - serials (array): The serials of the devices that should be claimed
- - licenses (array): The licenses that should be claimed
+ - hosts (array): List of hosts to deploy applications on
+ - application (object): Application information
+ - enabled (boolean): Whether the deployment should be enabled
+ - applicationConfiguration (object): Optional: Generic object for application-specific configuration
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure"],
- "operation": "claimIntoOrganization",
+ "tags": ["organizations", "configure", "compute", "application", "deployments", "bulkCreate"],
+ "operation": "createOrganizationComputeApplicationDeploymentsBulkCreate",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/claim"
+ resource = f"/organizations/{organizationId}/compute/application/deployments/bulkCreate"
body_params = [
- "orders",
- "serials",
- "licenses",
+ "hosts",
+ "application",
+ "enabled",
+ "applicationConfiguration",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2133,159 +4708,118 @@ def claimIntoOrganization(self, organizationId: str, **kwargs):
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"claimIntoOrganization: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"createOrganizationComputeApplicationDeploymentsBulkCreate: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.post(metadata, resource, payload)
- def getOrganizationClientsBandwidthUsageHistory(self, organizationId: str, **kwargs):
+ def updateOrganizationComputeApplicationDeployment(self, organizationId: str, deploymentId: str, enabled: bool, **kwargs):
"""
- **Return data usage (in megabits per second) over time for all clients in the given organization within a given time range.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-bandwidth-usage-history
+ **Update a Deployment agent configuration**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-compute-application-deployment
- organizationId (string): Organization ID
- - networkTag (string): Match result to an exact network tag
- - deviceTag (string): Match result to an exact device tag
- - ssidName (string): Filter results by ssid name
- - usageUplink (string): Filter results by usage uplink
- - t0 (string): The beginning of the timespan for the data.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 186 days. The default is 1 day.
+ - deploymentId (string): Deployment ID
+ - enabled (boolean): Whether or not the Application Deployment agent is enabled for the host.
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
- "tags": ["organizations", "monitor", "clients", "bandwidthUsageHistory"],
- "operation": "getOrganizationClientsBandwidthUsageHistory",
+ "tags": ["organizations", "configure", "compute", "application", "deployments"],
+ "operation": "updateOrganizationComputeApplicationDeployment",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clients/bandwidthUsageHistory"
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/{deploymentId}"
- query_params = [
- "networkTag",
- "deviceTag",
- "ssidName",
- "usageUplink",
- "t0",
- "t1",
- "timespan",
+ body_params = [
+ "enabled",
]
- params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
if self._session._validate_kwargs:
- all_params = query_params
+ all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationClientsBandwidthUsageHistory: ignoring unrecognized kwargs: {invalid}"
+ f"updateOrganizationComputeApplicationDeployment: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get(metadata, resource, params)
+ return self._session.put(metadata, resource, payload)
- def getOrganizationClientsOverview(self, organizationId: str, **kwargs):
+ def deleteOrganizationComputeApplicationDeployment(self, organizationId: str, deploymentId: str):
"""
- **Return summary information around client data usage (in kb) across the given organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-overview
+ **Delete a Application Deployment agent from the host**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-compute-application-deployment
- organizationId (string): Organization ID
- - t0 (string): The beginning of the timespan for the data.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - deploymentId (string): Deployment ID
"""
- kwargs.update(locals())
-
metadata = {
- "tags": ["organizations", "monitor", "clients", "overview"],
- "operation": "getOrganizationClientsOverview",
+ "tags": ["organizations", "configure", "compute", "application", "deployments"],
+ "operation": "deleteOrganizationComputeApplicationDeployment",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clients/overview"
-
- query_params = [
- "t0",
- "t1",
- "timespan",
- ]
- params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/{deploymentId}"
- if self._session._validate_kwargs:
- all_params = query_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationClientsOverview: ignoring unrecognized kwargs: {invalid}")
-
- return self._session.get(metadata, resource, params)
+ return self._session.delete(metadata, resource)
- def getOrganizationClientsSearch(self, organizationId: str, mac: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationComputeHosts(
+ self, organizationId: str, developerName: str, applicationName: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Return the client details in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-search
+ **Retrieves a list of compute hosts eligible for application deployment within a given organization, filtered by the specified application developer and application name, with optional network ID filtering.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-compute-hosts
- organizationId (string): Organization ID
- - mac (string): The MAC address of the client. Required.
+ - developerName (string): Filters hosts by application developer name
+ - applicationName (string): Filters hosts by application name
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5. Default is 5.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Filters hosts by the network ID they belong to
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "clients", "search"],
- "operation": "getOrganizationClientsSearch",
+ "tags": ["organizations", "configure", "compute", "hosts"],
+ "operation": "getOrganizationComputeHosts",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clients/search"
+ resource = f"/organizations/{organizationId}/compute/hosts"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
- "mac",
+ "developerName",
+ "applicationName",
+ "networkIds",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- if self._session._validate_kwargs:
- all_params = query_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationClientsSearch: ignoring unrecognized kwargs: {invalid}")
-
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
-
- def cloneOrganization(self, organizationId: str, name: str, **kwargs):
- """
- **Create a new organization by cloning the addressed organization**
- https://developer.cisco.com/meraki/api-v1/#!clone-organization
-
- - organizationId (string): Organization ID
- - name (string): The name of the new organization
- """
-
- kwargs = locals()
-
- metadata = {
- "tags": ["organizations", "configure"],
- "operation": "cloneOrganization",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clone"
-
- body_params = [
- "name",
+ array_params = [
+ "networkIds",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"cloneOrganization: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"getOrganizationComputeHosts: ignoring unrecognized kwargs: {invalid}")
- return self._session.post(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
def getOrganizationConfigTemplates(self, organizationId: str):
"""
@@ -2632,36 +5166,176 @@ def getOrganizationDevicesAvailabilitiesChangeHistory(
- productTypes (array): Optional parameter to filter device availabilities history by device product types
- networkIds (array): Optional parameter to filter device availabilities history by network IDs
- statuses (array): Optional parameter to filter device availabilities history by device statuses
+ - categories (array): Optional parameter to filter device availabilities history by categories of status, reboot, or upgrade
+ - networkTags (array): Optional parameter to filter device availabilities history by network tags. The filtering is case-sensitive. If tags are included, 'networkTagsFilterType' should also be included (see below).
+ - networkTagsFilterType (string): An optional parameter of value 'withAnyTags' or 'withAllTags' to indicate whether to return networks which contain ANY or ALL of the included tags. If no type is included, 'withAnyTags' will be selected.
+ - deviceTags (array): Optional parameter to filter device availabilities history by device tags. The filtering is case-sensitive. If tags are included, 'deviceTagsFilterType' should also be included (see below).
+ - deviceTagsFilterType (string): An optional parameter of value 'withAnyTags' or 'withAllTags' to indicate whether to return devices which contain ANY or ALL of the included tags. If no type is included, 'withAnyTags' will be selected.
+ """
+
+ kwargs.update(locals())
+
+ if "networkTagsFilterType" in kwargs:
+ options = ["withAllTags", "withAnyTags"]
+ assert kwargs["networkTagsFilterType"] in options, (
+ f'''"networkTagsFilterType" cannot be "{kwargs["networkTagsFilterType"]}", & must be set to one of: {options}'''
+ )
+ if "deviceTagsFilterType" in kwargs:
+ options = ["withAllTags", "withAnyTags"]
+ assert kwargs["deviceTagsFilterType"] in options, (
+ f'''"deviceTagsFilterType" cannot be "{kwargs["deviceTagsFilterType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "availabilities", "changeHistory"],
+ "operation": "getOrganizationDevicesAvailabilitiesChangeHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/availabilities/changeHistory"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "serials",
+ "productTypes",
+ "networkIds",
+ "statuses",
+ "categories",
+ "networkTags",
+ "networkTagsFilterType",
+ "deviceTags",
+ "deviceTagsFilterType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ "productTypes",
+ "networkIds",
+ "statuses",
+ "categories",
+ "networkTags",
+ "deviceTags",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesAvailabilitiesChangeHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesBootsHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns the history of device boots in reverse chronological order (most recent first)**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-boots-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 730 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 730 days.
+ - serials (array): Optional parameter to filter device by device serial numbers. This filter uses multiple exact matches.
+ - productTypes (array): Optional parameter to filter devices by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
+ - mostRecentPerDevice (boolean): If true, only the most recent boot for each device is returned.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'descending'.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "boots", "history"],
+ "operation": "getOrganizationDevicesBootsHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/boots/history"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "serials",
+ "productTypes",
+ "mostRecentPerDevice",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationDevicesBootsHistory: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesBootsOverviewByDevice(self, organizationId: str, **kwargs):
+ """
+ **Summarizes device reboots across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-boots-overview-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - productTypes (array): An optional parameter to filter device statuses by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "monitor", "devices", "availabilities", "changeHistory"],
- "operation": "getOrganizationDevicesAvailabilitiesChangeHistory",
+ "tags": ["organizations", "monitor", "devices", "boots", "overview", "byDevice"],
+ "operation": "getOrganizationDevicesBootsOverviewByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/devices/availabilities/changeHistory"
+ resource = f"/organizations/{organizationId}/devices/boots/overview/byDevice"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
+ "networkIds",
+ "productTypes",
"t0",
"t1",
"timespan",
- "serials",
- "productTypes",
- "networkIds",
- "statuses",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "serials",
- "productTypes",
"networkIds",
- "statuses",
+ "productTypes",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -2673,10 +5347,10 @@ def getOrganizationDevicesAvailabilitiesChangeHistory(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationDevicesAvailabilitiesChangeHistory: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationDevicesBootsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
def getOrganizationDevicesCellularDataDevices(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
@@ -3276,6 +5950,64 @@ def getOrganizationDevicesCellularUplinksTowersByDevice(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationDevicesCertificates(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List device certificates for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-certificates
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - serials (array): Device serial numbers to filter by (exact match; duplicates are ignored)
+ - featureTypes (array): Feature types these device certificates serve (exact match; e.g., radsec, openroaming, zigbee)
+ - sortBy (string): Field to sort by (default: authorityId)
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["authorityId", "featureType", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "certificates"],
+ "operation": "getOrganizationDevicesCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/certificates"
+
+ query_params = [
+ "serials",
+ "featureTypes",
+ "sortBy",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ "featureTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationDevicesCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def createOrganizationDevicesControllerMigration(self, organizationId: str, serials: list, target: str, **kwargs):
"""
**Migrate devices to another controller or management mode**
@@ -3410,6 +6142,56 @@ def bulkUpdateOrganizationDevicesDetails(self, organizationId: str, serials: lis
return self._session.post(metadata, resource, payload)
+ def getOrganizationDevicesMemoryByDevice(self, organizationId: str, networkIds: list, productTypes: list, **kwargs):
+ """
+ **Summarizes memory status across devices of a given network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-memory-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - productTypes (array): Parameter to filter device availabilities by device product types. This filter uses multiple exact matches.
+ - usageThreshold (number): Threshold of device memory utilization expressed as a percent. Filters out all devices below this value.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "memory", "byDevice"],
+ "operation": "getOrganizationDevicesMemoryByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/memory/byDevice"
+
+ query_params = [
+ "networkIds",
+ "productTypes",
+ "usageThreshold",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationDevicesMemoryByDevice: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
def getOrganizationDevicesOverviewByModel(self, organizationId: str, **kwargs):
"""
**Lists the count for each device model**
@@ -3744,6 +6526,65 @@ def stopOrganizationDevicesPacketCaptureCapture(self, organizationId: str, captu
return self._session.post(metadata, resource, payload)
+ def getOrganizationDevicesPacketCaptureOpportunisticByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the Opportunistic Pcap settings of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-packet-capture-opportunistic-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter results by network.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'descending'.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCapture", "opportunistic", "byNetwork"],
+ "operation": "getOrganizationDevicesPacketCaptureOpportunisticByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/opportunistic/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesPacketCaptureOpportunisticByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationDevicesPacketCaptureSchedules(self, organizationId: str, **kwargs):
"""
**List the Packet Capture Schedules**
@@ -3836,6 +6677,39 @@ def createOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, de
return self._session.post(metadata, resource, payload)
+ def bulkOrganizationDevicesPacketCaptureSchedulesDelete(self, organizationId: str, scheduleIds: list, **kwargs):
+ """
+ **Delete packet capture schedules**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-devices-packet-capture-schedules-delete
+
+ - organizationId (string): Organization ID
+ - scheduleIds (array): Delete the packet capture schedules of the specified schedule ids
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCapture", "schedules"],
+ "operation": "bulkOrganizationDevicesPacketCaptureSchedulesDelete",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/bulkDelete"
+
+ body_params = [
+ "scheduleIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"bulkOrganizationDevicesPacketCaptureSchedulesDelete: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def reorderOrganizationDevicesPacketCaptureSchedules(self, organizationId: str, order: list, **kwargs):
"""
**Bulk update priorities of pcap schedules**
@@ -3911,31 +6785,144 @@ def updateOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, sc
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationDevicesPacketCaptureSchedule: ignoring unrecognized kwargs: {invalid}"
+ f"updateOrganizationDevicesPacketCaptureSchedule: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, scheduleId: str):
+ """
+ **Delete schedule from cloud**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-devices-packet-capture-schedule
+
+ - organizationId (string): Organization ID
+ - scheduleId (string): Delete the capture schedules of the specified capture schedule id
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCapture", "schedules"],
+ "operation": "deleteOrganizationDevicesPacketCaptureSchedule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ scheduleId = urllib.parse.quote(str(scheduleId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
+
+ return self._session.delete(metadata, resource)
+
+ def tasksOrganizationDevicesPacketCapture(self, organizationId: str, packetId: str, task: str, **kwargs):
+ """
+ **Enqueues a task for a specific packet capture**
+ https://developer.cisco.com/meraki/api-v1/#!tasks-organization-devices-packet-capture
+
+ - organizationId (string): Organization ID
+ - packetId (string): Packet ID
+ - task (string): Type of task to enqueue. It can be one of: ["analysis", "reasoning", "summary", "highlights", "title", "flow"]
+ - networkId (string): Parameter to validate authorization by network access
+ """
+
+ kwargs.update(locals())
+
+ if "task" in kwargs:
+ options = ["analysis", "flow", "highlights", "reasoning", "summary", "title"]
+ assert kwargs["task"] in options, f'''"task" cannot be "{kwargs["task"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCaptures"],
+ "operation": "tasksOrganizationDevicesPacketCapture",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ packetId = urllib.parse.quote(str(packetId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCaptures/{packetId}/tasks"
+
+ body_params = [
+ "networkId",
+ "task",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"tasksOrganizationDevicesPacketCapture: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationDevicesPacketCaptureTask(self, organizationId: str, packetId: str, id: str, **kwargs):
+ """
+ **Retrieves packet capture analysis result for a specific packet capture task.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-packet-capture-task
+
+ - organizationId (string): Organization ID
+ - packetId (string): Packet ID
+ - id (string): ID
+ - networkId (string): Optional parameter to validate authorization by network access
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCaptures", "tasks"],
+ "operation": "getOrganizationDevicesPacketCaptureTask",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ packetId = urllib.parse.quote(str(packetId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCaptures/{packetId}/tasks/{id}"
+
+ query_params = [
+ "networkId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesPacketCaptureTask: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def deleteOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, scheduleId: str):
+ def bulkOrganizationDevicesPlacementPositionsUpdate(self, organizationId: str, serials: list, **kwargs):
"""
- **Delete schedule from cloud**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-devices-packet-capture-schedule
+ **Bulk update the attributes related to positions for provided devices**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-devices-placement-positions-update
- organizationId (string): Organization ID
- - scheduleId (string): Delete the capture schedules of the specified capture schedule id
+ - serials (array): List of device serials on a floor plan to update
+ - height (object): Height of the devices on the floor plan
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "devices", "packetCapture", "schedules"],
- "operation": "deleteOrganizationDevicesPacketCaptureSchedule",
+ "tags": ["organizations", "configure", "devices", "placement", "positions"],
+ "operation": "bulkOrganizationDevicesPlacementPositionsUpdate",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- scheduleId = urllib.parse.quote(str(scheduleId), safe="")
- resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
+ resource = f"/organizations/{organizationId}/devices/placement/positions/bulkUpdate"
- return self._session.delete(metadata, resource)
+ body_params = [
+ "serials",
+ "height",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"bulkOrganizationDevicesPlacementPositionsUpdate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
def getOrganizationDevicesPowerModulesStatusesByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
@@ -4078,6 +7065,216 @@ def getOrganizationDevicesProvisioningStatuses(self, organizationId: str, total_
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationDevicesSoftwareUpdatesOverviewsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns details about software updates for networks within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-software-updates-overviews-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
+ - sortKey (string): Specify key to order the list of networks.
+ - configSource (string): Limit the list of networks to those that contain devices with the specified config source
+ - networkIds (array): Limit the list of networks to those that match the provided network IDs
+ - networkGroupIds (array): Limit the list of networks to those that belong to one of the provided network group IDs.
+ - productTypes (array): Limit the list of product types included for each network
+ - networkName (string): Limit the list of networks to those whose name contains the given search string.
+ - versionIds (array): Limit the list of networks to those that are currently on one of the provided version IDs.
+ - firmwareStatus (string): Limit the list of networks to those whose current firmware version has the specified end-of-support status.
+ - firmwareType (string): Limit the list of networks to those whose current firmware version has the specified release type.
+ - upgradeDependencyIds (array): Limit the list of networks to those that belong to one of the provided upgrade dependencies.
+ - upgradeAvailable (boolean): Limit the list of networks by upgrade availability.
+ - templateRole (string): Limit the list of networks by config template role: non-template only, templates only, or templates and bound networks.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = [
+ "availability",
+ "currentVersion",
+ "firmwareStatus",
+ "firmwareType",
+ "lastUpgrade",
+ "networkGroup",
+ "networkName",
+ "networkType",
+ "scheduledTime",
+ "scheduledUpgradeVersion",
+ "upgradeDependency",
+ ]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+ if "configSource" in kwargs:
+ options = ["cloud", "local"]
+ assert kwargs["configSource"] in options, (
+ f'''"configSource" cannot be "{kwargs["configSource"]}", & must be set to one of: {options}'''
+ )
+ if "firmwareStatus" in kwargs:
+ options = ["critical", "good", "warning"]
+ assert kwargs["firmwareStatus"] in options, (
+ f'''"firmwareStatus" cannot be "{kwargs["firmwareStatus"]}", & must be set to one of: {options}'''
+ )
+ if "firmwareType" in kwargs:
+ options = ["beta", "candidate", "stable"]
+ assert kwargs["firmwareType"] in options, (
+ f'''"firmwareType" cannot be "{kwargs["firmwareType"]}", & must be set to one of: {options}'''
+ )
+ if "templateRole" in kwargs:
+ options = ["bound-templates", "non-template", "templates"]
+ assert kwargs["templateRole"] in options, (
+ f'''"templateRole" cannot be "{kwargs["templateRole"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "software", "updates", "overviews", "byNetwork"],
+ "operation": "getOrganizationDevicesSoftwareUpdatesOverviewsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/software/updates/overviews/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ "sortKey",
+ "configSource",
+ "networkIds",
+ "networkGroupIds",
+ "productTypes",
+ "networkName",
+ "versionIds",
+ "firmwareStatus",
+ "firmwareType",
+ "upgradeDependencyIds",
+ "upgradeAvailable",
+ "templateRole",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "productTypes",
+ "versionIds",
+ "upgradeDependencyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSoftwareUpdatesOverviewsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesSoftwareVersions(self, organizationId: str, releaseType: str, **kwargs):
+ """
+ **List the available software upgrade versions for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-software-versions
+
+ - organizationId (string): Organization ID
+ - releaseType (string): Filter by release type
+ """
+
+ kwargs = locals()
+
+ if "releaseType" in kwargs:
+ options = ["beta", "generallyAvailable", "recommended"]
+ assert kwargs["releaseType"] in options, (
+ f'''"releaseType" cannot be "{kwargs["releaseType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "software", "versions"],
+ "operation": "getOrganizationDevicesSoftwareVersions",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/software/versions"
+
+ query_params = [
+ "releaseType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSoftwareVersions: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationDevicesSoftwareVersionsChangelogs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provide changelogs for specified versions or, if unspecified, for all versions in the organization, including reference to the last and next versions.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-software-versions-changelogs
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - versionIds (array): Array of version IDs for filtering
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "software", "versions", "changelogs"],
+ "operation": "getOrganizationDevicesSoftwareVersionsChangelogs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/software/versions/changelogs"
+
+ query_params = [
+ "versionIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "versionIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSoftwareVersionsChangelogs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationDevicesStatuses(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List the status of every Meraki device in the organization**
@@ -4096,6 +7293,7 @@ def getOrganizationDevicesStatuses(self, organizationId: str, total_pages=1, dir
- models (array): Optional parameter to filter devices by models.
- tags (array): An optional parameter to filter devices by tags. The filtering is case-sensitive. If tags are included, 'tagsFilterType' should also be included (see below).
- tagsFilterType (string): An optional parameter of value 'withAnyTags' or 'withAllTags' to indicate whether to return devices which contain ANY or ALL of the included tags. If no type is included, 'withAnyTags' will be selected.
+ - configurationUpdatedAfter (string): Optional parameter to filter results by whether or not the device's configuration has been updated after the given timestamp
"""
kwargs.update(locals())
@@ -4124,6 +7322,7 @@ def getOrganizationDevicesStatuses(self, organizationId: str, total_pages=1, dir
"models",
"tags",
"tagsFilterType",
+ "configurationUpdatedAfter",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -4348,11 +7547,141 @@ def getOrganizationDevicesSystemMemoryUsageHistoryByInterval(
params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = query_params + array_params
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSystemMemoryUsageHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesTopologyInterfaces(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List topology interfaces in an organization, including layer 2 and layer 3 metadata when available.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-topology-interfaces
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter interfaces by network ID. This filter uses multiple exact matches. Query array syntax follows the standard bracket form, for example: networkIds[]=L_1234&networkIds[]=L_5678.
+ - serials (array): Optional parameter to filter interfaces by device serial. This filter uses multiple exact matches. Query array syntax follows the standard bracket form, for example: serials[]=Q234-ABCD-5678&serials[]=Q234-ABCD-9012.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "topology", "interfaces"],
+ "operation": "getOrganizationDevicesTopologyInterfaces",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/topology/interfaces"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesTopologyInterfaces: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesTopologyL2Links(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List layer 2 topology links originating from devices in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-topology-l-2-links
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "topology", "l2", "links"],
+ "operation": "getOrganizationDevicesTopologyL2Links",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/topology/l2/links"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesTopologyL2Links: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesTopologyNodesDiscovered(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List topology nodes discovered by LLDP/CDP from devices in an organization, including reported metadata when available.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-topology-nodes-discovered
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "topology", "nodes", "discovered"],
+ "operation": "getOrganizationDevicesTopologyNodesDiscovered",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/topology/nodes/discovered"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationDevicesSystemMemoryUsageHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationDevicesTopologyNodesDiscovered: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
@@ -4612,6 +7941,248 @@ def deleteOrganizationEarlyAccessFeaturesOptIn(self, organizationId: str, optInI
return self._session.delete(metadata, resource)
+ def updateOrganizationExtensionsSdwanmanagerInterconnect(
+ self, organizationId: str, interconnectId: str, name: str, status: str, **kwargs
+ ):
+ """
+ **Update name and status of an Interconnect**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-extensions-sdwanmanager-interconnect
+
+ - organizationId (string): Organization ID
+ - interconnectId (string): Interconnect ID
+ - name (string): Interconnect name
+ - status (string): Interconnect status
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "sdwanmanager", "interconnects"],
+ "operation": "updateOrganizationExtensionsSdwanmanagerInterconnect",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ interconnectId = urllib.parse.quote(str(interconnectId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/sdwanmanager/interconnects/{interconnectId}"
+
+ body_params = [
+ "name",
+ "status",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationExtensionsSdwanmanagerInterconnect: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationExtensionsThousandEyesNetworks(self, organizationId: str):
+ """
+ **List the ThousandEyes agent configurations under this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-extensions-thousand-eyes-networks
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "getOrganizationExtensionsThousandEyesNetworks",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, enabled: bool, networkId: str, **kwargs):
+ """
+ **Add a ThousandEyes agent for this network**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - enabled (boolean): Whether or not the ThousandEyes agent is enabled for the network.
+ - networkId (string): Network that will have the ThousandEyes agent installed on.
+ - tests (array): An array of tests to be created
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "createOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks"
+
+ body_params = [
+ "enabled",
+ "networkId",
+ "tests",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationExtensionsThousandEyesNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationExtensionsThousandEyesNetworksSupported(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all the networks eligible for ThousandEyes agent activation under this organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-extensions-thousand-eyes-networks-supported
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - agentInstalled (boolean): Set to true to get only networks with installed ThousandEyes agent; set to false to get networks without agents.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks", "supported"],
+ "operation": "getOrganizationExtensionsThousandEyesNetworksSupported",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/supported"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "agentInstalled",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationExtensionsThousandEyesNetworksSupported: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str):
+ """
+ **List the ThousandEyes agent configuration under this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "getOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str, enabled: bool, **kwargs):
+ """
+ **Update a ThousandEyes agent from this network**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ - enabled (boolean): Whether or not the ThousandEyes agent is enabled for the network.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "updateOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ body_params = [
+ "enabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationExtensionsThousandEyesNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str):
+ """
+ **Delete a ThousandEyes agent from this network**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "deleteOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationExtensionsThousandEyesTest(self, organizationId: str, **kwargs):
+ """
+ **Create a ThousandEyes test based on a provided test template**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-extensions-thousand-eyes-test
+
+ - organizationId (string): Organization ID
+ - tests (array): An array of tests to be created
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "tests"],
+ "operation": "createOrganizationExtensionsThousandEyesTest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/tests"
+
+ body_params = [
+ "tests",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationExtensionsThousandEyesTest: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getOrganizationFirmwareUpgrades(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Get firmware upgrade information for an organization**
@@ -4807,29 +8378,117 @@ def getOrganizationFloorPlansAutoLocateStatuses(self, organizationId: str, total
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "floorPlanIds",
- ]
- params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
-
- array_params = [
- "networkIds",
- "floorPlanIds",
+ "networkIds",
+ "floorPlanIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "floorPlanIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationFloorPlansAutoLocateStatuses: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAccessGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List effective Catalyst Center access groups for the requested Catalyst Center administrators in the specified organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-access-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of access groups to return per page. Range: 1-50. Defaults to 50 when omitted.
+ - startingAfter (string): Cursor token to retrieve access groups after the specified access group identifier.
+ - endingBefore (string): Cursor token to retrieve access groups before the specified access group identifier.
+ - assignedAdminEmails (array): Catalyst Center administrator email addresses used by federation to filter access groups for the requested administrators.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "iam", "admins", "accessGroups"],
+ "operation": "getOrganizationAccessGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/admins/accessGroups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "assignedAdminEmails",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "assignedAdminEmails",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAccessGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def resolveOrganizationIamAdminsAdministratorsMePermissions(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the authenticated caller admin's permissions for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!resolve-organization-iam-admins-administrators-me-permissions
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "iam", "admins", "administrators", "me", "permissions"],
+ "operation": "resolveOrganizationIamAdminsAdministratorsMePermissions",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/admins/administrators/me/permissions/resolve"
+
+ body_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
- for k, v in kwargs.items():
- if k.strip() in array_params:
- params[f"{k.strip()}[]"] = kwargs[f"{k}"]
- params.pop(k.strip())
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
if self._session._validate_kwargs:
- all_params = query_params + array_params
+ all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationFloorPlansAutoLocateStatuses: ignoring unrecognized kwargs: {invalid}"
+ f"resolveOrganizationIamAdminsAdministratorsMePermissions: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.post(metadata, resource, payload)
def getOrganizationIntegrationsDeployable(self, organizationId: str):
"""
@@ -5100,6 +8759,61 @@ def getOrganizationInventoryDevices(self, organizationId: str, total_pages=1, di
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationInventoryDevicesDetails(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return inventory devices with additional site, geolocation, software, licensing, lifecycle, and Catalyst Center-specific fields**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-inventory-devices-details
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter devices by network IDs. Matches devices in any of the provided network IDs. When multiple filter parameters are provided, a device must match each provided filter. Query array syntax follows the standard bracket form, for example: networkIds[]=L_1234&networkIds[]=L_5678. Maximum 100 network IDs.
+ - serials (array): Optional parameter to filter devices by serials. Matches devices with any of the provided serials. When multiple filter parameters are provided, a device must match each provided filter. Query array syntax follows the standard bracket form, for example: serials[]=Q234-ABCD-5678&serials[]=Q234-ABCD-9012. Maximum 100 serials.
+ - productTypes (array): Optional parameter to filter devices by product type. Matches devices with any of the provided product types. When multiple filter parameters are provided, a device must match each provided filter. Query array syntax follows the standard bracket form, for example: productTypes[]=switch&productTypes[]=wireless. Maximum 100 product types.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "inventory", "devices", "details"],
+ "operation": "getOrganizationInventoryDevicesDetails",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/inventory/devices/details"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "productTypes",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationInventoryDevicesDetails: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationInventoryDevicesEoxOverview(self, organizationId: str):
"""
**Fetch the EOX summary for an organization, including counts of devices that are end-of-sale, end-of-support, and end-of-support-soon.**
@@ -5687,6 +9401,7 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
- timeZone (string): The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
- copyFromNetworkId (string): The ID of the network to copy configuration from. Other provided parameters will override the copied configuration, except type which must match this network's type exactly.
- notes (string): Add any notes or additional information about this network here.
+ - details (array): An array of details
"""
kwargs.update(locals())
@@ -5705,6 +9420,252 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
"timeZone",
"copyFromNetworkId",
"notes",
+ "details",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNetwork: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds: list, **kwargs):
+ """
+ **Combine multiple networks into a single network**
+ https://developer.cisco.com/meraki/api-v1/#!combine-organization-networks
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the combined network
+ - networkIds (array): A list of the network IDs that will be combined. If an ID of a combined network is included in this list, the other networks in the list will be grouped into that network
+ - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break. All networks that are part of this combined network will have their enrollment string appended by '-network_type'. If left empty, all exisitng enrollment strings will be deleted.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks"],
+ "operation": "combineOrganizationNetworks",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/combine"
+
+ body_params = [
+ "name",
+ "networkIds",
+ "enrollmentString",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"combineOrganizationNetworks: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNetworksGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the network groups in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-networks-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - groupIds (array): Optional parameter to filter network groups by ID
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "getOrganizationNetworksGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups"
+
+ query_params = [
+ "groupIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "groupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNetworksGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNetworksGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a network group**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the network group
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "createOrganizationNetworksGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups"
+
+ body_params = [
+ "name",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNetworksGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNetworksGroupsOverviewByGroup(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the client and status overview information for the network groups in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-networks-groups-overview-by-group
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - sortBy (string): Field by which to sort the results
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "monitor", "networks", "groups", "overview", "byGroup"],
+ "operation": "getOrganizationNetworksGroupsOverviewByGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/overview/byGroup"
+
+ query_params = [
+ "sortBy",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNetworksGroupsOverviewByGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationNetworksGroup(self, organizationId: str, groupId: str, name: str, **kwargs):
+ """
+ **Update a network group**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - name (string): The new name of the network group
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "updateOrganizationNetworksGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}"
+
+ body_params = [
+ "name",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNetworksGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationNetworksGroup(self, organizationId: str, groupId: str):
+ """
+ **Delete a network group**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "deleteOrganizationNetworksGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}"
+
+ return self._session.delete(metadata, resource)
+
+ def bulkOrganizationNetworksGroupAssign(self, organizationId: str, groupId: str, networkIds: list, **kwargs):
+ """
+ **Add networks to a network group**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-networks-group-assign
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - networkIds (array): A list of network IDs to add to the network group
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "bulkOrganizationNetworksGroupAssign",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}/bulkAssign"
+
+ body_params = [
+ "networkIds",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -5712,34 +9673,32 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"createOrganizationNetwork: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"bulkOrganizationNetworksGroupAssign: ignoring unrecognized kwargs: {invalid}")
return self._session.post(metadata, resource, payload)
- def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds: list, **kwargs):
+ def bulkOrganizationNetworksGroupUnassign(self, organizationId: str, groupId: str, networkIds: list, **kwargs):
"""
- **Combine multiple networks into a single network**
- https://developer.cisco.com/meraki/api-v1/#!combine-organization-networks
+ **Remove networks from a network group**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-networks-group-unassign
- organizationId (string): Organization ID
- - name (string): The name of the combined network
- - networkIds (array): A list of the network IDs that will be combined. If an ID of a combined network is included in this list, the other networks in the list will be grouped into that network
- - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break. All networks that are part of this combined network will have their enrollment string appended by '-network_type'. If left empty, all exisitng enrollment strings will be deleted.
+ - groupId (string): Group ID
+ - networkIds (array): A list of network IDs to remove from the network group
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
- "tags": ["organizations", "configure", "networks"],
- "operation": "combineOrganizationNetworks",
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "bulkOrganizationNetworksGroupUnassign",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/networks/combine"
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}/bulkUnassign"
body_params = [
- "name",
"networkIds",
- "enrollmentString",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -5747,7 +9706,9 @@ def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"combineOrganizationNetworks: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"bulkOrganizationNetworksGroupUnassign: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.post(metadata, resource, payload)
@@ -5833,6 +9794,25 @@ def getNetworkMoves(self, organizationId: str, total_pages=1, direction="next",
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def deleteOrganizationOpenRoamingCertificate(self, organizationId: str, id: str):
+ """
+ **Delete an open roaming certificate.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-open-roaming-certificate
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "openRoaming", "certificates"],
+ "operation": "deleteOrganizationOpenRoamingCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/openRoaming/certificates/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationOpenapiSpec(self, organizationId: str, **kwargs):
"""
**Return the OpenAPI Specification of the organization's API documentation in JSON**
@@ -5954,6 +9934,7 @@ def getOrganizationPoliciesGlobalFirewallRulesets(self, organizationId: str, tot
- direction (string): direction to paginate, either "next" (default) or "prev" page
- rulesetIds (array): Filter rulesets by IDs
- name (string): Filter rulesets by name (partial match, case-insensitive). If multiple instances are provided, only the last one is used.
+ - excludedPolicyIds (array): Filter out rulesets that are associated with the specified policy IDs
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
@@ -5971,6 +9952,7 @@ def getOrganizationPoliciesGlobalFirewallRulesets(self, organizationId: str, tot
query_params = [
"rulesetIds",
"name",
+ "excludedPolicyIds",
"perPage",
"startingAfter",
"endingBefore",
@@ -5979,6 +9961,7 @@ def getOrganizationPoliciesGlobalFirewallRulesets(self, organizationId: str, tot
array_params = [
"rulesetIds",
+ "excludedPolicyIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -6499,6 +10482,7 @@ def getOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
- rulesetIds (array): Filter assignments by ruleset IDs
- policyIds (array): Filter assignments by policy IDs
- assignmentIds (array): Filter assignments by assignment IDs
+ - staged (boolean): Filter assignments by whether or not they are staged
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
@@ -6517,6 +10501,7 @@ def getOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
"rulesetIds",
"policyIds",
"assignmentIds",
+ "staged",
"perPage",
"startingAfter",
"endingBefore",
@@ -6554,6 +10539,7 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
- rulesetId (string): ID of the ruleset to assign
- policyId (string): ID of the policy to assign the ruleset to
- priority (integer): Priority of the ruleset assignment (lower numbers = higher priority)
+ - staged (boolean): Stage an assignment without applying it immediately to the policy
"""
kwargs.update(locals())
@@ -6569,6 +10555,7 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
"rulesetId",
"policyId",
"priority",
+ "staged",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -6582,6 +10569,41 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
return self._session.post(metadata, resource, payload)
+ def commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
+ self, organizationId: str, policy: dict, **kwargs
+ ):
+ """
+ **Commit staged Organization-Wide Policy Ruleset Assignments**
+ https://developer.cisco.com/meraki/api-v1/#!commit-organization-policies-global-group-policies-firewall-rulesets-assignments
+
+ - organizationId (string): Organization ID
+ - policy (object): Policy in which all staged rulesets will be committed
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "policies", "global", "group", "firewall", "rulesets", "assignments"],
+ "operation": "commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/policies/global/group/policies/firewall/rulesets/assignments/commit"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def updateOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
self, organizationId: str, assignmentId: str, **kwargs
):
@@ -7014,6 +11036,185 @@ def deleteOrganizationPolicyObject(self, organizationId: str, policyObjectId: st
return self._session.delete(metadata, resource)
+ def getOrganizationRoutingVrfs(self, organizationId: str, **kwargs):
+ """
+ **List existing organization-wide VRFs (Virtual Routing and Forwarding).**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-routing-vrfs
+
+ - organizationId (string): Organization ID
+ - vrfIds (array): IDs of the desired VRFs.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "getOrganizationRoutingVrfs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs"
+
+ query_params = [
+ "vrfIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "vrfIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationRoutingVrfs: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def createOrganizationRoutingVrf(self, organizationId: str, name: str, **kwargs):
+ """
+ **Add an organization-wide VRF (Virtual Routing and Forwarding)**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the VRF (Virtual Routing and Forwarding)
+ - description (string): Description of the VRF (Virtual Routing and Forwarding)
+ - routeDistinguisher (string): RD (Route Distinguisher) for the VRF (Virtual Routing and Forwarding)
+ - routeTarget (string): Route target are used to control the import and export of routes between VRFs
+ - appliance (object): This parameter is used to enable or disable the VRF on the WAN appliance
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "createOrganizationRoutingVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs"
+
+ body_params = [
+ "name",
+ "description",
+ "routeDistinguisher",
+ "routeTarget",
+ "appliance",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationRoutingVrf: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationRoutingVrfsOverviewByVrf(self, organizationId: str, **kwargs):
+ """
+ **List existing organization-wide VRFs (Virtual Routing and Forwarding) overviews.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-routing-vrfs-overview-by-vrf
+
+ - organizationId (string): Organization ID
+ - vrfIds (array): IDs of the desired VRFs.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "routing", "vrfs", "overview", "byVrf"],
+ "operation": "getOrganizationRoutingVrfsOverviewByVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/overview/byVrf"
+
+ query_params = [
+ "vrfIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "vrfIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationRoutingVrfsOverviewByVrf: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def updateOrganizationRoutingVrf(self, organizationId: str, vrfId: str, **kwargs):
+ """
+ **Update an organization-wide VRF (Virtual Routing and Forwarding)**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - vrfId (string): Vrf ID
+ - name (string): The name of the VRF (Virtual Routing and Forwarding)
+ - description (string): Description of the VRF (Virtual Routing and Forwarding)
+ - routeDistinguisher (string): RD (Route Distinguisher) for the VRF (Virtual Routing and Forwarding)
+ - routeTarget (string): Route target are used to control the import and export of routes between VRFs
+ - appliance (object): This parameter is used to enable or disable the VRF on the WAN appliance
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "updateOrganizationRoutingVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ vrfId = urllib.parse.quote(str(vrfId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/{vrfId}"
+
+ body_params = [
+ "name",
+ "description",
+ "routeDistinguisher",
+ "routeTarget",
+ "appliance",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationRoutingVrf: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationRoutingVrf(self, organizationId: str, vrfId: str):
+ """
+ **Delete a VRF (Virtual Routing and Forwarding) from a organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - vrfId (string): Vrf ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "deleteOrganizationRoutingVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ vrfId = urllib.parse.quote(str(vrfId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/{vrfId}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationSaml(self, organizationId: str):
"""
**Returns the SAML SSO enabled settings for an organization.**
@@ -7546,7 +11747,7 @@ def getOrganizationSaseSites(self, organizationId: str, total_pages=1, direction
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def attachOrganizationSaseSites(self, organizationId: str, **kwargs):
+ def attachOrganizationSaseSites(self, organizationId: str, items: list, **kwargs):
"""
**Attach sites in this organization to Secure Access**
https://developer.cisco.com/meraki/api-v1/#!attach-organization-sase-sites
@@ -7555,7 +11756,7 @@ def attachOrganizationSaseSites(self, organizationId: str, **kwargs):
- items (array): List of Meraki SD-WAN sites with the associated regions to be attached.
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
"tags": ["organizations", "configure", "sase", "sites"],
@@ -7687,9 +11888,114 @@ def updateOrganizationSaseSite(self, organizationId: str, siteId: str, **kwargs)
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"updateOrganizationSaseSite: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"updateOrganizationSaseSite: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationSites(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Lists unified site resources for an organization across Meraki networks and Catalyst Center sites**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sites
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 500.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - ids (array): Optional parameter to filter resources by unified resource ID. This filter uses multiple exact matches.
+ - resourceTypes (array): Optional parameter to filter resources by returned resource type.
+ - resourceTags (array): Optional parameter to filter resources by tag. By default all provided tags must match.
+ - resourceName (string): Optional parameter to filter resources by case-insensitive partial name match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "sites"],
+ "operation": "getOrganizationSites",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sites"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "ids",
+ "resourceTypes",
+ "resourceTags",
+ "resourceName",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ids",
+ "resourceTypes",
+ "resourceTags",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSites: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSitesBuildings(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the buildings belonging to the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sites-buildings
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter buildings by one or more network IDs
+ - buildingIds (array): Optional parameter to filter buildings by one or more building IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "sites", "buildings"],
+ "operation": "getOrganizationSitesBuildings",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sites/buildings"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "buildingIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "buildingIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSitesBuildings: ignoring unrecognized kwargs: {invalid}")
- return self._session.put(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
def getOrganizationSnmp(self, organizationId: str):
"""
@@ -7762,6 +12068,45 @@ def updateOrganizationSnmp(self, organizationId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getOrganizationSnmpTrapsByNetwork(self, organizationId: str, **kwargs):
+ """
+ **Retrieve the SNMP trap configuration for the networks in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-snmp-traps-by-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): An optional parameter to filter SNMP trap configs by network IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "snmp", "traps", "byNetwork"],
+ "operation": "getOrganizationSnmpTrapsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/snmp/traps/byNetwork"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSnmpTrapsByNetwork: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
def getOrganizationSplashAsset(self, organizationId: str, id: str):
"""
**Get a Splash Theme Asset**
@@ -7912,6 +12257,7 @@ def getOrganizationSummaryTopAppliancesByUtilization(self, organizationId: str,
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -7932,6 +12278,7 @@ def getOrganizationSummaryTopAppliancesByUtilization(self, organizationId: str,
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8057,6 +12404,7 @@ def getOrganizationSummaryTopClientsByUsage(self, organizationId: str, **kwargs)
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8077,6 +12425,7 @@ def getOrganizationSummaryTopClientsByUsage(self, organizationId: str, **kwargs)
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8104,6 +12453,7 @@ def getOrganizationSummaryTopClientsManufacturersByUsage(self, organizationId: s
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8124,6 +12474,7 @@ def getOrganizationSummaryTopClientsManufacturersByUsage(self, organizationId: s
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8151,6 +12502,7 @@ def getOrganizationSummaryTopDevicesByUsage(self, organizationId: str, **kwargs)
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8171,6 +12523,7 @@ def getOrganizationSummaryTopDevicesByUsage(self, organizationId: str, **kwargs)
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8198,6 +12551,7 @@ def getOrganizationSummaryTopDevicesModelsByUsage(self, organizationId: str, **k
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8218,6 +12572,7 @@ def getOrganizationSummaryTopDevicesModelsByUsage(self, organizationId: str, **k
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8247,6 +12602,7 @@ def getOrganizationSummaryTopNetworksByStatus(self, organizationId: str, total_p
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8267,6 +12623,7 @@ def getOrganizationSummaryTopNetworksByStatus(self, organizationId: str, total_p
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8294,6 +12651,7 @@ def getOrganizationSummaryTopSsidsByUsage(self, organizationId: str, **kwargs):
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8314,6 +12672,7 @@ def getOrganizationSummaryTopSsidsByUsage(self, organizationId: str, **kwargs):
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8341,6 +12700,7 @@ def getOrganizationSummaryTopSwitchesByEnergyUsage(self, organizationId: str, **
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8361,6 +12721,7 @@ def getOrganizationSummaryTopSwitchesByEnergyUsage(self, organizationId: str, **
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8489,6 +12850,137 @@ def getOrganizationWebhooksCallbacksStatus(self, organizationId: str, callbackId
return self._session.get(metadata, resource)
+ def getOrganizationWebhooksHttpServers(self, organizationId: str):
+ """
+ **List the HTTP servers for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-http-servers
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "getOrganizationWebhooksHttpServers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationWebhooksHttpServer(self, organizationId: str, name: str, url: str, **kwargs):
+ """
+ **Add an HTTP server to an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - name (string): A name for easy reference to the HTTP server
+ - url (string): The URL of the HTTP server
+ - sharedSecret (string): A shared secret that will be included in POSTs sent to the HTTP server. This secret can be used to verify that the request was sent by Meraki.
+ - payloadTemplate (object): The payload template to use when posting data to the HTTP server.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "createOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers"
+
+ body_params = [
+ "name",
+ "url",
+ "sharedSecret",
+ "payloadTemplate",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationWebhooksHttpServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWebhooksHttpServer(self, organizationId: str, id: str):
+ """
+ **Return an HTTP server for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "getOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationWebhooksHttpServer(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update an HTTP server for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): A name for easy reference to the HTTP server
+ - url (string): The URL of the HTTP server
+ - sharedSecret (string): A shared secret that will be included in POSTs sent to the HTTP server. This secret can be used to verify that the request was sent by Meraki.
+ - payloadTemplate (object): The payload template to use when posting data to the HTTP server.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "updateOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers/{id}"
+
+ body_params = [
+ "name",
+ "url",
+ "sharedSecret",
+ "payloadTemplate",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationWebhooksHttpServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationWebhooksHttpServer(self, organizationId: str, id: str):
+ """
+ **Delete an HTTP server from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "deleteOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationWebhooksLogs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Return the log of webhook POSTs sent**
@@ -8533,3 +13025,206 @@ def getOrganizationWebhooksLogs(self, organizationId: str, total_pages=1, direct
self._session._logger.warning(f"getOrganizationWebhooksLogs: ignoring unrecognized kwargs: {invalid}")
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWebhooksPayloadTemplates(self, organizationId: str):
+ """
+ **List the webhook payload templates for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-payload-templates
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "getOrganizationWebhooksPayloadTemplates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationWebhooksPayloadTemplate(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the new template
+ - body (string): The liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
+ - headers (array): The liquid template used with the webhook headers.
+ - bodyFile (string): A file containing liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
+ - headersFile (string): A file containing the liquid template used with the webhook headers.
+ - sharing (object): Information on which entities have access to the template
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "createOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates"
+
+ body_params = [
+ "name",
+ "body",
+ "headers",
+ "bodyFile",
+ "headersFile",
+ "sharing",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWebhooksPayloadTemplate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str):
+ """
+ **Get the webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "getOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ return self._session.get(metadata, resource)
+
+ def deleteOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str):
+ """
+ **Destroy a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "deleteOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str, **kwargs):
+ """
+ **Update a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ - name (string): The name of the template
+ - body (string): The liquid template used for the body of the webhook message.
+ - headers (array): The liquid template used with the webhook headers.
+ - bodyFile (string): A file containing liquid template used for the body of the webhook message.
+ - headersFile (string): A file containing the liquid template used with the webhook headers.
+ - sharing (object): Information on which entities have access to the template
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "updateOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ body_params = [
+ "name",
+ "body",
+ "headers",
+ "bodyFile",
+ "headersFile",
+ "sharing",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWebhooksPayloadTemplate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def createOrganizationWebhooksWebhookTest(self, organizationId: str, url: str, **kwargs):
+ """
+ **Send a test webhook for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-webhook-test
+
+ - organizationId (string): Organization ID
+ - url (string): The URL where the test webhook will be sent
+ - sharedSecret (string): The shared secret the test webhook will send. Optional. Defaults to HTTP server's shared secret. Otherwise, defaults to an empty string.
+ - payloadTemplateId (string): The ID of the payload template of the test webhook. Defaults to the HTTP server's template ID if one exists for the given URL, or Generic template ID otherwise
+ - payloadTemplateName (string): The name of the payload template.
+ - alertTypeId (string): The type of alert which the test webhook will send. Optional. Defaults to insight_app_outage_start.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "webhookTests"],
+ "operation": "createOrganizationWebhooksWebhookTest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/webhookTests"
+
+ body_params = [
+ "url",
+ "sharedSecret",
+ "payloadTemplateId",
+ "payloadTemplateName",
+ "alertTypeId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWebhooksWebhookTest: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWebhooksWebhookTest(self, organizationId: str, webhookTestId: str):
+ """
+ **Return the status of a webhook test for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-webhook-test
+
+ - organizationId (string): Organization ID
+ - webhookTestId (string): Webhook test ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "webhookTests"],
+ "operation": "getOrganizationWebhooksWebhookTest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ webhookTestId = urllib.parse.quote(str(webhookTestId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/webhookTests/{webhookTestId}"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/aio/api/secureConnect.py b/meraki/aio/api/secureConnect.py
new file mode 100644
index 00000000..47003170
--- /dev/null
+++ b/meraki/aio/api/secureConnect.py
@@ -0,0 +1,1084 @@
+import urllib
+
+
+class AsyncSecureConnect:
+ def __init__(self, session):
+ super().__init__()
+ self._session = session
+
+ def getOrganizationSecureConnectPrivateApplicationGroups(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides a list of private application groups for an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-application-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - nameIncludes (string): Optional parameter to search the application group list by group name, case is ignored
+ - applicationGroupIds (array): List of application group ids attached to fetch
+ - sortBy (string): Optional parameter to specify the field used to sort objects.
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is asc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["applicationGroupId", "modifiedAt", "name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "getOrganizationSecureConnectPrivateApplicationGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "nameIncludes",
+ "applicationGroupIds",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "applicationGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPrivateApplicationGroups: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Creates a group of private applications to apply to policy**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - name (string): Application Group Name. This is required and cannot have any special characters other than spaces and hyphens
+ - description (string): Optional short description for application group
+ - applicationIds (array): List of application ids attached to this Private Application Group
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "createOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups"
+
+ body_params = [
+ "name",
+ "description",
+ "applicationIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateApplicationGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, id: str, name: str, **kwargs):
+ """
+ **Update an application group in an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Application Group Name. This is required and cannot have any special characters other than spaces and hyphens
+ - description (string): Optional short description for application group
+ - applicationIds (array): List of application ids attached to this Private Application Group
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "updateOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "applicationIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateApplicationGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, id: str, **kwargs):
+ """
+ **Deletes private application group from an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - force (boolean): Boolean flag to force delete application group, even if application group is in use by one or more rules.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "deleteOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, id: str):
+ """
+ **Return the details of a specific private application group**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "getOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateApplications(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provides a list of private applications for an Organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-applications
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - nameIncludes (string): Optional parameter to filter the private applications list by application and associated application group names, case is ignored
+ - applicationGroupIds (array): Optional parameter for filtering the list of private applications belonging to the application group identified by the given IDs.
+ - appTypes (array): Optional parameter for filtering the list of private applications by applications that contain at least one destination with the specified accessType value.
+ - sortBy (string): Optional parameter to specify the field used to sort objects.
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is asc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["modifiedAt", "name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "getOrganizationSecureConnectPrivateApplications",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "nameIncludes",
+ "applicationGroupIds",
+ "appTypes",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "applicationGroupIds",
+ "appTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPrivateApplications: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectPrivateApplication(self, organizationId: str, name: str, destinations: list, **kwargs):
+ """
+ **Adds a new private application to the Organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - name (string): Name of Application. This is required and should be unique across all applications for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - destinations (array): List of IP address destinations.
+ - description (string): Optional Text description for Application
+ - appProtocol (string): Protocol for communication between proxy to private application. Applicable for Browser Based Access only.
+ - sni (string): Optional SNI. Applicable for Browser Based Access only. SNI should be a valid domain.
+ - externalFQDN (string): Cisco or Customer Managed URL for Application. Applicable for Browser Based Access only. This field is system generated based on the application name and organization ID and overrides user input in payload. This value must be unique across all applications for a given organization.
+ - sslVerificationEnabled (boolean): Enable Upstream SSL verification for the internally hosted URL by the customer. Applicable for Browser Based Access only. Default is true.
+ - applicationGroupIds (array): List of application group ids attached to this Private Application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "createOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications"
+
+ body_params = [
+ "name",
+ "description",
+ "destinations",
+ "appProtocol",
+ "sni",
+ "externalFQDN",
+ "sslVerificationEnabled",
+ "applicationGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateApplication: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateApplication(
+ self, organizationId: str, id: str, name: str, destinations: list, **kwargs
+ ):
+ """
+ **Updates a specific private application**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of Application. This is required and should be unique across all applications for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - destinations (array): List of IP address destinations.
+ - description (string): Optional Text description for Application
+ - appProtocol (string): Protocol for communication between proxy to private application. Applicable for Browser Based Access only.
+ - sni (string): Optional SNI. Applicable for Browser Based Access only. SNI should be a valid domain.
+ - externalFQDN (string): Cisco or Customer Managed URL for Application. Applicable for Browser Based Access only. This field is system generated based on the application name and organization ID and overrides user input in payload. This value must be unique across all applications for a given organization.
+ - sslVerificationEnabled (boolean): Enable Upstream SSL verification for the internally hosted URL by the customer. Applicable for Browser Based Access only. Default is true.
+ - applicationGroupIds (array): List of application group ids attached to this Private Application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "updateOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "destinations",
+ "appProtocol",
+ "sni",
+ "externalFQDN",
+ "sslVerificationEnabled",
+ "applicationGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateApplication: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateApplication(self, organizationId: str, id: str, **kwargs):
+ """
+ **Deletes a specific private application**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - force (boolean): Boolean flag to force delete application, even if application is in use by one or more rules.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "deleteOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateApplication(self, organizationId: str, id: str):
+ """
+ **Return the details of a specific private application**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "getOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateResourceGroups(self, organizationId: str):
+ """
+ **Provides a list of the private resource groups in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-resource-groups
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "getOrganizationSecureConnectPrivateResourceGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Adds a new private resource group to an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - name (string): Name of group. This is required and should be unique across all groups for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - description (string): Optional text description for a group.
+ - resourceIds (array): List of resource ids assigned to this group.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "createOrganizationSecureConnectPrivateResourceGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups"
+
+ body_params = [
+ "name",
+ "description",
+ "resourceIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateResourceGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, id: str, name: str, **kwargs):
+ """
+ **Updates a specific private resource group.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of group. This is required and should be unique across all groups for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - description (string): Optional text description for a group.
+ - resourceIds (array): List of resource ids assigned to this group.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "updateOrganizationSecureConnectPrivateResourceGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "resourceIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateResourceGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, id: str):
+ """
+ **Deletes a specific private resource group.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "deleteOrganizationSecureConnectPrivateResourceGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateResources(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provides a list of private resources for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-resources
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (string): Number of resources to return for a paginated response.
+ - startingAfter (string): The name of the resource to start after for a paginated response. Use '' for the first page.
+ - endingBefore (string): The name of the resource to end before for a paginated response. Use '' for the final page.
+ - sortBy (string): Parameter to specify the field used to sort objects, by default, resources are returned by name asc.
+ - sortOrder (string): Parameter to specify the direction used to sort objects, by default, resources are returned by name asc.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "getOrganizationSecureConnectPrivateResources",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPrivateResources: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectPrivateResource(
+ self, organizationId: str, name: str, accessTypes: list, resourceAddresses: list, **kwargs
+ ):
+ """
+ **Adds a new private resource to the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - name (string): Name of resource. This is required and should be unique across all resources for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - accessTypes (array): List of access types.
+ - resourceAddresses (array): List of resource addresses Protocols must be unique in this list.
+ - description (string): Optional text description for a resource.
+ - resourceGroupIds (array): List of resource group ids attached to this resource.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "createOrganizationSecureConnectPrivateResource",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources"
+
+ body_params = [
+ "name",
+ "description",
+ "accessTypes",
+ "resourceAddresses",
+ "resourceGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateResource: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateResource(
+ self, organizationId: str, id: str, name: str, accessTypes: list, resourceAddresses: list, **kwargs
+ ):
+ """
+ **Updates a specific private resource.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of resource. This is required and should be unique across all resources for a given organization.Name cannot have any special characters other than spaces and hyphens.
+ - accessTypes (array): List of access types.
+ - resourceAddresses (array): List of resource addresses Protocols must be unique in this list.
+ - description (string): Optional text description for resource.
+ - resourceGroupIds (array): List of resource group ids attached to this resource.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "updateOrganizationSecureConnectPrivateResource",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "accessTypes",
+ "resourceAddresses",
+ "resourceGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateResource: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateResource(self, organizationId: str, id: str):
+ """
+ **Deletes a specific private resource**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "deleteOrganizationSecureConnectPrivateResource",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPublicApplications(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provides a list of public applications for an Organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-public-applications
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - nameIncludes (string): Optional parameter to filter the public applications list by application name, case is ignored
+ - risks (array): List of risk levels to filter by
+ - categories (array): List of categories to filter by
+ - appTypes (array): List of app types to filter by
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - sortBy (string): Optional parameter to specify the field used to sort objects, by default, applications are returned by lastDetected desc
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is desc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["appType", "category", "lastDetected", "name", "risk"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "publicApplications"],
+ "operation": "getOrganizationSecureConnectPublicApplications",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/publicApplications"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "nameIncludes",
+ "risks",
+ "categories",
+ "appTypes",
+ "t0",
+ "t1",
+ "timespan",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "risks",
+ "categories",
+ "appTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPublicApplications: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSecureConnectRegions(self, organizationId: str, **kwargs):
+ """
+ **List deployed cloud hubs and regions in this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-regions
+
+ - organizationId (string): Organization ID
+ - regionType (string): Filter results by region type
+ """
+
+ kwargs.update(locals())
+
+ if "regionType" in kwargs:
+ options = ["CNHE", "CloudHub", "Region", "ThirdParty"]
+ assert kwargs["regionType"] in options, (
+ f'''"regionType" cannot be "{kwargs["regionType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "regions"],
+ "operation": "getOrganizationSecureConnectRegions",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/regions"
+
+ query_params = [
+ "regionType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSecureConnectRegions: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSecureConnectRemoteAccessLog(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the latest 5000 events logged by remote access.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-log
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - identityids (string): An identity ID or comma-delimited list of identity ID.
+ - identitytypes (string): An identity type or comma-delimited list of identity type.
+ - connectionevent (string): Specify the type of connection event.
+ - anyconnectversions (string): Specify a comma-separated list of AnyConnect Roaming Security module
+ versions to filter the data.
+ - osversions (string): Specify a comma-separated list of OS versions to filter the data.
+ """
+
+ kwargs.update(locals())
+
+ if "connectionevent" in kwargs:
+ options = ["connected", "disconnected", "failed"]
+ assert kwargs["connectionevent"] in options, (
+ f'''"connectionevent" cannot be "{kwargs["connectionevent"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "monitor", "remoteAccessLog"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLog",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLog"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "identityids",
+ "identitytypes",
+ "connectionevent",
+ "anyconnectversions",
+ "osversions",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectRemoteAccessLog: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSecureConnectRemoteAccessLogsExports(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides a list of remote access logs exports for an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-logs-exports
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - status (string): Filter exports by status.
+ """
+
+ kwargs.update(locals())
+
+ if "status" in kwargs:
+ options = ["complete", "continue", "error", "in_progress", "new", "zip"]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLogsExports",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "status",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectRemoteAccessLogsExports: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, **kwargs):
+ """
+ **Creates an export for a provided timestamp interval.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-remote-access-logs-export
+
+ - organizationId (string): Organization ID
+ - t0 (string): The start of the interval, must be within the past 30 days. Must be provided with t1.
+ - t1 (string): The end of the interval, must not exceed the current date. Must be provided with t0.
+ - from (integer): Legacy start of the interval in epoch seconds, must be within the past 30 days. Must be provided with to.
+ - to (integer): Legacy end of the interval in epoch seconds, must not exceed the current date. Must be provided with from.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports"],
+ "operation": "createOrganizationSecureConnectRemoteAccessLogsExport",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports"
+
+ body_params = [
+ "t0",
+ "t1",
+ "from",
+ "to",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectRemoteAccessLogsExport: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSecureConnectRemoteAccessLogsExportsDownload(
+ self, organizationId: str, id: str, fileType: str, **kwargs
+ ):
+ """
+ **Redirects to the download link of the completed export.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-logs-exports-download
+
+ - organizationId (string): Organization ID
+ - id (string): Export ID.
+ - fileType (string): Export download file type.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports", "download"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLogsExportsDownload",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports/download"
+
+ query_params = [
+ "id",
+ "fileType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectRemoteAccessLogsExportsDownload: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, id: str):
+ """
+ **Return the details of a specific remote access logs export**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-logs-export
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLogsExport",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSecureConnectSites(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List sites in this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-sites
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): If provided, filters results by search string
+ - enrolledState (string): Filter results by sites that have already been enrolled or can be enrolled. Acceptable values are 'enrolled' or 'enrollable
+ """
+
+ kwargs.update(locals())
+
+ if "enrolledState" in kwargs:
+ options = ["enrollable", "enrolled"]
+ assert kwargs["enrolledState"] in options, (
+ f'''"enrolledState" cannot be "{kwargs["enrolledState"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "sites"],
+ "operation": "getOrganizationSecureConnectSites",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "enrolledState",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSecureConnectSites: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectSite(self, organizationId: str, **kwargs):
+ """
+ **Enroll sites in this organization to Secure Connect**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-site
+
+ - organizationId (string): Organization ID
+ - enrollments (array): List of Meraki SD-WAN sites with the associated regions to be enrolled.
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "sites"],
+ "operation": "createOrganizationSecureConnectSite",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ body_params = [
+ "enrollments",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationSecureConnectSite: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectSites(self, organizationId: str, **kwargs):
+ """
+ **Detach given sites from Secure Connect**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-sites
+
+ - organizationId (string): Organization ID
+ - sites (array): List of site IDs to detach
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "sites"],
+ "operation": "deleteOrganizationSecureConnectSites",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ return self._session.delete(metadata, resource)
diff --git a/meraki/aio/api/sensor.py b/meraki/aio/api/sensor.py
index 115465f4..9e18e0da 100644
--- a/meraki/aio/api/sensor.py
+++ b/meraki/aio/api/sensor.py
@@ -74,9 +74,10 @@ def createDeviceSensorCommand(self, serial: str, operation: str, **kwargs):
- serial (string): Serial
- operation (string): Operation to run on the sensor. 'enableDownstreamPower', 'disableDownstreamPower', and 'cycleDownstreamPower' turn power on/off to the device that is connected downstream of an MT40 power monitor. 'refreshData' causes an MT15 or MT40 device to upload its latest readings so that they are immediately available in the Dashboard API.
+ - arguments (array): Additional options to provide to commands run on the sensor, each with a corresponding 'name' and 'value'.
"""
- kwargs = locals()
+ kwargs.update(locals())
if "operation" in kwargs:
options = ["cycleDownstreamPower", "disableDownstreamPower", "enableDownstreamPower", "refreshData"]
@@ -92,6 +93,7 @@ def createDeviceSensorCommand(self, serial: str, operation: str, **kwargs):
resource = f"/devices/{serial}/sensor/commands"
body_params = [
+ "arguments",
"operation",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -456,6 +458,103 @@ def getNetworkSensorRelationships(self, networkId: str):
return self._session.get(metadata, resource)
+ def getNetworkSensorSchedules(self, networkId: str):
+ """
+ **Returns a list of all sensor schedules.**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sensor-schedules
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["sensor", "configure", "schedules"],
+ "operation": "getNetworkSensorSchedules",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sensor/schedules"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSensorAlerts(self, organizationId: str, networkIds: list, total_pages=1, direction="next", **kwargs):
+ """
+ **Return a list of sensor alert events**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sensor-alerts
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filters alerts by network. For now, this must be a single network ID.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 365 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 365 days. The default is 365 days.
+ - sensorSerial (string): Filters alerts to those triggered by this sensor.
+ - triggerMetric (string): Filters alerts to those triggered by this metric.
+ """
+
+ kwargs.update(locals())
+
+ if "triggerMetric" in kwargs:
+ options = [
+ "apparentPower",
+ "co2",
+ "current",
+ "door",
+ "frequency",
+ "humidity",
+ "indoorAirQuality",
+ "noise",
+ "pm25",
+ "powerFactor",
+ "realPower",
+ "temperature",
+ "tvoc",
+ "upstreamPower",
+ "voltage",
+ "water",
+ ]
+ assert kwargs["triggerMetric"] in options, (
+ f'''"triggerMetric" cannot be "{kwargs["triggerMetric"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["sensor", "monitor", "alerts"],
+ "operation": "getOrganizationSensorAlerts",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sensor/alerts"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "sensorSerial",
+ "networkIds",
+ "triggerMetric",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSensorAlerts: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationSensorGatewaysConnectionsLatest(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Returns latest sensor-gateway connectivity data.**
@@ -564,6 +663,72 @@ def getOrganizationSensorReadingsHistory(self, organizationId: str, total_pages=
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationSensorReadingsHistoryByInterval(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return all reported readings from sensors in a given timespan, summarized as a series of intervals, sorted by interval start time in descending order**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sensor-readings-history-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 730 days, 11 hours, 38 minutes, and 24 seconds from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 730 days, 11 hours, 38 minutes, and 24 seconds after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 730 days, 11 hours, 38 minutes, and 24 seconds. The default is 7 days. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 15, 120, 300, 900, 3600, 14400, 86400, 604800. The default is 86400. Interval is calculated if time params are provided.
+ - networkIds (array): Optional parameter to filter readings by network.
+ - serials (array): Optional parameter to filter readings by sensor.
+ - metrics (array): Types of sensor readings to retrieve. If no metrics are supplied, all available types of readings will be retrieved.
+ - models (array): Optional parameter to filter readings by one or more models.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sensor", "monitor", "readings", "history", "byInterval"],
+ "operation": "getOrganizationSensorReadingsHistoryByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sensor/readings/history/byInterval"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "serials",
+ "metrics",
+ "models",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "metrics",
+ "models",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSensorReadingsHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationSensorReadingsLatest(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Return the latest available reading for each metric from each sensor, sorted by sensor serial**
diff --git a/meraki/aio/api/sm.py b/meraki/aio/api/sm.py
index 26075e3d..263da776 100644
--- a/meraki/aio/api/sm.py
+++ b/meraki/aio/api/sm.py
@@ -894,6 +894,379 @@ def getNetworkSmProfiles(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkSmScripts(self, networkId: str):
+ """
+ **List the scripts for this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-scripts
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "getNetworkSmScripts",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts"
+
+ return self._session.get(metadata, resource)
+
+ def createNetworkSmScript(self, networkId: str, name: str, platform: str, **kwargs):
+ """
+ **Create a new script**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-script
+
+ - networkId (string): Network ID
+ - name (string): Unique name to identify this script.
+ - platform (string): Platform that this script will run on.
+ - scope (string): The target scope of the script. (Either scope or targetGroupId must be present.)
+ - tags (array): The target tags of the script as an array of strings. Required if scope is one of withAny, withoutAny, withAll, withoutAll.
+ - targetGroupId (string): The tag target group ID that should be used to scope devices. Either scope or targetGroupId must be present.
+ - description (string): Description of this script.
+ - runAsUsername (string): Username that script should run as.
+ - externalSource (object): Properties for a script provided by a url instead of an upload
+ - upload (object): Properties for a script provided as an upload instead of a url
+ - schedule (object): When the script is intended to run
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs and kwargs["platform"] is not None:
+ options = ["Windows", "macOS"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+ if "scope" in kwargs:
+ options = ["all", "none", "withAll", "withAny", "withoutAll", "withoutAny"]
+ assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "createNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts"
+
+ body_params = [
+ "name",
+ "platform",
+ "scope",
+ "tags",
+ "targetGroupId",
+ "description",
+ "runAsUsername",
+ "externalSource",
+ "upload",
+ "schedule",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSmScript: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def createNetworkSmScriptsJob(self, networkId: str, scriptId: str, **kwargs):
+ """
+ **Create a job that will run a script on a set of devices**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-scripts-job
+
+ - networkId (string): Network ID
+ - scriptId (string): ID of script that should be run on the matching devices
+ - deviceIds (array): List of device IDs to run that should run this script
+ - deviceFilter (string): Create job on all devices in-scope or devices that have failed to run this script
+ """
+
+ kwargs.update(locals())
+
+ if "deviceFilter" in kwargs:
+ options = ["All", "Failed"]
+ assert kwargs["deviceFilter"] in options, (
+ f'''"deviceFilter" cannot be "{kwargs["deviceFilter"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "jobs"],
+ "operation": "createNetworkSmScriptsJob",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs"
+
+ body_params = [
+ "scriptId",
+ "deviceIds",
+ "deviceFilter",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSmScriptsJob: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getNetworkSmScriptsJobsStatusesLatestByScriptByInterval(self, networkId: str, **kwargs):
+ """
+ **List the latest script job statuses by script and by interval**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-scripts-jobs-statuses-latest-by-script-by-interval
+
+ - networkId (string): Network ID
+ - scriptIds (array): List of script IDs to fetch statuses
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 180 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 180 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "jobs", "statuses", "latest", "byScript", "byInterval"],
+ "operation": "getNetworkSmScriptsJobsStatusesLatestByScriptByInterval",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs/statuses/latest/byScript/byInterval"
+
+ query_params = [
+ "scriptIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "scriptIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkSmScriptsJobsStatusesLatestByScriptByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getNetworkSmScriptsJobsStatusesLatestByScriptAndDevice(
+ self, networkId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List jobs for a given script and/or device**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-scripts-jobs-statuses-latest-by-script-and-device
+
+ - networkId (string): Network ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - deviceId (string): Query parameter for filtering the list of script job statuses to those belonging to the specified deviceId.
+ - scriptId (string): Query parameter for filtering the list of script job statuses to those belonging to the specified script.
+ - inScopeOnly (boolean): If true, show only job statuses for scripts or devices that are in scope. This only applies when either deviceId or scriptId are given.
+ - status (string): Query parameter for filtering the list of job statuses to those having the specified status.
+ - sortOrder (string): Query parameter for specifying the direction of sorting to use for the given sortKey. This param is overridden if startingAfter or endingBefore is provided.
+ - sortKey (string): Query parameter to sort the script tasks by the value of the specified key. This param is overridden if startingAfter or endingBefore is provided.
+ - perPage (integer): Number of results to show per page.
+ - startingAfter (string): A statusId. Start the search cursor after the specified Status record.
+ - endingBefore (string): A statusId. Search backward with the cursor starting before the specified Status record.
+ """
+
+ kwargs.update(locals())
+
+ if "status" in kwargs:
+ options = [
+ "cancelled",
+ "command failed",
+ "completed",
+ "created",
+ "enqueued",
+ "error",
+ "failed",
+ "pending",
+ "running",
+ "success",
+ "unknown",
+ ]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = ["completedAt", "createdAt", "enqueuedAt", "status", "updatedAt"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "jobs", "statuses", "latest", "byScriptAndDevice"],
+ "operation": "getNetworkSmScriptsJobsStatusesLatestByScriptAndDevice",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs/statuses/latest/byScriptAndDevice"
+
+ query_params = [
+ "deviceId",
+ "scriptId",
+ "inScopeOnly",
+ "status",
+ "sortOrder",
+ "sortKey",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkSmScriptsJobsStatusesLatestByScriptAndDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createNetworkSmScriptsUpload(self, networkId: str, size: str, **kwargs):
+ """
+ **Creates an upload URL that can be used to upload a script**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-scripts-upload
+
+ - networkId (string): Network ID
+ - size (string): Size of the file in bytes that will be uploaded.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "uploads"],
+ "operation": "createNetworkSmScriptsUpload",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/uploads"
+
+ body_params = [
+ "size",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSmScriptsUpload: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getNetworkSmScript(self, networkId: str, scriptId: str):
+ """
+ **Return a script**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "getNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkSmScript(self, networkId: str, scriptId: str, **kwargs):
+ """
+ **Update an existing script**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ - name (string): Unique name to identify this script.
+ - platform (string): Platform that this script will run on.
+ - scope (string): The target scope of the script. (Either scope or targetGroupId must be present.)
+ - tags (array): The target tags of the script as an array of strings. Required if scope is one of withAny, withoutAny, withAll, withoutAll.
+ - targetGroupId (string): The tag target group ID that should be used to scope devices. Either scope or targetGroupId must be present.
+ - description (string): Description of this script.
+ - runAsUsername (string): Username that script should run as.
+ - externalSource (object): Properties for a script provided by a url instead of an upload
+ - upload (object): Properties for a script provided as an upload instead of a url
+ - schedule (object): When the script is intended to run
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs and kwargs["platform"] is not None:
+ options = ["Windows", "macOS"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+ if "scope" in kwargs:
+ options = ["all", "none", "withAll", "withAny", "withoutAll", "withoutAny"]
+ assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "updateNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ body_params = [
+ "name",
+ "platform",
+ "scope",
+ "tags",
+ "targetGroupId",
+ "description",
+ "runAsUsername",
+ "externalSource",
+ "upload",
+ "schedule",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSmScript: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteNetworkSmScript(self, networkId: str, scriptId: str):
+ """
+ **Delete a script**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "deleteNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ return self._session.delete(metadata, resource)
+
def getNetworkSmTargetGroups(self, networkId: str, **kwargs):
"""
**List the target groups in this network**
@@ -1396,6 +1769,187 @@ def getOrganizationSmApnsCert(self, organizationId: str):
return self._session.get(metadata, resource)
+ def createOrganizationSmAppleCloudEnrollmentSyncJob(self, organizationId: str, **kwargs):
+ """
+ **Enqueue a sync job for an ADE account**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-sm-apple-cloud-enrollment-sync-job
+
+ - organizationId (string): Organization ID
+ - adeAccountId (string): ADE Account ID
+ - fullSync (boolean): Whether or not job is full sync (defaults to full sync)
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sm", "configure", "apple", "cloudEnrollment", "syncJobs"],
+ "operation": "createOrganizationSmAppleCloudEnrollmentSyncJob",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/apple/cloudEnrollment/syncJobs"
+
+ body_params = [
+ "adeAccountId",
+ "fullSync",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSmAppleCloudEnrollmentSyncJob: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSmAppleCloudEnrollmentSyncJob(self, organizationId: str, syncJobId: str):
+ """
+ **Retrieve the status of an ADE sync job**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sm-apple-cloud-enrollment-sync-job
+
+ - organizationId (string): Organization ID
+ - syncJobId (string): Sync job ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "apple", "cloudEnrollment", "syncJobs"],
+ "operation": "getOrganizationSmAppleCloudEnrollmentSyncJob",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ syncJobId = urllib.parse.quote(str(syncJobId), safe="")
+ resource = f"/organizations/{organizationId}/sm/apple/cloudEnrollment/syncJobs/{syncJobId}"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationSmBulkEnrollmentToken(self, organizationId: str, networkId: str, expiresAt: str, **kwargs):
+ """
+ **Create a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - networkId (string): The id of the associated node_group.
+ - expiresAt (string): The expiration date.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "createOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token"
+
+ body_params = [
+ "networkId",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSmBulkEnrollmentToken: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str):
+ """
+ **Return a BulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "getOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str, **kwargs):
+ """
+ **Update a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ - networkId (string): The id of the associated node_group.
+ - expiresAt (string): The expiration date.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "updateOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ body_params = [
+ "networkId",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSmBulkEnrollmentToken: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str):
+ """
+ **Delete a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "deleteOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSmBulkEnrollmentTokens(self, organizationId: str):
+ """
+ **List all BulkEnrollmentTokens for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sm-bulk-enrollment-tokens
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "tokens"],
+ "operation": "getOrganizationSmBulkEnrollmentTokens",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/tokens"
+
+ return self._session.get(metadata, resource)
+
def updateOrganizationSmSentryPoliciesAssignments(self, organizationId: str, items: list, **kwargs):
"""
**Update an Organizations Sentry Policies using the provided list**
diff --git a/meraki/aio/api/support.py b/meraki/aio/api/support.py
new file mode 100644
index 00000000..721ee809
--- /dev/null
+++ b/meraki/aio/api/support.py
@@ -0,0 +1,24 @@
+import urllib
+
+
+class AsyncSupport:
+ def __init__(self, session):
+ super().__init__()
+ self._session = session
+
+ def getOrganizationSupportSalesRepresentatives(self, organizationId: str):
+ """
+ **Returns the organization's sales representatives**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-support-sales-representatives
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["support", "monitor", "salesRepresentatives"],
+ "operation": "getOrganizationSupportSalesRepresentatives",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/support/salesRepresentatives"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/aio/api/switch.py b/meraki/aio/api/switch.py
index 21dcc763..e4436722 100644
--- a/meraki/aio/api/switch.py
+++ b/meraki/aio/api/switch.py
@@ -6,14 +6,17 @@ def __init__(self, session):
super().__init__()
self._session = session
- def getDeviceSwitchPorts(self, serial: str):
+ def getDeviceSwitchPorts(self, serial: str, **kwargs):
"""
**List the switch ports for a switch**
https://developer.cisco.com/meraki/api-v1/#!get-device-switch-ports
- serial (string): Serial
+ - hideDefaultPorts (boolean): Optional flag that, when true, will hide modular switchports that may not be connected to the device at the moment
"""
+ kwargs.update(locals())
+
metadata = {
"tags": ["switch", "configure", "ports"],
"operation": "getDeviceSwitchPorts",
@@ -21,7 +24,18 @@ def getDeviceSwitchPorts(self, serial: str):
serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/switch/ports"
- return self._session.get(metadata, resource)
+ query_params = [
+ "hideDefaultPorts",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getDeviceSwitchPorts: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
def cycleDeviceSwitchPorts(self, serial: str, ports: list, **kwargs):
"""
@@ -54,6 +68,46 @@ def cycleDeviceSwitchPorts(self, serial: str, ports: list, **kwargs):
return self._session.post(metadata, resource, payload)
+ def updateDeviceSwitchPortsMirror(self, serial: str, source: dict, destination: dict, **kwargs):
+ """
+ **Update a port mirror**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-switch-ports-mirror
+
+ - serial (string): The switch identifier
+ - source (object): Source ports mirror configuration
+ - destination (object): Destination port mirror configuration
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "mirror"],
+ "operation": "updateDeviceSwitchPortsMirror",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/switch/ports/mirror"
+
+ body_params = [
+ "serial",
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceSwitchPortsMirror: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getDeviceSwitchPortsStatuses(self, serial: str, **kwargs):
"""
**Return the status for all the ports of a switch**
@@ -154,6 +208,7 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
- vlan (integer): The VLAN of the switch port. For a trunk port, this is the native VLAN. A null value will clear the value set for trunk ports.
- voiceVlan (integer): The voice VLAN of the switch port. Only applicable to access ports.
- allowedVlans (string): The VLANs allowed on the switch port. Only applicable to trunk ports.
+ - activeVlans (string): The VLANs that are active on the switch port. Only applicable to trunk ports.
- isolationEnabled (boolean): The isolation status of the switch port.
- rstpEnabled (boolean): The rapid spanning tree protocol status.
- stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard').
@@ -214,6 +269,7 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
"vlan",
"voiceVlan",
"allowedVlans",
+ "activeVlans",
"isolationEnabled",
"rstpEnabled",
"stpGuard",
@@ -303,6 +359,12 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -337,6 +399,12 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -386,6 +454,12 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -417,6 +491,12 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -1388,14 +1468,17 @@ def updateNetworkSwitchDscpToCosMappings(self, networkId: str, mappings: list, *
return self._session.put(metadata, resource, payload)
- def getNetworkSwitchLinkAggregations(self, networkId: str):
+ def getNetworkSwitchLinkAggregations(self, networkId: str, **kwargs):
"""
**List link aggregation groups**
https://developer.cisco.com/meraki/api-v1/#!get-network-switch-link-aggregations
- networkId (string): Network ID
+ - serials (array): Optional parameter to filter by device serial numbers. Matches multiple exact serials.
"""
+ kwargs.update(locals())
+
metadata = {
"tags": ["switch", "configure", "linkAggregations"],
"operation": "getNetworkSwitchLinkAggregations",
@@ -1403,7 +1486,26 @@ def getNetworkSwitchLinkAggregations(self, networkId: str):
networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/linkAggregations"
- return self._session.get(metadata, resource)
+ query_params = [
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getNetworkSwitchLinkAggregations: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
"""
@@ -1413,6 +1515,7 @@ def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
- networkId (string): Network ID
- switchPorts (array): Array of switch or stack ports for creating aggregation group. Minimum 2 and maximum 8 ports are supported.
- switchProfilePorts (array): Array of switch profile ports for creating aggregation group. Minimum 2 and maximum 8 ports are supported.
+ - esiMhPairId (string): ESI-MH pair ID. Required when creating a downstream aggregation across ESI-MH pair member switches.
"""
kwargs.update(locals())
@@ -1427,6 +1530,7 @@ def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
body_params = [
"switchPorts",
"switchProfilePorts",
+ "esiMhPairId",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1652,6 +1756,126 @@ def updateNetworkSwitchPortSchedule(self, networkId: str, portScheduleId: str, *
return self._session.put(metadata, resource, payload)
+ def getNetworkSwitchPortsProfiles(self, networkId: str):
+ """
+ **List the port profiles in a network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-switch-ports-profiles
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "getNetworkSwitchPortsProfiles",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles"
+
+ return self._session.get(metadata, resource)
+
+ def createNetworkSwitchPortsProfile(self, networkId: str, **kwargs):
+ """
+ **Create a port profile in a network**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "createNetworkSwitchPortsProfile",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles"
+
+ body_params = [
+ "name",
+ "description",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateNetworkSwitchPortsProfile(self, networkId: str, id: str, **kwargs):
+ """
+ **Update a port profile in a network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - id (string): ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "updateNetworkSwitchPortsProfile",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteNetworkSwitchPortsProfile(self, networkId: str, id: str):
+ """
+ **Delete a port profile from a network**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "deleteNetworkSwitchPortsProfile",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getNetworkSwitchQosRules(self, networkId: str):
"""
**List quality of service rules**
@@ -1855,6 +2079,64 @@ def updateNetworkSwitchQosRule(self, networkId: str, qosRuleId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getNetworkSwitchRaGuardPolicy(self, networkId: str):
+ """
+ **Return RA Guard settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-switch-ra-guard-policy
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "raGuardPolicy"],
+ "operation": "getNetworkSwitchRaGuardPolicy",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/raGuardPolicy"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkSwitchRaGuardPolicy(self, networkId: str, **kwargs):
+ """
+ **Update RA Guard settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-ra-guard-policy
+
+ - networkId (string): Network ID
+ - defaultPolicy (string): New Router Advertisers are 'allowed' or 'blocked'. Default value is 'allowed'.
+ - allowedServers (array): List the MAC addresses of Router Advertisers to permit on the network when defaultPolicy is set to blocked.
+ - blockedServers (array): List the MAC addresses of Router Advertisers to block on the network when defaultPolicy is set to allowed.
+ """
+
+ kwargs.update(locals())
+
+ if "defaultPolicy" in kwargs:
+ options = ["allowed", "blocked"]
+ assert kwargs["defaultPolicy"] in options, (
+ f'''"defaultPolicy" cannot be "{kwargs["defaultPolicy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["switch", "configure", "raGuardPolicy"],
+ "operation": "updateNetworkSwitchRaGuardPolicy",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/raGuardPolicy"
+
+ body_params = [
+ "defaultPolicy",
+ "allowedServers",
+ "blockedServers",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchRaGuardPolicy: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSwitchRoutingMulticast(self, networkId: str):
"""
**Return multicast settings for a network**
@@ -2175,6 +2457,45 @@ def updateNetworkSwitchSettings(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkSwitchSpanningTree(self, networkId: str, **kwargs):
+ """
+ **Updates Spanning Tree configuration**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-spanning-tree
+
+ - networkId (string): Network ID
+ - enabled (boolean): Network-level spanning Tree enable
+ - mode (string): Catalyst Spanning Tree Protocol mode (mst, rpvst+)
+ - priorities (array): Spanning tree priority for switches/stacks or switch templates. An empty array will clear the priority settings.
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["mst", "rpvst+"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "spanningTree"],
+ "operation": "updateNetworkSwitchSpanningTree",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/spanningTree"
+
+ body_params = [
+ "enabled",
+ "mode",
+ "priorities",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchSpanningTree: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSwitchStacks(self, networkId: str):
"""
**List the switch stacks in a network**
@@ -2331,6 +2652,49 @@ def addNetworkSwitchStack(self, networkId: str, switchStackId: str, serial: str,
return self._session.post(metadata, resource, payload)
+ def updateNetworkSwitchStackPortsMirror(
+ self, networkId: str, switchStackId: str, source: dict, destination: dict, **kwargs
+ ):
+ """
+ **Update switch port mirrors for switch stacks**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-stack-ports-mirror
+
+ - networkId (string): Network ID
+ - switchStackId (string): Switch stack ID
+ - source (object): Source port details
+ - destination (object): Destination port Details
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "stacks", "ports", "mirror"],
+ "operation": "updateNetworkSwitchStackPortsMirror",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/ports/mirror"
+
+ body_params = [
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchStackPortsMirror: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def removeNetworkSwitchStack(self, networkId: str, switchStackId: str, serial: str, **kwargs):
"""
**Remove a switch from a stack**
@@ -2426,6 +2790,12 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -2461,6 +2831,12 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -2515,6 +2891,12 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -2547,6 +2929,12 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -2946,31 +3334,85 @@ def updateNetworkSwitchStp(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
- def getOrganizationConfigTemplateSwitchProfiles(self, organizationId: str, configTemplateId: str):
+ def getOrganizationConfigTemplatesSwitchProfilesPortsMirrorsBySwitchProfile(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **List the switch templates for your switch template configuration**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profiles
+ **list the port mirror configurations in an organization by switch profile**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-config-templates-switch-profiles-ports-mirrors-by-switch-profile
- organizationId (string): Organization ID
- - configTemplateId (string): Config template ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - configTemplateIds (array): Optional parameter to filter the result set by the included set of config template IDs
+ - ids (array): A list of switch profile ids. The returned profiles will be filtered to only include these ids.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
+ kwargs.update(locals())
+
metadata = {
- "tags": ["switch", "configure", "configTemplates", "profiles"],
- "operation": "getOrganizationConfigTemplateSwitchProfiles",
+ "tags": ["switch", "configure", "configTemplates", "profiles", "ports", "mirrors", "bySwitchProfile"],
+ "operation": "getOrganizationConfigTemplatesSwitchProfilesPortsMirrorsBySwitchProfile",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
- resource = f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles"
+ resource = f"/organizations/{organizationId}/configTemplates/switch/profiles/ports/mirrors/bySwitchProfile"
- return self._session.get(metadata, resource)
+ query_params = [
+ "configTemplateIds",
+ "ids",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def getOrganizationConfigTemplateSwitchProfilePorts(self, organizationId: str, configTemplateId: str, profileId: str):
- """
- **Return all the ports of a switch template**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profile-ports
+ array_params = [
+ "configTemplateIds",
+ "ids",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
- - organizationId (string): Organization ID
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationConfigTemplatesSwitchProfilesPortsMirrorsBySwitchProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationConfigTemplateSwitchProfiles(self, organizationId: str, configTemplateId: str):
+ """
+ **List the switch templates for your switch template configuration**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profiles
+
+ - organizationId (string): Organization ID
+ - configTemplateId (string): Config template ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "configTemplates", "profiles"],
+ "operation": "getOrganizationConfigTemplateSwitchProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationConfigTemplateSwitchProfilePorts(self, organizationId: str, configTemplateId: str, profileId: str):
+ """
+ **Return all the ports of a switch template**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profile-ports
+
+ - organizationId (string): Organization ID
- configTemplateId (string): Config template ID
- profileId (string): Profile ID
"""
@@ -2986,6 +3428,55 @@ def getOrganizationConfigTemplateSwitchProfilePorts(self, organizationId: str, c
return self._session.get(metadata, resource)
+ def updateOrganizationConfigTemplateSwitchProfilePortsMirror(
+ self, organizationId: str, configTemplateId: str, profileId: str, source: dict, destination: dict, **kwargs
+ ):
+ """
+ **Update a port mirror**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-config-template-switch-profile-ports-mirror
+
+ - organizationId (string): Organization ID
+ - configTemplateId (string): Config template ID
+ - profileId (string): Profile ID
+ - source (object): Source ports mirror configuration
+ - destination (object): Destination port mirror configuration
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "configTemplates", "profiles", "ports", "mirror"],
+ "operation": "updateOrganizationConfigTemplateSwitchProfilePortsMirror",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles/{profileId}/ports/mirror"
+ )
+
+ body_params = [
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationConfigTemplateSwitchProfilePortsMirror: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getOrganizationConfigTemplateSwitchProfilePort(
self, organizationId: str, configTemplateId: str, profileId: str, portId: str
):
@@ -3032,6 +3523,7 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
- vlan (integer): The VLAN of the switch template port. For a trunk port, this is the native VLAN. A null value will clear the value set for trunk ports.
- voiceVlan (integer): The voice VLAN of the switch template port. Only applicable to access ports.
- allowedVlans (string): The VLANs allowed on the switch template port. Only applicable to trunk ports.
+ - activeVlans (string): The VLANs that are active on the switch template port. Only applicable to trunk ports.
- isolationEnabled (boolean): The isolation status of the switch template port.
- rstpEnabled (boolean): The rapid spanning tree protocol status.
- stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard').
@@ -3094,6 +3586,7 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
"vlan",
"voiceVlan",
"allowedVlans",
+ "activeVlans",
"isolationEnabled",
"rstpEnabled",
"stpGuard",
@@ -3163,89 +3656,37 @@ def getOrganizationSummarySwitchPowerHistory(self, organizationId: str, **kwargs
return self._session.get(metadata, resource, params)
- def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str, targetSerials: list, **kwargs):
- """
- **Clone port-level and some switch-level configuration settings from a source switch to one or more target switches**
- https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-devices
-
- - organizationId (string): Organization ID
- - sourceSerial (string): Serial number of the source switch (must be on a network not bound to a template)
- - targetSerials (array): Array of serial numbers of one or more target switches (must be on a network not bound to a template)
- """
-
- kwargs = locals()
-
- metadata = {
- "tags": ["switch", "configure", "devices"],
- "operation": "cloneOrganizationSwitchDevices",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/devices/clone"
-
- body_params = [
- "sourceSerial",
- "targetSerials",
- ]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
-
- if self._session._validate_kwargs:
- all_params = [] + body_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(f"cloneOrganizationSwitchDevices: ignoring unrecognized kwargs: {invalid}")
-
- return self._session.post(metadata, resource, payload)
-
- def getOrganizationSwitchPortsBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationSwitchAlertsPoeByDevice(self, organizationId: str, networkIds: list, **kwargs):
"""
- **List the switchports in an organization by switch**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-by-switch
+ **Gets all poe related alerts over a given network and returns information by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-alerts-poe-by-device
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 50.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "configure", "ports", "bySwitch"],
- "operation": "getOrganizationSwitchPortsBySwitch",
+ "tags": ["switch", "monitor", "alerts", "poe", "byDevice"],
+ "operation": "getOrganizationSwitchAlertsPoeByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/bySwitch"
+ resource = f"/organizations/{organizationId}/switch/alerts/poe/byDevice"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
"networkIds",
- "portProfileIds",
- "serial",
- "serials",
+ "t0",
+ "t1",
+ "timespan",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
- "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3256,66 +3697,60 @@ def getOrganizationSwitchPortsBySwitch(self, organizationId: str, total_pages=1,
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationSwitchPortsBySwitch: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationSwitchAlertsPoeByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsClientsOverviewByDevice(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def aurora2OrganizationSwitchSwitchTemplates(self, organizationId: str):
"""
- **List the number of clients for all switchports with at least one online client in an organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-clients-overview-by-device
+ **List switch templates running IOS XE Catalyst firmware.**
+ https://developer.cisco.com/meraki/api-v1/#!aurora-2-organization-switch-switch-templates
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 20.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ metadata = {
+ "tags": ["switch", "configure"],
+ "operation": "aurora2OrganizationSwitchSwitchTemplates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/aurora2SwitchTemplates"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSwitchClientsConnectionsAuthenticationByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarizes authentication outcomes per switch client across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-clients-connections-authentication-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "clients", "overview", "byDevice"],
- "operation": "getOrganizationSwitchPortsClientsOverviewByDevice",
+ "tags": ["switch", "monitor", "clients", "connections", "authentication", "byClient"],
+ "operation": "getOrganizationSwitchClientsConnectionsAuthenticationByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/clients/overview/byDevice"
+ resource = f"/organizations/{organizationId}/switch/clients/connections/authentication/byClient"
query_params = [
+ "networkIds",
"t0",
+ "t1",
"timespan",
- "perPage",
- "startingAfter",
- "endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
- "networkIds",
- "portProfileIds",
- "serial",
- "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
- "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3327,96 +3762,89 @@ def getOrganizationSwitchPortsClientsOverviewByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationSwitchPortsClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationSwitchClientsConnectionsAuthenticationByClient: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsOverview(self, organizationId: str, **kwargs):
+ def getOrganizationSwitchClientsConnectionsDhcpByClient(self, organizationId: str, **kwargs):
"""
- **Returns the counts of all active ports for the requested timespan, grouped by speed**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-overview
+ **Get IP assignment for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-clients-connections-dhcp-by-client
- organizationId (string): Organization ID
- - t0 (string): The beginning of the timespan for the data.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 12 hours and be less than or equal to 186 days. The default is 1 day.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "overview"],
- "operation": "getOrganizationSwitchPortsOverview",
+ "tags": ["switch", "monitor", "clients", "connections", "dhcp", "byClient"],
+ "operation": "getOrganizationSwitchClientsConnectionsDhcpByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/overview"
+ resource = f"/organizations/{organizationId}/switch/clients/connections/dhcp/byClient"
query_params = [
+ "networkIds",
"t0",
"t1",
"timespan",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
if self._session._validate_kwargs:
- all_params = query_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationSwitchPortsOverview: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationSwitchClientsConnectionsDhcpByClient: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsStatusesBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationSwitchClientsConnectionsSwitchPortStatusByClient(self, organizationId: str, **kwargs):
"""
- **List the switchports in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-statuses-by-switch
+ **Switch port status by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-clients-connections-switch-port-status-by-client
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "statuses", "bySwitch"],
- "operation": "getOrganizationSwitchPortsStatusesBySwitch",
+ "tags": ["switch", "monitor", "clients", "connections", "switchPortStatus", "byClient"],
+ "operation": "getOrganizationSwitchClientsConnectionsSwitchPortStatusByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/statuses/bySwitch"
+ resource = f"/organizations/{organizationId}/switch/clients/connections/switchPortStatus/byClient"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
"networkIds",
- "portProfileIds",
- "serial",
- "serials",
+ "t0",
+ "t1",
+ "timespan",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
- "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3428,66 +3856,265 @@ def getOrganizationSwitchPortsStatusesBySwitch(self, organizationId: str, total_
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationSwitchPortsStatusesBySwitch: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationSwitchClientsConnectionsSwitchPortStatusByClient: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsTopologyDiscoveryByDevice(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def cloneOrganizationSwitchProfilesToTemplateNetwork(self, organizationId: str, **kwargs):
"""
- **List most recently seen LLDP/CDP discovery and topology information per switch port in an organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-topology-discovery-by-device
+ **Clone existing switch templates into a destination template network.**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-profiles-to-template-network
+
+ - organizationId (string): Organization ID
+ - profileIds (array): Switch profile IDs to clone
+ - templateNodeGroupId (string): Destination template network ID
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure"],
+ "operation": "cloneOrganizationSwitchProfilesToTemplateNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/cloneProfilesToTemplateNetwork"
+
+ body_params = [
+ "profileIds",
+ "templateNodeGroupId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"cloneOrganizationSwitchProfilesToTemplateNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchConnectivityLanLinkErrorsByDeviceByPort(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Lan link errors by device and port.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-connectivity-lan-link-errors-by-device-by-port
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "connectivity", "lanLink", "errors", "byDevice", "byPort"],
+ "operation": "getOrganizationSwitchConnectivityLanLinkErrorsByDeviceByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/connectivity/lanLink/errors/byDevice/byPort"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchConnectivityLanLinkErrorsByDeviceByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchConnectivityLanStpErrorsByDeviceByPort(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Lan STP errors by device and port.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-connectivity-lan-stp-errors-by-device-by-port
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "connectivity", "lanStp", "errors", "byDevice", "byPort"],
+ "operation": "getOrganizationSwitchConnectivityLanStpErrorsByDeviceByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/connectivity/lanStp/errors/byDevice/byPort"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchConnectivityLanStpErrorsByDeviceByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchConnectivityVrrpFailuresByDevice(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Gets all vrrp related alerts over a given network and returns information by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-connectivity-vrrp-failures-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "connectivity", "vrrp", "failures", "byDevice"],
+ "operation": "getOrganizationSwitchConnectivityVrrpFailuresByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/connectivity/vrrp/failures/byDevice"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchConnectivityVrrpFailuresByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str, targetSerials: list, **kwargs):
+ """
+ **Clone port-level and some switch-level configuration settings from a source switch to one or more target switches**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-devices
+
+ - organizationId (string): Organization ID
+ - sourceSerial (string): Serial number of the source switch (must be on a network not bound to a template)
+ - targetSerials (array): Array of serial numbers of one or more target switches (must be on a network not bound to a template)
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "devices"],
+ "operation": "cloneOrganizationSwitchDevices",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/devices/clone"
+
+ body_params = [
+ "sourceSerial",
+ "targetSerials",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"cloneOrganizationSwitchDevices: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchDevicesSystemQueuesHistoryBySwitchByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return a historical record of packet transmission and loss, broken down by protocol, for insight into switch device health.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-devices-system-queues-history-by-switch-by-interval
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
+ - networkIds (array): Optional parameter to filter connectivity history by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter connectivity history by switch.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "topology", "discovery", "byDevice"],
- "operation": "getOrganizationSwitchPortsTopologyDiscoveryByDevice",
+ "tags": ["switch", "monitor", "devices", "system", "queues", "history", "bySwitch", "byInterval"],
+ "operation": "getOrganizationSwitchDevicesSystemQueuesHistoryBySwitchByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/topology/discovery/byDevice"
+ resource = f"/organizations/{organizationId}/switch/devices/system/queues/history/bySwitch/byInterval"
query_params = [
- "t0",
- "timespan",
"perPage",
"startingAfter",
"endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
"networkIds",
- "portProfileIds",
- "serial",
"serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
"serials",
]
for k, v in kwargs.items():
@@ -3500,28 +4127,25 @@ def getOrganizationSwitchPortsTopologyDiscoveryByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationSwitchPortsTopologyDiscoveryByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationSwitchDevicesSystemQueuesHistoryBySwitchByInterval: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationSwitchPortsBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **List the historical usage and traffic data of switchports in an organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-usage-history-by-device-by-interval
+ **List the switchports in an organization by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-by-switch
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 50.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - extendedParams (boolean): Optional flag to return all of the switchport data vs smaller dataset
+ - hideDefaultPorts (boolean): Optional flag that, when true, will hide modular switchports that may not be connected to the device at the moment
+ - type (array): Optional parameter to filter switchports by type ('access', 'trunk', 'stack', 'routed', 'svl' or 'dad'). All types are selected if not supplied.
- configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
@@ -3535,20 +4159,19 @@ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "usage", "history", "byDevice", "byInterval"],
- "operation": "getOrganizationSwitchPortsUsageHistoryByDeviceByInterval",
+ "tags": ["switch", "configure", "ports", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsBySwitch",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/usage/history/byDevice/byInterval"
+ resource = f"/organizations/{organizationId}/switch/ports/bySwitch"
query_params = [
- "t0",
- "t1",
- "timespan",
- "interval",
"perPage",
"startingAfter",
"endingBefore",
+ "extendedParams",
+ "hideDefaultPorts",
+ "type",
"configurationUpdatedAfter",
"mac",
"macs",
@@ -3561,6 +4184,7 @@ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
+ "type",
"macs",
"networkIds",
"portProfileIds",
@@ -3575,8 +4199,3033 @@ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(
- f"getOrganizationSwitchPortsUsageHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ self._session._logger.warning(f"getOrganizationSwitchPortsBySwitch: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsClientsOverviewByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the number of clients for all switchports with at least one online client in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-clients-overview-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "clients", "overview", "byDevice"],
+ "operation": "getOrganizationSwitchPortsClientsOverviewByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/clients/overview/byDevice"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsMirrorsBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **list the port mirror configurations in an organization by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-mirrors-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): A list of serial numbers. The returned devices will be filtered to only include these serials.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "mirrors", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsMirrorsBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/mirrors/bySwitch"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsMirrorsBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsOverview(self, organizationId: str, **kwargs):
+ """
+ **Returns the counts of all active ports for the requested timespan, grouped by speed**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-overview
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 12 hours and be less than or equal to 186 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "overview"],
+ "operation": "getOrganizationSwitchPortsOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/overview"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSwitchPortsOverview: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchPortsProfiles(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the port profiles in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Return the port profiles for the specified network(s)
+ - formattedStaticAssignments (boolean): Returns the list of static switchports that are assigned to the switchport profile
+ - searchQuery (string): Optional parameter to filter the result set by the search query
+ - radiusProfileEnabled (boolean): Optional parameter. If true, only return port profiles with a radius profile enabled
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "getOrganizationSwitchPortsProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles"
+
+ query_params = [
+ "networkIds",
+ "formattedStaticAssignments",
+ "searchQuery",
+ "radiusProfileEnabled",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSwitchPortsProfiles: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfile(self, organizationId: str, **kwargs):
+ """
+ **Create a port profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - isOrganizationWide (boolean): The scope of the profile whether it is organization level or network level
+ - networks (object): The networks which are included/excluded in the profile
+ - networkId (string): The network identifier
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "createOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles"
+
+ body_params = [
+ "name",
+ "description",
+ "isOrganizationWide",
+ "networks",
+ "networkId",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def batchOrganizationSwitchPortsProfilesAssignmentsAssign(self, organizationId: str, items: list, **kwargs):
+ """
+ **Batch assign or unassign port profiles to switch ports**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-switch-ports-profiles-assignments-assign
+
+ - organizationId (string): Organization ID
+ - items (array): Array of assignment operations (max 100)
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "assignments"],
+ "operation": "batchOrganizationSwitchPortsProfilesAssignmentsAssign",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/batchAssign"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchOrganizationSwitchPortsProfilesAssignmentsAssign: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchPortsProfilesAssignmentsByPort(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profile assignments in an organization, grouped by port**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-assignments-by-port
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - profileIds (array): Filter by specific profile IDs
+ - serials (array): Filter by switch serials
+ - networkIds (array): Filter by network IDs
+ - templateIds (array): Filter by template (node_profile) IDs
+ - types (array): Filter by port type: switch, template
+ - assignmentTypes (array): Filter by assignment type: direct, template, exception
+ - isActive (boolean): Filter by assignment status. true: only ports with active assignments, showing only active assignments per port. false: only ports with inactive assignments, showing only inactive assignments per port. Omit: all ports with all assignment layers.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "assignments", "byPort"],
+ "operation": "getOrganizationSwitchPortsProfilesAssignmentsByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/byPort"
+
+ query_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ "templateIds",
+ "types",
+ "assignmentTypes",
+ "isActive",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ "templateIds",
+ "types",
+ "assignmentTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesAssignmentsByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsProfilesAssignmentsBySwitch(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profile assignments in an organization, grouped by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-assignments-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - profileIds (array): Filter by specific profile IDs
+ - serials (array): Filter by switch serials
+ - networkIds (array): Filter by network IDs
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "assignments", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsProfilesAssignmentsBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/bySwitch"
+
+ query_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesAssignmentsBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsProfilesAutomations(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **list the automation port profiles in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-automations
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - ids (array): Optional parameter to filter the result set by the included set of automation IDs
+ - networkIds (array): Optional parameter to filter the result set by the associated networks.
+ - isOrganizationWide (string): Optional parameter to filter the result set by automations org-wide flag.
+ - searchQuery (string): Optional parameter to filter the result set by the search query
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "getOrganizationSwitchPortsProfilesAutomations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations"
+
+ query_params = [
+ "ids",
+ "networkIds",
+ "isOrganizationWide",
+ "searchQuery",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ids",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesAutomations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, **kwargs):
+ """
+ **Create a port profile automation for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the port profile automation.
+ - description (string): Text describing the port profile automation.
+ - fallbackProfile (object): Configuration settings for port profile
+ - rules (array): Configuration settings for port profile automation rules
+ - assignedSwitchPorts (array): assigned switch ports
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "createOrganizationSwitchPortsProfilesAutomation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations"
+
+ body_params = [
+ "name",
+ "description",
+ "fallbackProfile",
+ "rules",
+ "assignedSwitchPorts",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchPortsProfilesAutomation: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile automation in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the port profile automation.
+ - description (string): Text describing the port profile automation.
+ - fallbackProfile (object): Configuration settings for port profile
+ - rules (array): Configuration settings for port profile automation rules
+ - assignedSwitchPorts (array): assigned switch ports
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "updateOrganizationSwitchPortsProfilesAutomation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "fallbackProfile",
+ "rules",
+ "assignedSwitchPorts",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSwitchPortsProfilesAutomation: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, id: str):
+ """
+ **Delete an automation port profile from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "deleteOrganizationSwitchPortsProfilesAutomation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsProfilesNetworksAssignments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Fetch all Network - Smart Port Profile associations for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-networks-assignments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of records per page
+ - page (integer): Page number
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "getOrganizationSwitchPortsProfilesNetworksAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments"
+
+ query_params = [
+ "perPage",
+ "page",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesNetworksAssignments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfilesNetworksAssignment(
+ self, organizationId: str, type: str, profile: dict, network: dict, **kwargs
+ ):
+ """
+ **Create Network and Smart Ports Profile association for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-networks-assignment
+
+ - organizationId (string): Organization ID
+ - type (string): Type of association
+ - profile (object): Smart Port Profile object
+ - network (object): Network object
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "createOrganizationSwitchPortsProfilesNetworksAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments"
+
+ body_params = [
+ "type",
+ "profile",
+ "network",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchPortsProfilesNetworksAssignment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate(self, organizationId: str, items: list, **kwargs):
+ """
+ **Batch Create Network and Smart Ports Profile associations for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-switch-ports-profiles-networks-assignments-create
+
+ - organizationId (string): Organization ID
+ - items (array): Array of network and profile associations
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/batchCreate"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete(self, organizationId: str, items: list, **kwargs):
+ """
+ **Bulk delete Network and Smart Port Profile associations**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-switch-ports-profiles-networks-assignments-delete
+
+ - organizationId (string): Organization ID
+ - items (array): Array of assignments to delete
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/bulkDelete"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfilesNetworksAssignment(self, organizationId: str, assignmentId: str):
+ """
+ **Delete Network and Smart Port profile association for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-networks-assignment
+
+ - organizationId (string): Organization ID
+ - assignmentId (string): Assignment ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "deleteOrganizationSwitchPortsProfilesNetworksAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ assignmentId = urllib.parse.quote(str(assignmentId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/{assignmentId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsProfilesOverviewByProfile(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profiles in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-overview-by-profile
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Return the port profiles for the specified network(s)
+ - formattedStaticAssignments (boolean): Returns the list of static switchports that are assgined to the switchport profile
+ - searchQuery (string): Optional parameter to filter the result set by the search query
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "overview", "byProfile"],
+ "operation": "getOrganizationSwitchPortsProfilesOverviewByProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/overview/byProfile"
+
+ query_params = [
+ "networkIds",
+ "formattedStaticAssignments",
+ "searchQuery",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesOverviewByProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsProfilesRadiusAssignments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profile RADIUS assignments**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-radius-assignments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): If present, the networks to limit the assignments to
+ - portProfileIds (array): If present, the port profiles to limit the assignments to
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "getOrganizationSwitchPortsProfilesRadiusAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments"
+
+ query_params = [
+ "networkIds",
+ "portProfileIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "portProfileIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesRadiusAssignments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, network: dict, **kwargs):
+ """
+ **Create a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - network (object): The network where the RADIUS name is assigned
+ - portProfile (object): The assigned port profile
+ - radius (object): The RADIUS options for this assignment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "createOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments"
+
+ body_params = [
+ "network",
+ "portProfile",
+ "radius",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchPortsProfilesRadiusAssignment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str):
+ """
+ **Return a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "getOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - network (object): The network where the RADIUS name is assigned
+ - portProfile (object): The assigned port profile
+ - radius (object): The RADIUS options for this assignment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "updateOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ body_params = [
+ "network",
+ "portProfile",
+ "radius",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSwitchPortsProfilesRadiusAssignment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str):
+ """
+ **Deletes a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "deleteOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsProfile(self, organizationId: str, id: str):
+ """
+ **Get detailed information about a port profile**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "getOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationSwitchPortsProfile(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - isOrganizationWide (boolean): The scope of the profile whether it is organization level or network level
+ - networks (object): The networks which are included/excluded in the profile
+ - networkId (string): The network identifier
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "updateOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "isOrganizationWide",
+ "networks",
+ "networkId",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfile(self, organizationId: str, id: str):
+ """
+ **Delete a port profile from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "deleteOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsStatusesBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the switchports in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-statuses-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "statuses", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsStatusesBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/statuses/bySwitch"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsStatusesBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsStatusesPacketsByDeviceByPort(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Switch port packets by device and port.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-statuses-packets-by-device-by-port
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 1200, 14400, 86400. The default is 14400. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "statuses", "packets", "byDevice", "byPort"],
+ "operation": "getOrganizationSwitchPortsStatusesPacketsByDeviceByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/statuses/packets/byDevice/byPort"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsStatusesPacketsByDeviceByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchPortsTopologyDiscoveryByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List most recently seen LLDP/CDP discovery and topology information per switch port in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-topology-discovery-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "topology", "discovery", "byDevice"],
+ "operation": "getOrganizationSwitchPortsTopologyDiscoveryByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/topology/discovery/byDevice"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsTopologyDiscoveryByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsTransceiversReadingsHistoryBySwitch(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return time-series digital optical monitoring (DOM) readings for ports on each DOM-enabled switch in an organization, in addition to thresholds for each relevant Small Form Factor Pluggable (SFP) module.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-transceivers-readings-history-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
+ - networkIds (array): Networks for which information should be gathered.
+ - serials (array): Optional parameter to filter usage by switch.
+ - portIds (array): Optional parameter to filter usage by port ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "transceivers", "readings", "history", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsTransceiversReadingsHistoryBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/transceivers/readings/history/bySwitch"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "serials",
+ "portIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "portIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsTransceiversReadingsHistoryBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the historical usage and traffic data of switchports in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-usage-history-by-device-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "usage", "history", "byDevice", "byInterval"],
+ "operation": "getOrganizationSwitchPortsUsageHistoryByDeviceByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/usage/history/byDevice/byInterval"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsUsageHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpAutonomousSystems(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the autonomous systems configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-autonomous-systems
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - numbers (array): Optional parameter to filter autonomous systems by number. This filter uses multiple exact matches.
+ - autonomousSystemIds (array): Optional parameter to filter autonomous systems by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "getOrganizationSwitchRoutingBgpAutonomousSystems",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpAutonomousSystems: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, number: int, **kwargs):
+ """
+ **Create an autonomous system**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - number (integer): The autonomous system number (CLI: 'router bgp ')
+ - description (string): A description for the autonomous system
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "createOrganizationSwitchRoutingBgpAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems"
+
+ body_params = [
+ "number",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpAutonomousSystem: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpAutonomousSystemsOverviewByAutonomousSystem(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the autonomous systems configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-autonomous-systems-overview-by-autonomous-system
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - numbers (array): Optional parameter to filter autonomous systems by number. This filter uses multiple exact matches.
+ - autonomousSystemIds (array): Optional parameter to filter autonomous systems by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems", "overview", "byAutonomousSystem"],
+ "operation": "getOrganizationSwitchRoutingBgpAutonomousSystemsOverviewByAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/overview/byAutonomousSystem"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpAutonomousSystemsOverviewByAutonomousSystem: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, autonomousSystemId: str, **kwargs):
+ """
+ **Update an autonomous system**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - autonomousSystemId (string): Autonomous system ID
+ - number (integer): The autonomous system number (CLI: 'router bgp ')
+ - description (string): A description for the autonomous system
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "updateOrganizationSwitchRoutingBgpAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ autonomousSystemId = urllib.parse.quote(str(autonomousSystemId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/{autonomousSystemId}"
+
+ body_params = [
+ "number",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSwitchRoutingBgpAutonomousSystem: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, autonomousSystemId: str):
+ """
+ **Delete an autonomous system from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - autonomousSystemId (string): Autonomous system ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "deleteOrganizationSwitchRoutingBgpAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ autonomousSystemId = urllib.parse.quote(str(autonomousSystemId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/{autonomousSystemId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingBgpFiltersFilterLists(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the filter lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-filter-lists
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter 'filter lists' by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter 'filter lists' by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersFilterLists",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersFilterLists: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy(
+ self, organizationId: str, filterList: dict, network: dict, rules: list, **kwargs
+ ):
+ """
+ **Create or update a filter list, in addition to its associated rules**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-filters-filter-lists-deploy
+
+ - organizationId (string): Organization ID
+ - filterList (object): Information regarding the filter list
+ - network (object): Information regarding the network the filter list belongs to
+ - rules (array): Information regarding the filter list rules
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/deploy"
+
+ body_params = [
+ "filterList",
+ "network",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpFiltersFilterListsOverviewByFilterList(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the filter lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-filter-lists-overview-by-filter-list
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter 'filter list' overviews by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter 'filter list' overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "filters", "filterLists", "overview", "byFilterList"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersFilterListsOverviewByFilterList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/overview/byFilterList"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersFilterListsOverviewByFilterList: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpFiltersFilterListsRules(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the filter list rules configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-filter-lists-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter 'filter list' rules by network ID. This filter uses multiple exact matches.
+ - ruleIds (array): Optional parameter to filter 'filter list' rules by ID. This filter uses multiple exact matches.
+ - filterListIds (array): Optional parameter to filter 'filter lists' by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists", "rules"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersFilterListsRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/rules"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "ruleIds",
+ "filterListIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "ruleIds",
+ "filterListIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersFilterListsRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationSwitchRoutingBgpFiltersFilterList(self, organizationId: str, listId: str):
+ """
+ **Delete a filter list**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-filters-filter-list
+
+ - organizationId (string): Organization ID
+ - listId (string): List ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists"],
+ "operation": "deleteOrganizationSwitchRoutingBgpFiltersFilterList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ listId = urllib.parse.quote(str(listId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/{listId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingBgpFiltersPrefixLists(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the prefix lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-prefix-lists
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter prefix lists by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter prefix lists by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersPrefixLists",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersPrefixLists: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy(
+ self, organizationId: str, network: dict, prefixList: dict, rules: list, **kwargs
+ ):
+ """
+ **Create or update a prefix list, in addition to its associated rules**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-filters-prefix-lists-deploy
+
+ - organizationId (string): Organization ID
+ - network (object): Information regarding the network the prefix list belongs to
+ - prefixList (object): Information regarding the prefix list
+ - rules (array): Information regarding the prefix list rules
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/deploy"
+
+ body_params = [
+ "network",
+ "prefixList",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpFiltersPrefixListsOverviewByPrefixList(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the prefix lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-prefix-lists-overview-by-prefix-list
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter prefix list overviews by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter prefix list overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "filters", "prefixLists", "overview", "byPrefixList"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersPrefixListsOverviewByPrefixList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/overview/byPrefixList"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersPrefixListsOverviewByPrefixList: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpFiltersPrefixListsRules(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the prefix list rules configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-prefix-lists-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter prefix list rules by network ID. This filter uses multiple exact matches.
+ - prefixListIds (array): Optional parameter to filter prefix list rules by prefix list ID. This filter uses multiple exact matches.
+ - ruleIds (array): Optional parameter to filter prefix list rules by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists", "rules"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersPrefixListsRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/rules"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "prefixListIds",
+ "ruleIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "prefixListIds",
+ "ruleIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersPrefixListsRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationSwitchRoutingBgpFiltersPrefixList(self, organizationId: str, listId: str):
+ """
+ **Delete a prefix list**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-filters-prefix-list
+
+ - organizationId (string): Organization ID
+ - listId (string): List ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists"],
+ "operation": "deleteOrganizationSwitchRoutingBgpFiltersPrefixList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ listId = urllib.parse.quote(str(listId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/{listId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingBgpPeersGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the BGP peer groups configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer groups by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter peer groups by router ID. This filter uses multiple exact matches.
+ - profileIds (array): Optional parameter to filter peer groups by profile ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer groups by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroups: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersGroupsAddressFamiliesDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for multiple peer groups or address families configured in the given organization, including profile information, peer group address family information, neighbors, and listen ranges**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups-address-families-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer group address family deployments by network ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer group address family deployments by peer group
+ - addressFamilyIds (array): Optional parameter to filter peer group address family deployments by address family
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups", "addressFamilies", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroupsAddressFamiliesDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/addressFamilies/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "peerGroupIds",
+ "addressFamilyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "peerGroupIds",
+ "addressFamilyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroupsAddressFamiliesDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpPeersGroupsDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ network: dict,
+ peerGroup: dict,
+ peerGroupAddressFamilyBindingProfile: dict,
+ peerGroupProfile: dict,
+ policies: list,
+ router: dict,
+ **kwargs,
+ ):
+ """
+ **Create or update a peer group, in addition to an associated peer group profile, peer group address family binding, peer group address family binding profile and routing policies associated with the peer group**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-peers-groups-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family the peer group address family binding belongs to
+ - network (object): Information regarding the network the peer group profile belongs to
+ - peerGroup (object): Information regarding the peer group
+ - peerGroupAddressFamilyBindingProfile (object): Information regarding the peer group address family binding profile
+ - peerGroupProfile (object): Information regarding the peer group profile
+ - policies (array): Information regarding the routing policies
+ - router (object): Information regarding the router this peer group belongs to
+ - peerGroupAddressFamilyBinding (object): Information regarding the peer group address family binding. Only required when updating.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpPeersGroupsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/deploy"
+
+ body_params = [
+ "addressFamily",
+ "network",
+ "peerGroup",
+ "peerGroupAddressFamilyBinding",
+ "peerGroupAddressFamilyBindingProfile",
+ "peerGroupProfile",
+ "policies",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpPeersGroupsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpPeersGroupsDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for peer groups configured in the given organization, including peer group address family information, as well as routing policies**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer group deployments by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter peer group deployments by router ID. This filter uses multiple exact matches.
+ - profileIds (array): Optional parameter to filter peer group deployments by profile ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer group deployments by peer group ID. This filter uses multiple exact matches.
+ - afi (string): Optional parameter to filter deployments on each peer group by address family identifier (AFI).
+ - safi (string): Optional parameter to filter deployments on each peer group by subsequent address family identifier (SAFI).
+ """
+
+ kwargs.update(locals())
+
+ if "afi" in kwargs:
+ options = ["ipv4"]
+ assert kwargs["afi"] in options, f'''"afi" cannot be "{kwargs["afi"]}", & must be set to one of: {options}'''
+ if "safi" in kwargs:
+ options = ["unicast"]
+ assert kwargs["safi"] in options, f'''"safi" cannot be "{kwargs["safi"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroupsDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ "afi",
+ "safi",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroupsDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersGroupsOverviewByPeerGroup(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the BGP peer groups configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups-overview-by-peer-group
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer group overviews by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter peer group overviews by router ID. This filter uses multiple exact matches.
+ - profileIds (array): Optional parameter to filter peer group overviews by profile ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer group overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "peers", "groups", "overview", "byPeerGroup"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroupsOverviewByPeerGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/overview/byPeerGroup"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroupsOverviewByPeerGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersListenRanges(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the listen ranges configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-listen-ranges
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter listen ranges by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter listen ranges by router ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter listen ranges by peer group ID. This filter uses multiple exact matches.
+ - listenRangeIds (array): Optional parameter to filter listen ranges by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "listenRanges"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersListenRanges",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/listenRanges"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "peerGroupIds",
+ "listenRangeIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "peerGroupIds",
+ "listenRangeIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersListenRanges: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersNeighbors(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the neighbors configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-neighbors
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter neighbors by network ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter neighbors by peer group ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter neighbors by router ID. This filter uses multiple exact matches.
+ - neighborIds (array): Optional parameter to filter neighbors by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "neighbors"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersNeighbors",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersNeighbors: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpPeersNeighborsDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ neighbor: dict,
+ neighborAddressFamilyBinding: dict,
+ peerGroup: dict,
+ policies: list,
+ router: dict,
+ **kwargs,
+ ):
+ """
+ **Create or update a neighor, in addition to an associated neighbor address family binding and routing policies associated with the neighbor**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-peers-neighbors-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family this binding is bound to
+ - neighbor (object): Information regarding the BPG neighbor
+ - neighborAddressFamilyBinding (object): Information regarding the neighbor address family binding
+ - peerGroup (object): Information regarding the peer group this neighbor belongs to
+ - policies (array): Information regarding the routing policies related to the neighbor
+ - router (object): Information regarding the router this neighbor peers with
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "neighbors", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpPeersNeighborsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors/deploy"
+
+ body_params = [
+ "addressFamily",
+ "neighbor",
+ "neighborAddressFamilyBinding",
+ "peerGroup",
+ "policies",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpPeersNeighborsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpPeersNeighborsDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for neighbors configured in the given organization, including address family information, as well as routing policies**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-neighbors-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter neighbor deployments by network ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter neighbor deployments by peer group ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter neighbor deployments by router ID. This filter uses multiple exact matches.
+ - neighborIds (array): Optional parameter to filter neighbor deployments by neighbor ID. This filter uses multiple exact matches.
+ - afi (string): Optional parameter to filter deployments on each neighbor by address family identifier (AFI).
+ - safi (string): Optional parameter to filter deployments on each neighbor by subsequent address family identifier (SAFI).
+ """
+
+ kwargs.update(locals())
+
+ if "afi" in kwargs:
+ options = ["ipv4"]
+ assert kwargs["afi"] in options, f'''"afi" cannot be "{kwargs["afi"]}", & must be set to one of: {options}'''
+ if "safi" in kwargs:
+ options = ["unicast"]
+ assert kwargs["safi"] in options, f'''"safi" cannot be "{kwargs["safi"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "neighbors", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersNeighborsDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ "afi",
+ "safi",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersNeighborsDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpRouters(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the routers configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-routers
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter routers by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter routers by serial. This filter uses multiple exact matches.
+ - switchNames (array): Optional parameter to filter routers by switch name. The filter uses multiple exact matches.
+ - asNumbers (array): Optional parameter to filter routers by autonomous system number. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter routers by ID. This filter uses multiple exact matches.
+ - switchStackIds (array): Optional parameter to filter routers by switch stack id. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers"],
+ "operation": "getOrganizationSwitchRoutingBgpRouters",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpRouters: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpRoutersDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ addressFamilyPrefixes: list,
+ addressFamilyProfile: dict,
+ autonomousSystem: dict,
+ router: dict,
+ switch: dict,
+ **kwargs,
+ ):
+ """
+ **Create a BGP router, in addition to an associated address family, address family prefixes, and address family profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-routers-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family
+ - addressFamilyPrefixes (array): The list of network prefixes to which the address family applies
+ - addressFamilyProfile (object): Information regarding the profile applied to the address family
+ - autonomousSystem (object): Information regarding the router's autonomous system
+ - router (object): Information regarding the BPG router
+ - switch (object): The router's switch node. When the router is part of a switch stack, this is the switch stack's active node
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpRoutersDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/deploy"
+
+ body_params = [
+ "addressFamily",
+ "addressFamilyPrefixes",
+ "addressFamilyProfile",
+ "autonomousSystem",
+ "router",
+ "switch",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpRoutersDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpRoutersDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for routers configured in a given organization, including all address families**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-routers-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter router deployments by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter router deployments by serial. This filter uses multiple exact matches.
+ - switchNames (array): Optional parameter to filter router deployments by switch name. The filter uses multiple exact matches.
+ - asNumbers (array): Optional parameter to filter router deployments by autonomous system number. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter router deployments by router ID. This filter uses multiple exact matches.
+ - switchStackIds (array): Optional parameter to filter router deployments by switch stack id. This filter uses multiple exact matches.
+ - afi (string): Optional parameter to filter deployments on each router by address family identifier (AFI).
+ - safi (string): Optional parameter to filter deployments on each router by subsequent address family identifier (SAFI).
+ """
+
+ kwargs.update(locals())
+
+ if "afi" in kwargs:
+ options = ["ipv4"]
+ assert kwargs["afi"] in options, f'''"afi" cannot be "{kwargs["afi"]}", & must be set to one of: {options}'''
+ if "safi" in kwargs:
+ options = ["unicast"]
+ assert kwargs["safi"] in options, f'''"safi" cannot be "{kwargs["safi"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpRoutersDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ "afi",
+ "safi",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpRoutersDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpRoutersOverviewByRouter(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the routers configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-routers-overview-by-router
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter router overviews by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter router overviews by serial. This filter uses multiple exact matches.
+ - switchNames (array): Optional parameter to filter router overviews by switch name. This filter uses multiple exact matches.
+ - asNumbers (array): Optional parameter to filter router overviews by autonomous system number. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter router overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "routers", "overview", "byRouter"],
+ "operation": "getOrganizationSwitchRoutingBgpRoutersOverviewByRouter",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/overview/byRouter"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpRoutersOverviewByRouter: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpRoutersPeersDeploy(
+ self, organizationId: str, addressFamily: dict, peerGroups: list, router: dict, **kwargs
+ ):
+ """
+ **Create and update listen ranges, update peers' enabled flag, and delete peer groups for a BGP router**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-routers-peers-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family
+ - peerGroups (array): Information regarding the peer group peers for a router's peer group
+ - router (object): Information regarding the BPG router
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers", "peers", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpRoutersPeersDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/peers/deploy"
+
+ body_params = [
+ "addressFamily",
+ "peerGroups",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpRoutersPeersDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationSwitchRoutingBgpRouter(self, organizationId: str, routerId: str):
+ """
+ **Delete a router from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-router
+
+ - organizationId (string): Organization ID
+ - routerId (string): Router ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers"],
+ "operation": "deleteOrganizationSwitchRoutingBgpRouter",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ routerId = urllib.parse.quote(str(routerId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/{routerId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingStaticRoutes(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List layer 3 static routes for switches within an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-static-routes
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "staticRoutes"],
+ "operation": "getOrganizationSwitchRoutingStaticRoutes",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/staticRoutes"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingStaticRoutes: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchSpanningTree(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns Spanning Tree configuration settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-spanning-tree
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "spanningTree"],
+ "operation": "getOrganizationSwitchSpanningTree",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/spanningTree"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSwitchSpanningTree: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchStacksPortsMirrorsByStack(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the port mirror configurations in an organization by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-stacks-ports-mirrors-by-stack
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - ids (array): Return the port mirror configuration for the specified stack(s)
+ - networkIds (array): Return the port mirror configurations for the specified network(s)
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "stacks", "ports", "mirrors", "byStack"],
+ "operation": "getOrganizationSwitchStacksPortsMirrorsByStack",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/stacks/ports/mirrors/byStack"
+
+ query_params = [
+ "ids",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ids",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchStacksPortsMirrorsByStack: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
diff --git a/meraki/aio/api/users.py b/meraki/aio/api/users.py
new file mode 100644
index 00000000..c65a5ecb
--- /dev/null
+++ b/meraki/aio/api/users.py
@@ -0,0 +1,838 @@
+import urllib
+
+
+class AsyncUsers:
+ def __init__(self, session):
+ super().__init__()
+ self._session = session
+
+ def getOrganizationIamUsersAuthorizations(
+ self, organizationId: str, userIds: list, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List specific authorizations for the list of Meraki end users.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-authorizations
+
+ - organizationId (string): Organization ID
+ - userIds (array): Meraki end user IDs
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "getOrganizationIamUsersAuthorizations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "userIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "userIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersAuthorizations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationIamUsersAuthorization(self, organizationId: str, authZone: dict, **kwargs):
+ """
+ **Authorize a Meraki end user for an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-authorization
+
+ - organizationId (string): Organization ID
+ - authZone (object): Auth zone
+ - email (string): Meraki end user's email
+ - idpUserId (string): Meraki end user's ID
+ - startsAt (string): Start time of the desired access for the authorization. Defaults to now.
+ - expiresAt (string): Expiration time of the desired access for the authorization
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "createOrganizationIamUsersAuthorization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ body_params = [
+ "email",
+ "idpUserId",
+ "authZone",
+ "startsAt",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationIamUsersAuthorization: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationIamUsersAuthorizations(self, organizationId: str, **kwargs):
+ """
+ **Update a Meraki end user's access to an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-authorizations
+
+ - organizationId (string): Organization ID
+ - authorizationId (string): Authorization ID
+ - email (string): Meraki end user's email
+ - authZone (object): Auth zone
+ - startsAt (string): Start time of the desired access for the authorization
+ - expiresAt (string): Expiration time of the desired access for the authorization
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "updateOrganizationIamUsersAuthorizations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ body_params = [
+ "authorizationId",
+ "email",
+ "authZone",
+ "startsAt",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationIamUsersAuthorizations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def revokeOrganizationIamUsersAuthorizationsAuthorization(self, organizationId: str, authZone: dict, **kwargs):
+ """
+ **Revoke a Meraki end user's access to an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-organization-iam-users-authorizations-authorization
+
+ - organizationId (string): Organization ID
+ - authZone (object): Auth zone
+ - email (string): Meraki end user's email
+ - authorizationId (string): Authorization ID
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations", "authorization"],
+ "operation": "revokeOrganizationIamUsersAuthorizationsAuthorization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/authorization/revoke"
+
+ body_params = [
+ "email",
+ "authorizationId",
+ "authZone",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"revokeOrganizationIamUsersAuthorizationsAuthorization: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersAuthorizationsZones(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List all of the available auth zones for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-authorizations-zones
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 10 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations", "zones"],
+ "operation": "getOrganizationIamUsersAuthorizationsZones",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/zones"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersAuthorizationsZones: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationIamUsersAuthorization(self, organizationId: str, authorizationId: str):
+ """
+ **Delete an authorization for a Meraki end user.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-authorization
+
+ - organizationId (string): Organization ID
+ - authorizationId (string): Authorization ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "deleteOrganizationIamUsersAuthorization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ authorizationId = urllib.parse.quote(str(authorizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/{authorizationId}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationIamUsersIdp(self, organizationId: str, name: str, type: str, idpConfig: dict, **kwargs):
+ """
+ **Create an identity provider for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the identity provider
+ - type (string): Type of the identity provider
+ - idpConfig (object): Identity provider configuration. Required for external identity providers.
+ - description (string): Optional. Description of the identity provider
+ - syncType (string): The synchronization method for the identity provider. Set to 'proactive' to sync all users and groups from your identity provider.
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["Azure AD"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+ if "syncType" in kwargs and kwargs["syncType"] is not None:
+ options = ["proactive"]
+ assert kwargs["syncType"] in options, (
+ f'''"syncType" cannot be "{kwargs["syncType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "createOrganizationIamUsersIdp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps"
+
+ body_params = [
+ "name",
+ "type",
+ "description",
+ "idpConfig",
+ "syncType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def searchOrganizationIdpGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Search all IdP groups for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!search-organization-idp-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - idpIds (array): Filter IdP groups by IdP ID(s). Multiple IdP IDs can be passed as a comma separated list.
+ - authZone (object): Auth zone
+ - searchQuery (string): Fuzzy filter by group name
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "groups", "search"],
+ "operation": "searchOrganizationIdpGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/groups/search"
+
+ body_params = [
+ "idpIds",
+ "authZone",
+ "searchQuery",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"searchOrganizationIdpGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersIdpsProductIntegrations(self, organizationId: str):
+ """
+ **List all available IdP Product Integration urls for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idps-product-integrations
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "productIntegrations"],
+ "operation": "getOrganizationIamUsersIdpsProductIntegrations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/productIntegrations"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationIamUsersIdpsSearch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Search all IdPs for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-search
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - idpIds (array): Filter identity providers by id(s). Multiple ids can be passed as a comma separated list.
+ - type (string): Filter identity providers by idp type.
+ - authZone (object): Filter by auth zone
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["Azure AD"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "search"],
+ "operation": "createOrganizationIamUsersIdpsSearch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/search"
+
+ body_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "idpIds",
+ "type",
+ "authZone",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdpsSearch: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersIdpsSyncHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get the IdP sync status records for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idps-sync-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - idpId (string): Identity provider ID. Optional.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync", "history"],
+ "operation": "getOrganizationIamUsersIdpsSyncHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/sync/history"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "idpId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersIdpsSyncHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationIamUsersIdpsSyncLatest(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get the latest IdP sync status records for all IdPs in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idps-sync-latest
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - idpIds (array): Identity provider IDs. Optional.
+ - authZoneId (string): Auth Zone ID
+ - authZoneType (string): Auth Zone type
+ """
+
+ kwargs.update(locals())
+
+ if "authZoneType" in kwargs:
+ options = ["access_policy", "node_group", "product", "ssid"]
+ assert kwargs["authZoneType"] in options, (
+ f'''"authZoneType" cannot be "{kwargs["authZoneType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync", "latest"],
+ "operation": "getOrganizationIamUsersIdpsSyncLatest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/sync/latest"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "idpIds",
+ "authZoneId",
+ "authZoneType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "idpIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersIdpsSyncLatest: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationIamUsersIdpsTestConnectivity(self, organizationId: str, **kwargs):
+ """
+ **Test connectivity to an Entra ID identity provider.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-test-connectivity
+
+ - organizationId (string): Organization ID
+ - idpId (string): Id of the identity provider
+ - idpConfig (object): Identity provider configuration. Required for external identity providers.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "testConnectivity"],
+ "operation": "createOrganizationIamUsersIdpsTestConnectivity",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/testConnectivity"
+
+ body_params = [
+ "idpId",
+ "idpConfig",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationIamUsersIdpsTestConnectivity: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationIamUsersIdpsUser(self, organizationId: str, **kwargs):
+ """
+ **Create a Meraki user**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - displayName (string): A human-readable identifier for the created user.
+ - email (string): An email address identified with the user.
+ - password (string): The password for the user account.
+ - sendPassword (boolean): If true, sends an email with the password to the user.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "createOrganizationIamUsersIdpsUser",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users"
+
+ body_params = [
+ "displayName",
+ "email",
+ "password",
+ "sendPassword",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdpsUser: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationIamUsersIdpsUser(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a Meraki user**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - displayName (string): A human-readable identifier for the created user.
+ - email (string): An email address identified with the user.
+ - password (string): The password for the user account.
+ - sendPassword (boolean): If true, sends an email with the password to the user.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "updateOrganizationIamUsersIdpsUser",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users/{id}"
+
+ body_params = [
+ "displayName",
+ "email",
+ "password",
+ "sendPassword",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationIamUsersIdpsUser: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationIamUsersIdpsUser(self, organizationId: str, id: str):
+ """
+ **Delete a Meraki end user**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "deleteOrganizationIamUsersIdpsUser",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationIamUsersIdpSync(self, organizationId: str, idpId: str, **kwargs):
+ """
+ **Trigger an IdP sync for an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idp-sync
+
+ - organizationId (string): Organization ID
+ - idpId (string): Idp ID
+ - emails (array): List of emails to sync
+ - force (boolean): Force a complete sync of all users and groups
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync"],
+ "operation": "createOrganizationIamUsersIdpSync",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{idpId}/sync"
+
+ body_params = [
+ "emails",
+ "force",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdpSync: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersIdpSyncLatest(self, organizationId: str, idpId: str):
+ """
+ **Get the latest IdP sync status for an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idp-sync-latest
+
+ - organizationId (string): Organization ID
+ - idpId (string): Idp ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync", "latest"],
+ "operation": "getOrganizationIamUsersIdpSyncLatest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{idpId}/sync/latest"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationIamUsersIdp(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the identity provider
+ - description (string): Description of the identity provider
+ - idpConfig (object): Identity provider configuration. You can update individual attributes
+ - syncType (string): The synchronization method for the identity provider. Set to 'proactive' to sync all users and groups from your identity provider. Set to 'null' for on-demand user and group provisioning.
+ """
+
+ kwargs.update(locals())
+
+ if "syncType" in kwargs and kwargs["syncType"] is not None:
+ options = ["proactive"]
+ assert kwargs["syncType"] in options, (
+ f'''"syncType" cannot be "{kwargs["syncType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "updateOrganizationIamUsersIdp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "idpConfig",
+ "syncType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationIamUsersIdp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationIamUsersIdp(self, organizationId: str, id: str):
+ """
+ **Delete a identity provider from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "deleteOrganizationIamUsersIdp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationIamUsersIdpAuthZones(self, organizationId: str, id: str):
+ """
+ **List all auth zones for an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idp-auth-zones
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "authZones"],
+ "operation": "getOrganizationIamUsersIdpAuthZones",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}/authZones"
+
+ return self._session.get(metadata, resource)
+
+ def searchOrganizationUsers(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the end users and their associated identity providers for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!search-organization-users
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - userIds (array): Filter end users by id(s).
+ - idpIds (array): Filter by identity provider id(s).
+ - groupIds (array): Filter by identity provider group id(s).
+ - accessTypes (array): Filter by access type(s).
+ - searchQuery (string): Fuzzy filter by display name, user name and email.
+ - statuses (array): Filter by user status(es).
+ - sortKey (string): Optional parameter to specify the field used to sort results. (default: username)
+ - sortOrder (string): Optional parameter to specify the sort order. (default: asc)
+ """
+
+ kwargs.update(locals())
+
+ if "sortKey" in kwargs:
+ options = ["created_at", "updated_at", "username"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "search"],
+ "operation": "searchOrganizationUsers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/search"
+
+ body_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "userIds",
+ "idpIds",
+ "groupIds",
+ "accessTypes",
+ "searchQuery",
+ "statuses",
+ "sortKey",
+ "sortOrder",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"searchOrganizationUsers: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersSummaryPanel(self, organizationId: str):
+ """
+ **Get the count of users and user groups for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-summary-panel
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "summaryPanel"],
+ "operation": "getOrganizationIamUsersSummaryPanel",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/summaryPanel"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/aio/api/wireless.py b/meraki/aio/api/wireless.py
index b9ece30d..756d9819 100644
--- a/meraki/aio/api/wireless.py
+++ b/meraki/aio/api/wireless.py
@@ -68,6 +68,7 @@ def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs):
Dashboard's automatically generated value.
- minor (integer): Desired minor value of the beacon. If the value is set to null it will reset to
Dashboard's automatically generated value.
+ - transmit (object): Transmit settings including power, interval, and advertised power.
"""
kwargs.update(locals())
@@ -83,6 +84,7 @@ def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs):
"uuid",
"major",
"minor",
+ "transmit",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -196,6 +198,23 @@ def updateDeviceWirelessElectronicShelfLabel(self, serial: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getDeviceWirelessHealthScores(self, serial: str):
+ """
+ **Fetch the health scores for a given AP on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-health-scores
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "healthScores"],
+ "operation": "getDeviceWirelessHealthScores",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getDeviceWirelessLatencyStats(self, serial: str, **kwargs):
"""
**Aggregated latency info for a given AP on this network**
@@ -248,6 +267,123 @@ def getDeviceWirelessLatencyStats(self, serial: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getDeviceWirelessRadioAfcPosition(self, serial: str):
+ """
+ **Return the position for a wireless device**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-afc-position
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "position"],
+ "operation": "getDeviceWirelessRadioAfcPosition",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/position"
+
+ return self._session.get(metadata, resource)
+
+ def updateDeviceWirelessRadioAfcPosition(self, serial: str, **kwargs):
+ """
+ **Update the position attributes for this device**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-wireless-radio-afc-position
+
+ - serial (string): Serial
+ - height (object): Height attributes
+ - gps (object): GPS attributes
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "position"],
+ "operation": "updateDeviceWirelessRadioAfcPosition",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/position"
+
+ body_params = [
+ "height",
+ "gps",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceWirelessRadioAfcPosition: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getDeviceWirelessRadioAfcPowerLimits(self, serial: str):
+ """
+ **Return the AFC power limits for a wireless device**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-afc-power-limits
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "powerLimits"],
+ "operation": "getDeviceWirelessRadioAfcPowerLimits",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/powerLimits"
+
+ return self._session.get(metadata, resource)
+
+ def getDeviceWirelessRadioOverrides(self, serial: str):
+ """
+ **Return the radio overrides of a device**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-overrides
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "overrides"],
+ "operation": "getDeviceWirelessRadioOverrides",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/overrides"
+
+ return self._session.get(metadata, resource)
+
+ def updateDeviceWirelessRadioOverrides(self, serial: str, **kwargs):
+ """
+ **Update 2.4 GHz, 5 GHz, and 6 GHz radio settings (channel, channel width, power, and enable/disable) that override RF profiles.**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-wireless-radio-overrides
+
+ - serial (string): Serial
+ - rfProfile (object): This device's RF profile
+ - radios (array): Radio overrides.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "overrides"],
+ "operation": "updateDeviceWirelessRadioOverrides",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/overrides"
+
+ body_params = [
+ "rfProfile",
+ "radios",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceWirelessRadioOverrides: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getDeviceWirelessRadioSettings(self, serial: str):
"""
**Return the manually configured radio settings overrides of a device, which take precedence over RF profiles.**
@@ -300,6 +436,23 @@ def updateDeviceWirelessRadioSettings(self, serial: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getDeviceWirelessRadioStatus(self, serial: str):
+ """
+ **Show the status of this device's radios**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-status
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "status"],
+ "operation": "getDeviceWirelessRadioStatus",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/status"
+
+ return self._session.get(metadata, resource)
+
def getDeviceWirelessStatus(self, serial: str):
"""
**Return the SSID statuses of an access point**
@@ -655,6 +808,7 @@ def updateNetworkWirelessBluetoothSettings(self, networkId: str, **kwargs):
- majorMinorAssignmentMode (string): The way major and minor number should be assigned to nodes in the network. ('Unique', 'Non-unique')
- major (integer): The major number to be used in the beacon identifier. Only valid in 'Non-unique' mode.
- minor (integer): The minor number to be used in the beacon identifier. Only valid in 'Non-unique' mode.
+ - transmit (object): Transmit settings.
"""
kwargs.update(locals())
@@ -679,6 +833,7 @@ def updateNetworkWirelessBluetoothSettings(self, networkId: str, **kwargs):
"majorMinorAssignmentMode",
"major",
"minor",
+ "transmit",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -848,6 +1003,23 @@ def getNetworkWirelessClientsConnectionStats(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessClientsHealthScores(self, networkId: str):
+ """
+ **Fetch the health scores for all clients on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-clients-health-scores
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "healthScores"],
+ "operation": "getNetworkWirelessClientsHealthScores",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getNetworkWirelessClientsLatencyStats(self, networkId: str, **kwargs):
"""
**Aggregated latency info for this network, grouped by clients**
@@ -902,6 +1074,53 @@ def getNetworkWirelessClientsLatencyStats(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessClientsOnboardingHistory(self, networkId: str, **kwargs):
+ """
+ **Return counts of distinct wireless clients connecting to a network over time**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-clients-onboarding-history
+
+ - networkId (string): Network ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
+ - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 300. The default is 300.
+ - band (string): Filter results by band (either '2.4', '5' or '6'); this cannot be combined with the SSID filter.
+ - ssid (integer): Filter results by SSID number; this cannot be combined with the band filter.
+ """
+
+ kwargs.update(locals())
+
+ if "band" in kwargs:
+ options = ["2.4", "5", "6"]
+ assert kwargs["band"] in options, f'''"band" cannot be "{kwargs["band"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "onboardingHistory"],
+ "operation": "getNetworkWirelessClientsOnboardingHistory",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/onboardingHistory"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "resolution",
+ "band",
+ "ssid",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkWirelessClientsOnboardingHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
def getNetworkWirelessClientConnectionStats(self, networkId: str, clientId: str, **kwargs):
"""
**Aggregated connectivity info for a given client on this network**
@@ -1038,6 +1257,25 @@ def getNetworkWirelessClientConnectivityEvents(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getNetworkWirelessClientHealthScores(self, networkId: str, clientId: str):
+ """
+ **Fetch the health scores for a given client on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-client-health-scores
+
+ - networkId (string): Network ID
+ - clientId (string): Client ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "healthScores"],
+ "operation": "getNetworkWirelessClientHealthScores",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/{clientId}/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getNetworkWirelessClientLatencyHistory(self, networkId: str, clientId: str, **kwargs):
"""
**Return the latency history for a client**
@@ -1133,6 +1371,53 @@ def getNetworkWirelessClientLatencyStats(self, networkId: str, clientId: str, **
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessClientRoamingHistory(self, networkId: str, clientId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get client roam events within the specified timespan.**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-client-roaming-history
+
+ - networkId (string): Network ID
+ - clientId (string): Client ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "roaming", "history"],
+ "operation": "getNetworkWirelessClientRoamingHistory",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/{clientId}/roaming/history"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkWirelessClientRoamingHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getNetworkWirelessConnectionStats(self, networkId: str, **kwargs):
"""
**Aggregated connectivity info for this network**
@@ -1284,6 +1569,23 @@ def getNetworkWirelessDevicesConnectionStats(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessDevicesHealthScores(self, networkId: str):
+ """
+ **Fetch the health scores of all APs on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-devices-health-scores
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "healthScores"],
+ "operation": "getNetworkWirelessDevicesHealthScores",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/devices/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getNetworkWirelessDevicesLatencyStats(self, networkId: str, **kwargs):
"""
**Aggregated latency info for this network, grouped by node**
@@ -1439,6 +1741,7 @@ def createNetworkWirelessEthernetPortsProfile(self, networkId: str, name: str, p
- name (string): AP port profile name
- ports (array): AP ports configuration
- usbPorts (array): AP usb ports configuration
+ - security (object): AP port security configuration
"""
kwargs.update(locals())
@@ -1454,6 +1757,7 @@ def createNetworkWirelessEthernetPortsProfile(self, networkId: str, name: str, p
"name",
"ports",
"usbPorts",
+ "security",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1564,6 +1868,7 @@ def updateNetworkWirelessEthernetPortsProfile(self, networkId: str, profileId: s
- name (string): AP port profile name
- ports (array): AP ports configuration
- usbPorts (array): AP usb ports configuration
+ - security (object): AP port security configuration
"""
kwargs.update(locals())
@@ -1580,6 +1885,7 @@ def updateNetworkWirelessEthernetPortsProfile(self, networkId: str, profileId: s
"name",
"ports",
"usbPorts",
+ "security",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1811,6 +2117,41 @@ def updateNetworkWirelessLocationScanning(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkWirelessLocationWayfinding(self, networkId: str, **kwargs):
+ """
+ **Change client wayfinding settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-location-wayfinding
+
+ - networkId (string): Network ID
+ - enabled (boolean): Whether to enable client wayfinding on that network (only supported on Wireless networks).
+ - maintenanceWindow (object): Maintenance window during which optimization might take place to improve location accuracy.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "wayfinding"],
+ "operation": "updateNetworkWirelessLocationWayfinding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/location/wayfinding"
+
+ body_params = [
+ "enabled",
+ "maintenanceWindow",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkWirelessLocationWayfinding: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkWirelessMeshStatuses(self, networkId: str, total_pages=1, direction="next", **kwargs):
"""
**List wireless mesh statuses for repeaters**
@@ -1848,32 +2189,26 @@ def getNetworkWirelessMeshStatuses(self, networkId: str, total_pages=1, directio
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
+ def updateNetworkWirelessOpportunisticPcap(self, networkId: str, **kwargs):
"""
- **Update the AutoRF settings for a wireless network**
- https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-rrm
+ **Update the Opportunistic Pcap settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-opportunistic-pcap
- networkId (string): Network ID
- - busyHour (object): Busy Hour settings
- - channel (object): Channel settings
- - fra (object): FRA settings
- - ai (object): AI settings
+ - enablement (object): Enablement settings
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "radio", "rrm"],
- "operation": "updateNetworkWirelessRadioRrm",
+ "tags": ["wireless", "configure", "opportunisticPcap"],
+ "operation": "updateNetworkWirelessOpportunisticPcap",
}
networkId = urllib.parse.quote(str(networkId), safe="")
- resource = f"/networks/{networkId}/wireless/radio/rrm"
+ resource = f"/networks/{networkId}/wireless/opportunisticPcap"
body_params = [
- "busyHour",
- "channel",
- "fra",
- "ai",
+ "enablement",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1881,14 +2216,90 @@ def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"updateNetworkWirelessRadioRrm: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"updateNetworkWirelessOpportunisticPcap: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.put(metadata, resource, payload)
- def getNetworkWirelessRfProfiles(self, networkId: str, **kwargs):
+ def updateNetworkWirelessRadioAutoRf(self, networkId: str, **kwargs):
"""
- **List RF profiles for this network**
- https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-rf-profiles
+ **Update the AutoRF settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-auto-rf
+
+ - networkId (string): Network ID
+ - busyHour (object): Busy Hour settings
+ - channel (object): Channel settings
+ - fra (object): FRA settings
+ - aiRrm (object): AI-RRM settings
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "autoRf"],
+ "operation": "updateNetworkWirelessRadioAutoRf",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/radio/autoRf"
+
+ body_params = [
+ "busyHour",
+ "channel",
+ "fra",
+ "aiRrm",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkWirelessRadioAutoRf: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
+ """
+ **Update the AutoRF settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-rrm
+
+ - networkId (string): Network ID
+ - busyHour (object): Busy Hour settings
+ - channel (object): Channel settings
+ - fra (object): FRA settings
+ - ai (object): AI settings
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "rrm"],
+ "operation": "updateNetworkWirelessRadioRrm",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/radio/rrm"
+
+ body_params = [
+ "busyHour",
+ "channel",
+ "fra",
+ "ai",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkWirelessRadioRrm: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getNetworkWirelessRfProfiles(self, networkId: str, **kwargs):
+ """
+ **List RF profiles for this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-rf-profiles
- networkId (string): Network ID
- includeTemplateProfiles (boolean): If the network is bound to a template, this parameter controls whether or not the non-basic RF profiles defined on the template should be included in the response alongside the non-basic profiles defined on the bound network. Defaults to false.
@@ -1933,6 +2344,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
- transmission (object): Settings related to radio transmission.
- perSsidSettings (object): Per-SSID radio settings by number.
- flexRadios (object): Flex radio settings.
+ - dot11be (object): 802.11be settings
"""
kwargs.update(locals())
@@ -1967,6 +2379,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
"transmission",
"perSsidSettings",
"flexRadios",
+ "dot11be",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1998,6 +2411,7 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
- transmission (object): Settings related to radio transmission.
- perSsidSettings (object): Per-SSID radio settings by number.
- flexRadios (object): Flex radio settings.
+ - dot11be (object): 802.11be settings
"""
kwargs.update(locals())
@@ -2035,6 +2449,7 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
"transmission",
"perSsidSettings",
"flexRadios",
+ "dot11be",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2252,6 +2667,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
- number (string): Number
- name (string): The name of the SSID
- enabled (boolean): Whether or not the SSID is enabled
+ - localAuth (boolean): Extended local auth flag for Enterprise NAC
- authMode (string): The association control method for the SSID ('open', 'open-enhanced', 'psk', 'open-with-radius', 'open-enhanced-with-radius', 'open-with-nac', '8021x-meraki', '8021x-nac', '8021x-radius', '8021x-google', '8021x-entra', '8021x-localradius', 'ipsk-with-radius', 'ipsk-without-radius', 'ipsk-with-nac' or 'ipsk-with-radius-easy-psk')
- enterpriseAdminAccess (string): Whether or not an SSID is accessible by 'enterprise' administrators ('access disabled' or 'access enabled')
- ssidAdminAccessible (boolean): SSID Administrator access status
@@ -2283,6 +2699,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
- radiusAccountingInterimInterval (integer): The interval (in seconds) in which accounting information is updated and sent to the RADIUS accounting server.
- radiusAttributeForGroupPolicies (string): Specify the RADIUS attribute used to look up group policies ('Filter-Id', 'Reply-Message', 'Airespace-ACL-Name' or 'Aruba-User-Role'). Access points must receive this attribute in the RADIUS Access-Accept message
- ipAssignmentMode (string): The client IP assignment mode ('NAT mode', 'Bridge mode', 'Layer 3 roaming', 'Ethernet over GRE', 'Layer 3 roaming with a concentrator', 'VPN' or 'Campus Gateway')
+ - campusGateway (object): Campus gateway settings
- useVlanTagging (boolean): Whether or not traffic should be directed to use specific VLANs. This param is only valid if the ipAssignmentMode is 'Bridge mode' or 'Layer 3 roaming'
- concentratorNetworkId (string): The concentrator to use when the ipAssignmentMode is 'Layer 3 roaming with a concentrator' or 'VPN'.
- secondaryConcentratorNetworkId (string): The secondary concentrator to use when the ipAssignmentMode is 'VPN'. If configured, the APs will switch to using this concentrator if the primary concentrator is unreachable. This param is optional. ('disabled' represents no secondary concentrator.)
@@ -2404,6 +2821,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
body_params = [
"name",
"enabled",
+ "localAuth",
"authMode",
"enterpriseAdminAccess",
"ssidAdminAccessible",
@@ -2435,6 +2853,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
"radiusAccountingInterimInterval",
"radiusAttributeForGroupPolicies",
"ipAssignmentMode",
+ "campusGateway",
"useVlanTagging",
"concentratorNetworkId",
"secondaryConcentratorNetworkId",
@@ -3017,6 +3436,154 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw
return self._session.put(metadata, resource, payload)
+ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, number: str, **kwargs):
+ """
+ **Update the client exclusion status configuration for a given SSID**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-ssid-policies-client-exclusion
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - static (object): Static client exclusion status
+ - dynamic (object): Dynamic client exclusion configuration
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion"],
+ "operation": "updateNetworkWirelessSsidPoliciesClientExclusion",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion"
+
+ body_params = [
+ "static",
+ "dynamic",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkWirelessSsidPoliciesClientExclusion: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Replace the static client exclusion list for the given SSID (use PUT /exclusions)**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-ssid-policies-client-exclusion-static-exclusions
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to set as static exclusion list
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions"],
+ "operation": "updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Add MAC addresses to the existing static client exclusion list for the given SSID (use POST /bulkAdd)**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-wireless-ssid-policies-client-exclusion-static-exclusions-bulk-add
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to add to static exclusion
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions", "bulkAdd"],
+ "operation": "createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions/bulkAdd"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Remove MAC addresses from the existing static client exclusion list for the given SSID (use POST /bulkRemove)**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-wireless-ssid-policies-client-exclusion-static-exclusions-bulk-remove
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to remove from static exclusion
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions", "bulkRemove"],
+ "operation": "createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions/bulkRemove"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getNetworkWirelessSsidSchedules(self, networkId: str, number: str):
"""
**List the outage schedule for the SSID**
@@ -3105,6 +3672,7 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
- redirectUrl (string): The custom redirect URL where the users will go after the splash page.
- useRedirectUrl (boolean): The Boolean indicating whether the the user will be redirected to the custom redirect URL after the splash page. A custom redirect URL must be set if this is true.
- welcomeMessage (string): The welcome message for the users on the splash page.
+ - language (string): Language of splash page.
- userConsent (object): User consent settings
- themeId (string): The id of the selected splash theme.
- splashLogo (object): The logo used in the splash page.
@@ -3126,6 +3694,32 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
assert kwargs["splashTimeout"] in options, (
f'''"splashTimeout" cannot be "{kwargs["splashTimeout"]}", & must be set to one of: {options}'''
)
+ if "language" in kwargs:
+ options = [
+ "DA",
+ "DE",
+ "EL",
+ "EN",
+ "ES",
+ "FI",
+ "FR",
+ "GL",
+ "IT",
+ "JA",
+ "KO",
+ "NL",
+ "NO",
+ "PL",
+ "PT",
+ "RU",
+ "SK",
+ "SV",
+ "UK",
+ "ZH",
+ ]
+ assert kwargs["language"] in options, (
+ f'''"language" cannot be "{kwargs["language"]}", & must be set to one of: {options}'''
+ )
if "controllerDisconnectionBehavior" in kwargs:
options = ["default", "open", "restricted"]
assert kwargs["controllerDisconnectionBehavior"] in options, (
@@ -3147,6 +3741,7 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
"redirectUrl",
"useRedirectUrl",
"welcomeMessage",
+ "language",
"userConsent",
"themeId",
"splashLogo",
@@ -3379,34 +3974,38 @@ def updateNetworkWirelessZigbee(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
- def getOrganizationWirelessAirMarshalRules(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceConnectivityWirelessRfHealthByBand(self, organizationId: str, networkIds: list, **kwargs):
"""
- **Returns the current Air Marshal rules for this organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-rules
+ **Show the by-device RF Health score overview information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-connectivity-wireless-rf-health-by-band
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): (optional) The set of network IDs to include.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Networks for which information should be gathered.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 3600, 14400, 86400. The default is 3600. Interval is calculated if time params are provided.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "airMarshal", "rules"],
- "operation": "getOrganizationWirelessAirMarshalRules",
+ "tags": ["wireless", "configure", "connectivity", "rfHealth", "byBand"],
+ "operation": "getOrganizationAssuranceConnectivityWirelessRfHealthByBand",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/airMarshal/rules"
+ resource = f"/organizations/{organizationId}/assurance/connectivity/wireless/rfHealth/byBand"
query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
"networkIds",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -3423,23 +4022,26 @@ def getOrganizationWirelessAirMarshalRules(self, organizationId: str, total_page
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessAirMarshalRules: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceConnectivityWirelessRfHealthByBand: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessAirMarshalSettingsByNetwork(
+ def getOrganizationAssuranceImpactedDeviceWirelessByNetwork(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Returns the current Air Marshal settings for this network**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-settings-by-network
+ **Returns count of impacted wireless devices per network on a given organization and time range.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-impacted-device-wireless-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): The network IDs to include in the result set.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 2 hours and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
@@ -3447,14 +4049,17 @@ def getOrganizationWirelessAirMarshalSettingsByNetwork(
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "airMarshal", "settings", "byNetwork"],
- "operation": "getOrganizationWirelessAirMarshalSettingsByNetwork",
+ "tags": ["wireless", "monitor", "impactedDevice", "byNetwork"],
+ "operation": "getOrganizationAssuranceImpactedDeviceWirelessByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/airMarshal/settings/byNetwork"
+ resource = f"/organizations/{organizationId}/assurance/impactedDevice/wireless/byNetwork"
query_params = [
- "networkIds",
+ "networkGroupIds",
+ "t0",
+ "t1",
+ "timespan",
"perPage",
"startingAfter",
"endingBefore",
@@ -3462,7 +4067,7 @@ def getOrganizationWirelessAirMarshalSettingsByNetwork(
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "networkIds",
+ "networkGroupIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3474,23 +4079,29 @@ def getOrganizationWirelessAirMarshalSettingsByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessAirMarshalSettingsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceImpactedDeviceWirelessByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **List access point client count at the moment in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-overview-by-device
+ **Summarizes wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): Optional parameter to filter access points client counts by network ID. This filter uses multiple exact matches.
- - serials (array): Optional parameter to filter access points client counts by its serial numbers. This filter uses multiple exact matches.
- - campusGatewayClusterIds (array): Optional parameter to filter access points client counts by MCG cluster IDs. This filter uses multiple exact matches.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
@@ -3498,16 +4109,20 @@ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, to
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "clients", "overview", "byDevice"],
- "operation": "getOrganizationWirelessClientsOverviewByDevice",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/clients/overview/byDevice"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork"
query_params = [
"networkIds",
"serials",
- "campusGatewayClusterIds",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
"perPage",
"startingAfter",
"endingBefore",
@@ -3517,7 +4132,8 @@ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, to
array_params = [
"networkIds",
"serials",
- "campusGatewayClusterIds",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3529,57 +4145,61 @@ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, to
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationByDevice(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByBand(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get average channel utilization for all bands in a network, split by AP**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-device
+ **Summarizes wireless post connection capacity successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-band
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "byDevice"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationByDevice",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByBand",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byDevice"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byBand"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3591,57 +4211,61 @@ def getOrganizationWirelessDevicesChannelUtilizationByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationByNetwork(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClient(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get average channel utilization across all bands for all networks in the organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-network
+ **Summarizes wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-client
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "byNetwork"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationByNetwork",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byNetwork"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byClient"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3653,57 +4277,61 @@ def getOrganizationWirelessDevicesChannelUtilizationByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientOs(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get a time-series of average channel utilization for all bands, segmented by device.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-device-by-interval
+ **Summarizes wireless post connection capacity successes and failures by client OS and driver version.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-client-os
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byDevice", "byInterval"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientOs",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byDevice/byInterval"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byClientOs"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3715,57 +4343,61 @@ def getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientType(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get a time-series of average channel utilization for all bands**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-network-by-interval
+ **Summarizes wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-client-type
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byNetwork", "byInterval"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientType",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byNetwork/byInterval"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byClientType"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3777,44 +4409,61 @@ def getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesEthernetStatuses(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **List the most recent Ethernet link speed, duplex, aggregation and power mode and status information for wireless devices.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-ethernet-statuses
+ **Summarizes wireless post connection capacity successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-device
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): A list of Meraki network IDs to filter results to contain only specified networks. E.g.: networkIds[]=N_12345678&networkIds[]=L_3456
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "ethernet", "statuses"],
- "operation": "getOrganizationWirelessDevicesEthernetStatuses",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/ethernet/statuses"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byDevice"
query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3826,59 +4475,63 @@ def getOrganizationWirelessDevicesEthernetStatuses(self, organizationId: str, to
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesEthernetStatuses: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPacketLossByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Get average packet loss for the given timespan for all clients in the organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-client
+ **Time-series of wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-interval
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - ssids (array): Filter results by SSID number.
- - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
- - macs (array): Filter results by client mac address(es).
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "packetLoss", "byClient"],
- "operation": "getOrganizationWirelessDevicesPacketLossByClient",
+ "tags": ["wireless", "monitor", "experience", "channelAvailability", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byClient"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byInterval"
query_params = [
"networkIds",
- "ssids",
+ "serials",
+ "ssidNumbers",
"bands",
- "macs",
- "perPage",
- "startingAfter",
- "endingBefore",
"t0",
"t1",
"timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
- "ssids",
+ "serials",
+ "ssidNumbers",
"bands",
- "macs",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3890,58 +4543,60 @@ def getOrganizationWirelessDevicesPacketLossByClient(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPacketLossByClient: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPacketLossByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Get average packet loss for the given timespan for all devices in the organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-device
+ **Summarizes wireless post connection capacity successes and failures by ssid.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-ssid
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - ssids (array): Filter results by SSID number.
- - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "packetLoss", "byDevice"],
- "operation": "getOrganizationWirelessDevicesPacketLossByDevice",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkBySsid",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byDevice"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/bySsid"
query_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
- "perPage",
- "startingAfter",
- "endingBefore",
"t0",
"t1",
"timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
]
for k, v in kwargs.items():
@@ -3954,60 +4609,77 @@ def getOrganizationWirelessDevicesPacketLossByDevice(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPacketLossByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPacketLossByNetwork(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityInsightsByNetwork(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get average packet loss for the given timespan for all networks in the organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-network
+ **Provides insights into wireless capacity experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-insights-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - ssids (array): Filter results by SSID number.
- - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
"""
kwargs.update(locals())
+ if "contributor" in kwargs:
+ options = ["Co-channel interference", "High traffic", "Non-wifi interference"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "monitor", "devices", "packetLoss", "byNetwork"],
- "operation": "getOrganizationWirelessDevicesPacketLossByNetwork",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityInsightsByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byNetwork"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/insights/byNetwork"
query_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "contributor",
+ "subContributor",
+ "insights",
"t0",
"t1",
"timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
]
for k, v in kwargs.items():
@@ -4020,53 +4692,143 @@ def getOrganizationWirelessDevicesPacketLossByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPacketLossByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPowerModeHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceClientsInsights(self, organizationId: str, **kwargs):
"""
- **Return a record of power mode changes for wireless devices in the organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-power-mode-history
+ **Returns the top wireless service-level insights for the specified time window, including each network and the impacted client count per metric.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-clients-insights
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days.
+ - limit (integer): Number of top networks to return. Default is 5. Maximum is 10.
+ """
+
+ kwargs.update(locals())
+
+ if "limit" in kwargs:
+ options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ assert kwargs["limit"] in options, f'''"limit" cannot be "{kwargs["limit"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "clients", "insights"],
+ "operation": "getOrganizationAssuranceWirelessExperienceClientsInsights",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/clients/insights"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "limit",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceClientsInsights: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceClientsOverviewHistoryByInterval(self, organizationId: str, **kwargs):
+ """
+ **Returns time series data for impacted and active clients for organization wireless experience metrics.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-clients-overview-history-by-interval
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 300, 600, 900, 1800, 3600, 86400. The default is 300.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "clients", "overview", "history", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceClientsOverviewHistoryByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/clients/overview/history/byInterval"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "resolution",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceClientsOverviewHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
- - serials (array): Optional parameter to filter device availabilities history by device serial numbers
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "power", "mode", "history"],
- "operation": "getOrganizationWirelessDevicesPowerModeHistory",
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/power/mode/history"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork"
query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4078,133 +4840,5359 @@ def getOrganizationWirelessDevicesPowerModeHistory(self, organizationId: str, to
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPowerModeHistory: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesProvisioningDeployments(
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByBand(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **List the zero touch deployments for wireless access points in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-deployments
+ **Summarizes wireless coverage successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-band
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 20.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - search (string): Filter by MAC address, serial number, new device name, old device name, or model.
- - sortBy (string): Field used to sort results. Default is 'status'.
- - sortOrder (string): Sort order. Default is 'asc'.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByBand",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byBand"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientOs(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Time-series of wireless coverage successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "coverage", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by SSID.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageInsightsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides insights into wireless coverage experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-insights-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "contributor" in kwargs:
+ options = ["Admin power restriction", "Insufficient AP density", "Sticky client", "Transient weak signal"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageInsightsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/insights/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "contributor",
+ "subContributor",
+ "insights",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceMetricsOverviewHistoryByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns organization wireless experience metrics overview grouped by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-metrics-overview-history-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "metrics", "overview", "history", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceMetricsOverviewHistoryByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/metrics/overview/history/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceMetricsOverviewHistoryByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceMostImpactedNetworks(self, organizationId: str, **kwargs):
+ """
+ **Returns the most impacted wireless experience networks and the top failure contributor for each network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-most-impacted-networks
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - limit (integer): Number of most impacted networks to return. Default is 5. Maximum is 10.
+ """
+
+ kwargs.update(locals())
+
+ if "limit" in kwargs:
+ options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ assert kwargs["limit"] in options, f'''"limit" cannot be "{kwargs["limit"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "mostImpactedNetworks"],
+ "operation": "getOrganizationAssuranceWirelessExperienceMostImpactedNetworks",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/mostImpactedNetworks"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "limit",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceMostImpactedNetworks: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceMostImpactedXMs(self, organizationId: str, **kwargs):
+ """
+ **Returns the most impacted wireless experience metrics and the top failure contributor for each metric/network pair.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-most-impacted-x-ms
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - limit (integer): Number of most impacted XMs to return. Default is 5. Maximum is 10.
+ """
+
+ kwargs.update(locals())
+
+ if "limit" in kwargs:
+ options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ assert kwargs["limit"] in options, f'''"limit" cannot be "{kwargs["limit"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "mostImpactedXMs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceMostImpactedXMs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/mostImpactedXMs"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "limit",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceMostImpactedXMs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByBand(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-band
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByBand",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byBand"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 10000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientOs(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Time-series of wireless connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "successfulConnects", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByServer(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-server
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byServer"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byServer"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by ssid.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides insights into wireless successful connects experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-insights-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "contributor" in kwargs:
+ options = ["assoc", "auth", "dhcp", "dns"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/insights/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "contributor",
+ "subContributor",
+ "insights",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless time to connect metrics by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByBand(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-band
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByBand",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byBand"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless time to connect metrics by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 10000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientOs(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection time to connect metrics by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Time-series of wireless time to connect by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "timeToConnect", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByServer(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection time to connect metrics by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-server
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byServer"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byServer"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection time to connect metrics by ssid.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectInsightsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides insights into wireless time to connect experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-insights-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "contributor" in kwargs:
+ options = ["assoc", "auth", "dhcp", "dns"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectInsightsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/insights/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "contributor",
+ "subContributor",
+ "insights",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessAirMarshalRules(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns the current Air Marshal rules for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): (optional) The set of network IDs to include.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "airMarshal", "rules"],
+ "operation": "getOrganizationWirelessAirMarshalRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/airMarshal/rules"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessAirMarshalRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessAirMarshalSettingsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns the current Air Marshal settings for this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-settings-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): The network IDs to include in the result set.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "airMarshal", "settings", "byNetwork"],
+ "operation": "getOrganizationWirelessAirMarshalSettingsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/airMarshal/settings/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessAirMarshalSettingsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessAlertsLowPowerByDevice(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Gets all low power related alerts over a given network and returns information by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-alerts-low-power-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "alerts", "lowPower", "byDevice"],
+ "operation": "getOrganizationWirelessAlertsLowPowerByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/alerts/lowPower/byDevice"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessAlertsLowPowerByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessCertificatesOpenRoamingCertificateAuthority(self, organizationId: str):
+ """
+ **Query for details on the organization's OpenRoaming Certificate Authority certificate (CAs).**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-certificates-open-roaming-certificate-authority
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "certificates", "openRoaming", "certificateAuthority"],
+ "operation": "getOrganizationWirelessCertificatesOpenRoamingCertificateAuthority",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/certificates/openRoaming/certificateAuthority"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationWirelessClientsConnectionsAssociationByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarize association outcomes per wireless client across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-association-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "association", "byClient"],
+ "operation": "getOrganizationWirelessClientsConnectionsAssociationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/association/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsAssociationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsConnectionsAuthenticationByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarize authentication outcomes per wireless client across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-authentication-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "authentication", "byClient"],
+ "operation": "getOrganizationWirelessClientsConnectionsAuthenticationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/authentication/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsAuthenticationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsConnectionsDhcpByClient(self, organizationId: str, **kwargs):
+ """
+ **Get IP assignment for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-dhcp-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "dhcp", "byClient"],
+ "operation": "getOrganizationWirelessClientsConnectionsDhcpByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/dhcp/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsDhcpByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsConnectionsFailuresHistoryByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns failed wireless client connections for this organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-failures-history-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - connectionTimeSortOrder (string): (optional) Sort order of events by connection start time. (default desc)
+ - failureSteps (array): (optional) The step in the connection process that failed
+ - clientMac (string): (optional) The MAC address of the client with which the list of events will be filtered.
+ - serials (array): (optional) Filter devices by serial number
+ - timespan (integer): (optional) The timespan, in seconds, for the failed connections. The period will be from [timespan] seconds ago until now. The maximum allowed timespan is 1 month. Default: 86400 (24 hours)
+ - ssidNumber (integer): (optional) The SSID number to include
+ - networkIds (array): (optional) The set of network IDs to include.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "connectionTimeSortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["connectionTimeSortOrder"] in options, (
+ f'''"connectionTimeSortOrder" cannot be "{kwargs["connectionTimeSortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "ssidNumber" in kwargs:
+ options = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
+ assert kwargs["ssidNumber"] in options, (
+ f'''"ssidNumber" cannot be "{kwargs["ssidNumber"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "connections", "failures", "history", "byDevice"],
+ "operation": "getOrganizationWirelessClientsConnectionsFailuresHistoryByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/failures/history/byDevice"
+
+ query_params = [
+ "connectionTimeSortOrder",
+ "failureSteps",
+ "clientMac",
+ "serials",
+ "timespan",
+ "ssidNumber",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "failureSteps",
+ "serials",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsFailuresHistoryByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsConnectionsImpactedByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarize the number of wireless clients impacted by connection failures on network SSIDs, across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-impacted-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "impacted", "byNetwork", "bySsid"],
+ "operation": "getOrganizationWirelessClientsConnectionsImpactedByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/impacted/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "networkGroupIds",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsImpactedByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List access point client count at the moment in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-overview-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter access points client counts by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter access points client counts by its serial numbers. This filter uses multiple exact matches.
+ - campusGatewayClusterIds (array): Optional parameter to filter access points client counts by MCG cluster IDs. This filter uses multiple exact matches.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "overview", "byDevice"],
+ "operation": "getOrganizationWirelessClientsOverviewByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/overview/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "campusGatewayClusterIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "campusGatewayClusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def byOrganizationWirelessClientsRfHealthOverviewNetwork(self, organizationId: str, **kwargs):
+ """
+ **Show the by-network client information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!by-organization-wireless-clients-rf-health-overview-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Networks for which information should be gathered.
+ - bands (array): Bands for which information should be gathered. Valid bands are 2.4, 5, and 6.
+ - channels (array): Channel for which information should be gathered.
+ - serials (array): Serial number of the devices for which information should be gathered.
+ - gFloorplanId (string): Geoaligned floorplan ID nodes for which information is gathered belong to.
+ - tags (array): Access Point tags for which information should be gathered.
+ - models (array): Access Point models for which information should be gathered.
+ - rfProfiles (array): Rf Profiles for which information should be gathered.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
+ - retryOnEmpty (boolean): If true, the query will be retried with a longer timeframe if the results are empty.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "rfHealth", "overview"],
+ "operation": "byOrganizationWirelessClientsRfHealthOverviewNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/rfHealth/overview/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "gFloorplanId",
+ "tags",
+ "models",
+ "rfProfiles",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ "retryOnEmpty",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"byOrganizationWirelessClientsRfHealthOverviewNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsStickyEvents(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get sticky client events within the specified timespan.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-sticky-events
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - clientIds (array): Filter results by client id.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "stickyEvents"],
+ "operation": "getOrganizationWirelessClientsStickyEvents",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/stickyEvents"
+
+ query_params = [
+ "networkIds",
+ "clientIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "clientIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsStickyEvents: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsUsageByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns client usage details for wireless networks within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-usage-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - networkIds (array): Filter results by a list of network IDs.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - gatewayNetworkIds (array): Limit the results to clients tunneled to campus gateways in the provided networks.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "usage", "byNetwork"],
+ "operation": "getOrganizationWirelessClientsUsageByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/usage/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsUsageByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsUsageByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns client usage details for wireless network SSIDs within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-usage-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - networkIds (array): Filter results by a list of network IDs.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - ssidIds (array): Filter results by a list of SSID IDs.
+ - ssidNames (array): Filter results by a list of SSID names.
+ - gatewayNetworkIds (array): Limit the results to clients tunneled to campus gateways in the provided networks.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "usage", "byNetwork", "bySsid"],
+ "operation": "getOrganizationWirelessClientsUsageByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/usage/byNetwork/bySsid"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "networkGroupIds",
+ "ssidIds",
+ "ssidNames",
+ "gatewayNetworkIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "ssidIds",
+ "ssidNames",
+ "gatewayNetworkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsUsageByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsUsageBySsid(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns client usage details for SSIDs within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-usage-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - ssidNames (array): Filter results by a list of SSID names.
+ - networkIds (array): Limit the results to clients that belong to one of the provided networks.
+ - networkGroupIds (array): Limit the results to clients that belong to one of the provided network groups.
+ - gatewayNetworkIds (array): Limit the results to clients tunneled to campus gateways in the provided networks.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "usage", "bySsid"],
+ "operation": "getOrganizationWirelessClientsUsageBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/usage/bySsid"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "ssidNames",
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ssidNames",
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsUsageBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesAccelerometerStatuses(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the most recent AP accelerometer status information for wireless devices that support it.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-accelerometer-statuses
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of Meraki network IDs to filter results to contain only specified networks. E.g.: networkIds[]=N_12345678&networkIds[]=L_3456
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "accelerometer", "statuses"],
+ "operation": "getOrganizationWirelessDevicesAccelerometerStatuses",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/accelerometer/statuses"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesAccelerometerStatuses: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average channel utilization for all bands in a network, split by AP**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average channel utilization across all bands for all networks in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get a time-series of average channel utilization for all bands, segmented by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-device-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byDevice", "byInterval"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byDevice/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get a time-series of average channel utilization for all bands**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byNetwork", "byInterval"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesDataRateByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get average uplink and downlink datarates for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-data-rate-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - macs (array): Filter results by client mac address(es).
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "dataRate", "byClient"],
+ "operation": "getOrganizationWirelessDevicesDataRateByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/dataRate/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesDataRateByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesEthernetStatuses(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the most recent Ethernet link speed, duplex, aggregation and power mode and status information for wireless devices.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-ethernet-statuses
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of Meraki network IDs to filter results to contain only specified networks. E.g.: networkIds[]=N_12345678&networkIds[]=L_3456
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "ethernet", "statuses"],
+ "operation": "getOrganizationWirelessDevicesEthernetStatuses",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/ethernet/statuses"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesEthernetStatuses: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesLatencyByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get latency summaries for all wireless devices in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-latency-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - networkIds (array): Filter results by network.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssids (array): Filter results by SSID number.
+ - macs (array): Filter results by client mac address(es).
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "latency", "byClient"],
+ "operation": "getOrganizationWirelessDevicesLatencyByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/latency/byClient"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "bands",
+ "ssids",
+ "macs",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "bands",
+ "ssids",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesLatencyByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesLatencyByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get latency summaries for all wireless devices in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-latency-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssids (array): Filter results by SSID number.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "latency", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesLatencyByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/latency/byDevice"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesLatencyByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesLatencyByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get per-network latency summaries for all wireless networks in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-latency-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssids (array): Filter results by SSID number.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "latency", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesLatencyByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/latency/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesLatencyByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessDevicesLiveToolsClientDisconnect(self, organizationId: str, clientId: str, **kwargs):
+ """
+ **Enqueue a job to disconnect a client from an AP**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-live-tools-client-disconnect
+
+ - organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "liveTools", "devices", "clients", "disconnect"],
+ "operation": "createOrganizationWirelessDevicesLiveToolsClientDisconnect",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/liveTools/clients/{clientId}/disconnect"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWirelessDevicesLiveToolsClientDisconnect: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWirelessDevicesPacketLossByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get average packet loss for the given timespan for all clients in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - macs (array): Filter results by client mac address(es).
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "packetLoss", "byClient"],
+ "operation": "getOrganizationWirelessDevicesPacketLossByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byClient"
+
+ query_params = [
+ "networkIds",
+ "ssids",
+ "bands",
+ "macs",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "ssids",
+ "bands",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPacketLossByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesPacketLossByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get average packet loss for the given timespan for all devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "packetLoss", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesPacketLossByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPacketLossByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesPacketLossByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average packet loss for the given timespan for all networks in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "packetLoss", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesPacketLossByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPacketLossByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesPowerModeHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return a record of power mode changes for wireless devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-power-mode-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): Optional parameter to filter device availabilities history by device serial numbers
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "power", "mode", "history"],
+ "operation": "getOrganizationWirelessDevicesPowerModeHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/power/mode/history"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPowerModeHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesProvisioningDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the zero touch deployments for wireless access points in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): Filter by MAC address, serial number, new device name, old device name, or model.
+ - sortBy (string): Field used to sort results. Default is 'status'.
+ - sortOrder (string): Sort order. Default is 'asc'.
- deploymentType (string): Filter deployments by type.
"""
kwargs.update(locals())
- if "sortBy" in kwargs:
- options = ["afterAction", "createdAt", "deploymentId", "name", "status"]
- assert kwargs["sortBy"] in options, (
- f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
- )
- if "sortOrder" in kwargs:
- options = ["asc", "desc"]
- assert kwargs["sortOrder"] in options, (
- f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
- )
- if "deploymentType" in kwargs:
- options = ["deploy", "replace"]
- assert kwargs["deploymentType"] in options, (
- f'''"deploymentType" cannot be "{kwargs["deploymentType"]}", & must be set to one of: {options}'''
- )
+ if "sortBy" in kwargs:
+ options = ["afterAction", "createdAt", "deploymentId", "name", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "deploymentType" in kwargs:
+ options = ["deploy", "replace"]
+ assert kwargs["deploymentType"] in options, (
+ f'''"deploymentType" cannot be "{kwargs["deploymentType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "getOrganizationWirelessDevicesProvisioningDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "sortBy",
+ "sortOrder",
+ "deploymentType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, items: list, **kwargs):
+ """
+ **Create a zero touch deployment for a wireless access point**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-provisioning-deployment
+
+ - organizationId (string): Organization ID
+ - items (array): List of zero touch deployments to create
+ - meta (object): Metadata relevant to the paginated dataset
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "createOrganizationWirelessDevicesProvisioningDeployment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+
+ body_params = [
+ "items",
+ "meta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWirelessDevicesProvisioningDeployment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationId: str, items: list, **kwargs):
+ """
+ **Update a zero touch deployment**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-provisioning-deployments
+
+ - organizationId (string): Organization ID
+ - items (array): List of zero touch deployments to create
+ - meta (object): Metadata relevant to the paginated dataset
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "updateOrganizationWirelessDevicesProvisioningDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+
+ body_params = [
+ "items",
+ "meta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationWirelessDevicesProvisioningDeploymentsByNewDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns deployment IDs for the given new node serial numbers**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-deployments-by-new-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 80.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - serials (array): Array of new device serial numbers to query
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments", "byNewDevice"],
+ "operation": "getOrganizationWirelessDevicesProvisioningDeploymentsByNewDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/byNewDevice"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesProvisioningDeploymentsByNewDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, deploymentId: str):
+ """
+ **Delete a zero touch deployment**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-devices-provisioning-deployment
+
+ - organizationId (string): Organization ID
+ - deploymentId (string): Deployment ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "deleteOrganizationWirelessDevicesProvisioningDeployment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/{deploymentId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationWirelessDevicesProvisioningRecommendationsTags(self, organizationId: str, **kwargs):
+ """
+ **List the recommended device tags for zero touch deployments available for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-recommendations-tags
+
+ - organizationId (string): Organization ID
+ - networkIds (array): The list of networks to use as hints for device tags recommendations.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "recommendations", "tags"],
+ "operation": "getOrganizationWirelessDevicesProvisioningRecommendationsTags",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/recommendations/tags"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesProvisioningRecommendationsTags: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ """
+ **Query for details on the organization's RadSec device Certificate Authority certificates (CAs)**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
+ "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def updateOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ """
+ **Update an organization's RadSec device Certificate Authority (CA) state**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-radsec-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - status (string): The "status" to update the Certificate Authority to. Only valid option is "trusted".
+ - certificateAuthorityId (string): The ID of the Certificate Authority to update.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
+ "operation": "updateOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+
+ body_params = [
+ "status",
+ "certificateAuthorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def createOrganizationWirelessDevicesRadsecCertificatesAuthority(self, organizationId: str):
+ """
+ **Create an organization's RadSec device Certificate Authority (CA)**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-radsec-certificates-authority
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
+ "operation": "createOrganizationWirelessDevicesRadsecCertificatesAuthority",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+
+ return self._session.post(metadata, resource)
+
+ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls(self, organizationId: str, **kwargs):
+ """
+ **Query for certificate revocation list (CRL) for the organization's RadSec device Certificate Authorities (CAs).**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls"],
+ "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas(self, organizationId: str, **kwargs):
+ """
+ **Query for all delta certificate revocation list (CRL) for the organization's RadSec device Certificate Authority (CA) with the given id.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls-deltas
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls", "deltas"],
+ "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls/deltas"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessDevicesSignalQualityByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average signal quality for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-signal-quality-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - macs (array): Filter results by client mac address(es).
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "signalQuality", "byClient"],
+ "operation": "getOrganizationWirelessDevicesSignalQualityByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/signalQuality/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSignalQualityByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesSignalQualityByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average signal quality for all devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-signal-quality-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "signalQuality", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesSignalQualityByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/signalQuality/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSignalQualityByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesSignalQualityByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average signal quality for all networks in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-signal-quality-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "signalQuality", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesSignalQualityByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/signalQuality/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSignalQualityByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesSystemCpuLoadHistory(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return the CPU Load history for a list of wireless devices in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-system-cpu-load-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): Optional parameter to filter device availabilities history by device serial numbers
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "system", "cpu", "load", "history"],
+ "operation": "getOrganizationWirelessDevicesSystemCpuLoadHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/system/cpu/load/history"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSystemCpuLoadHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesTelemetry(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the wireless device telemetry of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-telemetry
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 200. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 3 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 minutes after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 30 minutes. The default is 30 minutes.
+ - networkIds (array): Optional parameter to filter results by network.
+ - serials (array): Optional parameter to filter results by device serial.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "telemetry"],
+ "operation": "getOrganizationWirelessDevicesTelemetry",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/telemetry"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesTelemetry: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesWirelessControllersByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List of Catalyst access points information**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-wireless-controllers-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter access points by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter access points by its cloud ID. This filter uses multiple exact matches.
+ - controllerSerials (array): Optional parameter to filter access points by its wireless LAN controller cloud ID. This filter uses multiple exact matches.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "wirelessControllers", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesWirelessControllersByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/wirelessControllers/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "controllerSerials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "controllerSerials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesWirelessControllersByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessLocationScanningByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter scanning settings by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "byNetwork"],
+ "operation": "getOrganizationWirelessLocationScanningByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessLocationScanningByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessLocationScanningReceivers(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return scanning API receivers**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-receivers
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter scanning API receivers by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "getOrganizationWirelessLocationScanningReceivers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessLocationScanningReceivers: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessLocationScanningReceiver(
+ self, organizationId: str, network: dict, url: str, version: str, radio: dict, sharedSecret: str, **kwargs
+ ):
+ """
+ **Add new receiver for scanning API**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-location-scanning-receiver
+
+ - organizationId (string): Organization ID
+ - network (object): Add scanning API receiver for network
+ - url (string): Receiver Url
+ - version (string): Scanning API Version
+ - radio (object): Add scanning API Radio
+ - sharedSecret (string): Secret Value for Receiver
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "createOrganizationWirelessLocationScanningReceiver",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+
+ body_params = [
+ "network",
+ "url",
+ "version",
+ "radio",
+ "sharedSecret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str, **kwargs):
+ """
+ **Change scanning API receiver settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-location-scanning-receiver
+
+ - organizationId (string): Organization ID
+ - receiverId (string): Receiver ID
+ - url (string): Receiver Url
+ - version (string): Scanning API Version
+ - radio (object): Add scanning API Radio
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "updateOrganizationWirelessLocationScanningReceiver",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ receiverId = urllib.parse.quote(str(receiverId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
+
+ body_params = [
+ "url",
+ "version",
+ "radio",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str):
+ """
+ **Delete a scanning API receiver**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-location-scanning-receiver
+
+ - organizationId (string): Organization ID
+ - receiverId (string): Receiver ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "deleteOrganizationWirelessLocationScanningReceiver",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ receiverId = urllib.parse.quote(str(receiverId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationWirelessLocationWayfindingByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return Client wayfinding settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-wayfinding-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter wayfinding settings by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "wayfinding", "byNetwork"],
+ "operation": "getOrganizationWirelessLocationWayfindingByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/wayfinding/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessLocationWayfindingByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessMqttSettings(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return MQTT Settings for networks**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-mqtt-settings
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter mqtt settings by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "mqtt", "settings"],
+ "operation": "getOrganizationWirelessMqttSettings",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationWirelessMqttSettings(self, organizationId: str, network: dict, mqtt: dict, **kwargs):
+ """
+ **Add new broker config for wireless MQTT**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-mqtt-settings
+
+ - organizationId (string): Organization ID
+ - network (object): Add MQTT Settings for network
+ - mqtt (object): MQTT Settings for network
+ - ble (object): MQTT BLE Settings for network
+ - wifi (object): MQTT Wi-Fi Settings for network
+ """
+
+ kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "getOrganizationWirelessDevicesProvisioningDeployments",
+ "tags": ["wireless", "configure", "mqtt", "settings"],
+ "operation": "updateOrganizationWirelessMqttSettings",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+ resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+
+ body_params = [
+ "network",
+ "mqtt",
+ "ble",
+ "wifi",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def byOrganizationWirelessOpportunisticPcapLicenseNetwork(self, organizationId: str, **kwargs):
+ """
+ **Check the Opportunistic Pcap license status of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!by-organization-wireless-opportunistic-pcap-license-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter results by network.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "opportunisticPcap", "license"],
+ "operation": "byOrganizationWirelessOpportunisticPcapLicenseNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/opportunisticPcap/license/byNetwork"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"byOrganizationWirelessOpportunisticPcapLicenseNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessRadioAfcPositionByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the AFC power limits of an organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-afc-position-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter device's AFC position by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter device's AFC position by device serial numbers. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "position", "byDevice"],
+ "operation": "getOrganizationWirelessRadioAfcPositionByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/radio/afc/position/byDevice"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
- "search",
- "sortBy",
- "sortOrder",
- "deploymentType",
+ "networkIds",
+ "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
if self._session._validate_kwargs:
- all_params = query_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioAfcPositionByDevice: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def createOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, items: list, **kwargs):
+ def getOrganizationWirelessRadioAfcPowerLimitsByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Create a zero touch deployment for a wireless access point**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-provisioning-deployment
+ **List the AFC power limits of an organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-afc-power-limits-by-device
- organizationId (string): Organization ID
- - items (array): List of zero touch deployments to create
- - meta (object): Metadata relevant to the paginated dataset
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter device's AFC power limits by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter device's AFC power limits by device serial numbers. This filter uses multiple exact matches.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "createOrganizationWirelessDevicesProvisioningDeployment",
+ "tags": ["wireless", "configure", "radio", "afc", "powerLimits", "byDevice"],
+ "operation": "getOrganizationWirelessRadioAfcPowerLimitsByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+ resource = f"/organizations/{organizationId}/wireless/radio/afc/powerLimits/byDevice"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessRadioAfcPowerLimitsByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessRadioAutoRfByNetwork(self, organizationId: str, **kwargs):
+ """
+ **List the AutoRF settings of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-auto-rf-by-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter results by network.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "autoRf", "byNetwork"],
+ "operation": "getOrganizationWirelessRadioAutoRfByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/radio/autoRf/byNetwork"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessRadioAutoRfByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessRadioAutoRfChannelsPlanningActivities(self, organizationId: str, **kwargs):
+ """
+ **List the channel planning activities of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-auto-rf-channels-planning-activities
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter results by network.
+ - deviceSerials (array): Optional parameter to filter results by device serial.
+ - bands (array): Optional parameter to filter results by bands. Valid bands are 2.4, 5, and 6.
+ - channels (array): Optional parameter to filter results by channels.
+ - serials (array): Serial number of the devices for which information should be gathered.
+ - gFloorplanId (string): Geoaligned floorplan ID nodes for which information is gathered belong to.
+ - tags (array): Optional parameter to filter results by node tags.
+ - models (array): Optional parameter to filter results by access point models.
+ - rfProfiles (array): Optional parameter to filter results by RF Profiles.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "autoRf", "channels", "planning", "activities"],
+ "operation": "getOrganizationWirelessRadioAutoRfChannelsPlanningActivities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/planning/activities"
+
+ query_params = [
+ "networkIds",
+ "deviceSerials",
+ "bands",
+ "channels",
+ "serials",
+ "gFloorplanId",
+ "tags",
+ "models",
+ "rfProfiles",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- body_params = [
- "items",
- "meta",
+ array_params = [
+ "networkIds",
+ "deviceSerials",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"createOrganizationWirelessDevicesProvisioningDeployment: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioAutoRfChannelsPlanningActivities: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.post(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationId: str, items: list, **kwargs):
+ def recalculateOrganizationWirelessRadioAutoRfChannels(self, organizationId: str, networkIds: list, **kwargs):
"""
- **Update a zero touch deployment**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-provisioning-deployments
+ **Recalculates automatically assigned channels for every AP within specified the specified network(s)**
+ https://developer.cisco.com/meraki/api-v1/#!recalculate-organization-wireless-radio-auto-rf-channels
- organizationId (string): Organization ID
- - items (array): List of zero touch deployments to create
- - meta (object): Metadata relevant to the paginated dataset
+ - networkIds (array): A list of network ids (limit: 15).
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "updateOrganizationWirelessDevicesProvisioningDeployments",
+ "tags": ["wireless", "configure", "radio", "autoRf", "channels"],
+ "operation": "recalculateOrganizationWirelessRadioAutoRfChannels",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+ resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/recalculate"
body_params = [
- "items",
- "meta",
+ "networkIds",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -4213,55 +10201,47 @@ def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationI
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ f"recalculateOrganizationWirelessRadioAutoRfChannels: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
-
- def deleteOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, deploymentId: str):
- """
- **Delete a zero touch deployment**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-devices-provisioning-deployment
-
- - organizationId (string): Organization ID
- - deploymentId (string): Deployment ID
- """
-
- metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "deleteOrganizationWirelessDevicesProvisioningDeployment",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- deploymentId = urllib.parse.quote(str(deploymentId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/{deploymentId}"
-
- return self._session.delete(metadata, resource)
+ return self._session.post(metadata, resource, payload)
- def getOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ def getOrganizationWirelessRadioOverridesByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Query for details on the organization's RadSec device Certificate Authority certificates (CAs)**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities
+ **Return a list of radio overrides**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-overrides-by-device
- organizationId (string): Organization ID
- - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of network IDs. The returned radio overrides will be filtered to only include these networks.
+ - serials (array): A list of serial numbers. The returned radio overrides will be filtered to only include these serials.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
- "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ "tags": ["wireless", "configure", "radio", "overrides", "byDevice"],
+ "operation": "getOrganizationWirelessRadioOverridesByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+ resource = f"/organizations/{organizationId}/wireless/radio/overrides/byDevice"
query_params = [
- "certificateAuthorityIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "certificateAuthorityIds",
+ "networkIds",
+ "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4273,88 +10253,132 @@ def getOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizati
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioOverridesByDevice: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get(metadata, resource, params)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def updateOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ def byOrganizationWirelessRadioRfHealthNeighborsRssiDevice(self, organizationId: str, **kwargs):
"""
- **Update an organization's RadSec device Certificate Authority (CA) state**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-radsec-certificates-authorities
+ **Show the by-device neighbor rssi information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!by-organization-wireless-radio-rf-health-neighbors-rssi-device
- organizationId (string): Organization ID
- - status (string): The "status" to update the Certificate Authority to. Only valid option is "trusted".
- - certificateAuthorityId (string): The ID of the Certificate Authority to update.
+ - networkIds (array): Networks for which information should be gathered.
+ - bands (array): Bands for which information should be gathered. Valid bands are 2.4, 5, and 6.
+ - channels (array): Channel for which information should be gathered.
+ - serials (array): Serial number of the devices for which information should be gathered.
+ - tags (array): Access Point tags for which information should be gathered.
+ - models (array): Access Point models for which information should be gathered.
+ - rfProfiles (array): Rf Profiles for which information should be gathered.
+ - gFloorplanId (string): Geoaligned floorplan ID nodes for which information is gathered belong to.
+ - minimumNeighborRssi (integer): Minimum Neighbor RSSI score for a neighbor entry to be retrieved.
+ - maximumNeighborRssi (integer): Maximum Neighbor RSSI score for a neighbor entry to be retrieved.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
+ - rfScoreInterval (integer): Size of the rf score interval in seconds.
+ - rfScoreRetryOnEmpty (boolean): If true, the query will be retried further back if no data is present in the latest rf score interval.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
- "operation": "updateOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ "tags": ["wireless", "configure", "radio", "rfHealth", "neighbors", "rssi"],
+ "operation": "byOrganizationWirelessRadioRfHealthNeighborsRssiDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+ resource = f"/organizations/{organizationId}/wireless/radio/rfHealth/neighbors/rssi/byDevice"
- body_params = [
- "status",
- "certificateAuthorityId",
+ query_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
+ "gFloorplanId",
+ "minimumNeighborRssi",
+ "maximumNeighborRssi",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ "rfScoreInterval",
+ "rfScoreRetryOnEmpty",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ f"byOrganizationWirelessRadioRfHealthNeighborsRssiDevice: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
-
- def createOrganizationWirelessDevicesRadsecCertificatesAuthority(self, organizationId: str):
- """
- **Create an organization's RadSec device Certificate Authority (CA)**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-radsec-certificates-authority
-
- - organizationId (string): Organization ID
- """
-
- metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
- "operation": "createOrganizationWirelessDevicesRadsecCertificatesAuthority",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
-
- return self._session.post(metadata, resource)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls(self, organizationId: str, **kwargs):
+ def getOrganizationWirelessRadioRfHealthOverviewByNetworkByInterval(self, organizationId: str, **kwargs):
"""
- **Query for certificate revocation list (CRL) for the organization's RadSec device Certificate Authorities (CAs).**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls
+ **Show the by-network RF Health score overview information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-rf-health-overview-by-network-by-interval
- organizationId (string): Organization ID
- - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 182 days, 14 hours, 54 minutes, and 36 seconds from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days, 10 hours, 29 minutes, and 6 seconds after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days, 10 hours, 29 minutes, and 6 seconds. The default is 14 days. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 7200, 86400. The default is 7200. Interval is calculated if time params are provided.
+ - networkIds (array): Networks for which information should be gathered.
+ - bands (array): Bands for which information should be gathered. Valid bands are 2.4, 5, and 6.
+ - minimumRfHealthScore (integer): Minimum RF Health score for a network to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for a network to be retrieved.
+ - minimumHighCciPercentage (integer): Minimum percentage of radios with high CCI for a network to be retrieved.
+ - maximumHighCciPercentage (integer): Maximum percentage of radios with high CCI for a network to be retrieved.
+ - minimumChannelChanges (integer): Minimum number of channel changes for a network to be retrieved.
+ - maximumChannelChanges (integer): Maximum number of channel changes for a network to be retrieved.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls"],
- "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls",
+ "tags": ["wireless", "configure", "radio", "rfHealth", "overview", "byNetwork", "byInterval"],
+ "operation": "getOrganizationWirelessRadioRfHealthOverviewByNetworkByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls"
+ resource = f"/organizations/{organizationId}/wireless/radio/rfHealth/overview/byNetwork/byInterval"
query_params = [
- "certificateAuthorityIds",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "bands",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ "minimumHighCciPercentage",
+ "maximumHighCciPercentage",
+ "minimumChannelChanges",
+ "maximumChannelChanges",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "certificateAuthorityIds",
+ "networkIds",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4366,36 +10390,52 @@ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls(self, organi
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioRfHealthOverviewByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get(metadata, resource, params)
- def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas(self, organizationId: str, **kwargs):
+ def getOrganizationWirelessRadioRrmByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Query for all delta certificate revocation list (CRL) for the organization's RadSec device Certificate Authority (CA) with the given id.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls-deltas
+ **List the AutoRF settings of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-rrm-by-network
- organizationId (string): Organization ID
- - certificateAuthorityIds (array): Parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter results by network.
+ - startingAfter (string): Retrieving items after this network ID
+ - endingBefore (string): Retrieving items before this network ID
+ - perPage (integer): Number of items per page
+ - sortOrder (string): The sort order of items
"""
kwargs.update(locals())
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls", "deltas"],
- "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas",
+ "tags": ["wireless", "configure", "radio", "rrm", "byNetwork"],
+ "operation": "getOrganizationWirelessRadioRrmByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls/deltas"
+ resource = f"/organizations/{organizationId}/wireless/radio/rrm/byNetwork"
query_params = [
- "certificateAuthorityIds",
+ "networkIds",
+ "startingAfter",
+ "endingBefore",
+ "perPage",
+ "sortOrder",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "certificateAuthorityIds",
+ "networkIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4407,47 +10447,31 @@ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas(self,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioRrmByNetwork: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get(metadata, resource, params)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesSystemCpuLoadHistory(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationWirelessRadioStatusByNetwork(self, organizationId: str, **kwargs):
"""
- **Return the CPU Load history for a list of wireless devices in the organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-system-cpu-load-history
+ **Show the status of this organization's radios, categorized by network and device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-status-by-network
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
- - serials (array): Optional parameter to filter device availabilities history by device serial numbers
+ - networkIds (array): Networks for which radio status should be returned.
+ - serials (array): Serials for which radio status should be returned.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "system", "cpu", "load", "history"],
- "operation": "getOrganizationWirelessDevicesSystemCpuLoadHistory",
+ "tags": ["wireless", "configure", "radio", "status", "byNetwork"],
+ "operation": "getOrganizationWirelessRadioStatusByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/system/cpu/load/history"
+ resource = f"/organizations/{organizationId}/wireless/radio/status/byNetwork"
query_params = [
- "t0",
- "t1",
- "timespan",
- "perPage",
- "startingAfter",
- "endingBefore",
"networkIds",
"serials",
]
@@ -4467,52 +10491,66 @@ def getOrganizationWirelessDevicesSystemCpuLoadHistory(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesSystemCpuLoadHistory: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioStatusByNetwork: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessDevicesWirelessControllersByDevice(
+ def getOrganizationWirelessRfProfilesAssignmentsByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **List of Catalyst access points information**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-wireless-controllers-by-device
+ **List the RF profiles of an organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-rf-profiles-assignments-by-device
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): Optional parameter to filter access points by network ID. This filter uses multiple exact matches.
- - serials (array): Optional parameter to filter access points by its cloud ID. This filter uses multiple exact matches.
- - controllerSerials (array): Optional parameter to filter access points by its wireless LAN controller cloud ID. This filter uses multiple exact matches.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter devices by network.
+ - productTypes (array): Optional parameter to filter devices by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
+ - name (string): Optional parameter to filter RF profiles by device name. All returned devices will have a name that contains the search term or is an exact match.
+ - mac (string): Optional parameter to filter RF profiles by device MAC address. All returned devices will have a MAC address that contains the search term or is an exact match.
+ - serial (string): Optional parameter to filter RF profiles by device serial number. All returned devices will have a serial number that contains the search term or is an exact match.
+ - model (string): Optional parameter to filter RF profiles by device model. All returned devices will have a model that contains the search term or is an exact match.
+ - macs (array): Optional parameter to filter RF profiles by one or more device MAC addresses. All returned devices will have a MAC address that is an exact match.
+ - serials (array): Optional parameter to filter RF profiles by one or more device serial numbers. All returned devices will have a serial number that is an exact match.
+ - models (array): Optional parameter to filter RF profiles by one or more device models. All returned devices will have a model that is an exact match.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "wirelessControllers", "byDevice"],
- "operation": "getOrganizationWirelessDevicesWirelessControllersByDevice",
+ "tags": ["wireless", "configure", "rfProfiles", "assignments", "byDevice"],
+ "operation": "getOrganizationWirelessRfProfilesAssignmentsByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/wirelessControllers/byDevice"
+ resource = f"/organizations/{organizationId}/wireless/rfProfiles/assignments/byDevice"
query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
"networkIds",
+ "productTypes",
+ "name",
+ "mac",
+ "serial",
+ "model",
+ "macs",
"serials",
- "controllerSerials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "models",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "productTypes",
+ "macs",
"serials",
- "controllerSerials",
+ "models",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4524,39 +10562,39 @@ def getOrganizationWirelessDevicesWirelessControllersByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesWirelessControllersByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRfProfilesAssignmentsByDevice: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessLocationScanningByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessRoamingByNetworkByInterval(self, organizationId: str, networkIds: list, **kwargs):
"""
- **Return scanning API settings**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-by-network
+ **Get all wireless clients' roam events within the specified timespan grouped by network and time interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-roaming-by-network-by-interval
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter scanning settings by network ID.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 1800, 3600, 7200, 10800, 14400, 18000, 21600, 25200, 28800, 32400, 36000, 39600, 43200, 86400, 604800. The default is 7200.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "byNetwork"],
- "operation": "getOrganizationWirelessLocationScanningByNetwork",
+ "tags": ["wireless", "monitor", "roaming", "byNetwork", "byInterval"],
+ "operation": "getOrganizationWirelessRoamingByNetworkByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/byNetwork"
+ resource = f"/organizations/{organizationId}/wireless/roaming/byNetwork/byInterval"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
"networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -4573,44 +10611,49 @@ def getOrganizationWirelessLocationScanningByNetwork(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessLocationScanningByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRoamingByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessLocationScanningReceivers(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Return scanning API receivers**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-receivers
+ **List the L2 isolation allow list MAC entry in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-firewall-isolation-allowlist-entries
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter scanning API receivers by network ID.
+ - networkIds (array): networkIds array to filter out results
+ - ssids (array): ssids number array to filter out results
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "getOrganizationWirelessLocationScanningReceivers",
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
"networkIds",
+ "ssids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "ssids",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4622,41 +10665,39 @@ def getOrganizationWirelessLocationScanningReceivers(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessLocationScanningReceivers: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def createOrganizationWirelessLocationScanningReceiver(
- self, organizationId: str, network: dict, url: str, version: str, radio: dict, sharedSecret: str, **kwargs
+ def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
+ self, organizationId: str, client: dict, ssid: dict, network: dict, **kwargs
):
"""
- **Add new receiver for scanning API**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-location-scanning-receiver
+ **Create isolation allow list MAC entry for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-firewall-isolation-allowlist-entry
- organizationId (string): Organization ID
- - network (object): Add scanning API receiver for network
- - url (string): Receiver Url
- - version (string): Scanning API Version
- - radio (object): Add scanning API Radio
- - sharedSecret (string): Secret Value for Receiver
+ - client (object): The client of allowlist
+ - ssid (object): The SSID that allowlist belongs to
+ - network (object): The Network that allowlist belongs to
+ - description (string): The description of mac address
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "createOrganizationWirelessLocationScanningReceiver",
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
body_params = [
+ "description",
+ "client",
+ "ssid",
"network",
- "url",
- "version",
- "radio",
- "sharedSecret",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -4665,37 +10706,54 @@ def createOrganizationWirelessLocationScanningReceiver(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"createOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ f"createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
)
return self._session.post(metadata, resource, payload)
- def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str, **kwargs):
+ def deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str):
"""
- **Change scanning API receiver settings**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-location-scanning-receiver
+ **Destroy isolation allow list MAC entry for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-firewall-isolation-allowlist-entry
- organizationId (string): Organization ID
- - receiverId (string): Receiver ID
- - url (string): Receiver Url
- - version (string): Scanning API Version
- - radio (object): Add scanning API Radio
+ - entryId (string): Entry ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ entryId = urllib.parse.quote(str(entryId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str, **kwargs):
+ """
+ **Update isolation allow list MAC entry info**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-firewall-isolation-allowlist-entry
+
+ - organizationId (string): Organization ID
+ - entryId (string): Entry ID
+ - description (string): The description of mac address
+ - client (object): The client of allowlist
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "updateOrganizationWirelessLocationScanningReceiver",
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- receiverId = urllib.parse.quote(str(receiverId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
+ entryId = urllib.parse.quote(str(entryId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
body_params = [
- "url",
- "version",
- "radio",
+ "description",
+ "client",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -4704,58 +10762,41 @@ def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ f"updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
)
return self._session.put(metadata, resource, payload)
- def deleteOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str):
- """
- **Delete a scanning API receiver**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-location-scanning-receiver
-
- - organizationId (string): Organization ID
- - receiverId (string): Receiver ID
- """
-
- metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "deleteOrganizationWirelessLocationScanningReceiver",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- receiverId = urllib.parse.quote(str(receiverId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
-
- return self._session.delete(metadata, resource)
-
- def getOrganizationWirelessMqttSettings(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessSsidsOpenRoamingByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Return MQTT Settings for networks**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-mqtt-settings
+ **Returns an array of objects, each containing SSID OpenRoaming configs for the corresponding network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-open-roaming-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter mqtt settings by network ID.
+ - networkIds (array): Optional parameter to filter OpenRoaming configuration by Network Id.
+ - includeDisabledSsids (boolean): Optional parameter to include OpenRoaming configuration for disabled ssids.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "mqtt", "settings"],
- "operation": "getOrganizationWirelessMqttSettings",
+ "tags": ["wireless", "configure", "ssids", "openRoaming", "byNetwork"],
+ "operation": "getOrganizationWirelessSsidsOpenRoamingByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+ resource = f"/organizations/{organizationId}/wireless/ssids/openRoaming/byNetwork"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
"networkIds",
+ "includeDisabledSsids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -4771,123 +10812,108 @@ def getOrganizationWirelessMqttSettings(self, organizationId: str, total_pages=1
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationWirelessSsidsOpenRoamingByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def updateOrganizationWirelessMqttSettings(self, organizationId: str, network: dict, mqtt: dict, **kwargs):
+ def getOrganizationWirelessSsidsPoliciesClientExclusionBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Add new broker config for wireless MQTT**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-mqtt-settings
+ **Returns an array of objects, each containing client exclusion enablement statuses for one SSID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-policies-client-exclusion-by-ssid
- organizationId (string): Organization ID
- - network (object): Add MQTT Settings for network
- - mqtt (object): MQTT Settings for network
- - ble (object): MQTT BLE Settings for network
- - wifi (object): MQTT Wi-Fi Settings for network
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter by Network ID.
+ - includeDisabledSsids (boolean): Optional parameter to include disabled SSID's.
+ - ssidNumbers (array): Optional parameter to filter by SSID numbers.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "mqtt", "settings"],
- "operation": "updateOrganizationWirelessMqttSettings",
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "bySsid"],
+ "operation": "getOrganizationWirelessSsidsPoliciesClientExclusionBySsid",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+ resource = f"/organizations/{organizationId}/wireless/ssids/policies/clientExclusion/bySsid"
- body_params = [
- "network",
- "mqtt",
- "ble",
- "wifi",
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "includeDisabledSsids",
+ "ssidNumbers",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
-
- if self._session._validate_kwargs:
- all_params = [] + body_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(
- f"updateOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}"
- )
-
- return self._session.put(metadata, resource, payload)
-
- def recalculateOrganizationWirelessRadioAutoRfChannels(self, organizationId: str, networkIds: list, **kwargs):
- """
- **Recalculates automatically assigned channels for every AP within specified the specified network(s)**
- https://developer.cisco.com/meraki/api-v1/#!recalculate-organization-wireless-radio-auto-rf-channels
-
- - organizationId (string): Organization ID
- - networkIds (array): A list of network ids (limit: 15).
- """
-
- kwargs = locals()
-
- metadata = {
- "tags": ["wireless", "configure", "radio", "autoRf", "channels"],
- "operation": "recalculateOrganizationWirelessRadioAutoRfChannels",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/recalculate"
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- body_params = [
+ array_params = [
"networkIds",
+ "ssidNumbers",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"recalculateOrganizationWirelessRadioAutoRfChannels: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsPoliciesClientExclusionBySsid: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.post(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessRadioRrmByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
- """
- **List the AutoRF settings of an organization by network**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-rrm-by-network
+ def getOrganizationWirelessSsidsPoliciesClientExclusionStaticExclusionsBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns an array of objects, each containing a list of MAC's excluded from a given SSID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-policies-client-exclusion-static-exclusions-by-ssid
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): Optional parameter to filter results by network.
- - startingAfter (string): Retrieving items after this network ID
- - endingBefore (string): Retrieving items before this network ID
- - perPage (integer): Number of items per page
- - sortOrder (string): The sort order of items
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter Network ID.
+ - includeDisabledSsids (boolean): Optional parameter to include disabled SSID's.
+ - ssidNumbers (array): Optional parameter to filter by SSID numbers.
"""
kwargs.update(locals())
- if "sortOrder" in kwargs:
- options = ["ascending", "descending"]
- assert kwargs["sortOrder"] in options, (
- f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
- )
-
metadata = {
- "tags": ["wireless", "configure", "radio", "rrm", "byNetwork"],
- "operation": "getOrganizationWirelessRadioRrmByNetwork",
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions", "bySsid"],
+ "operation": "getOrganizationWirelessSsidsPoliciesClientExclusionStaticExclusionsBySsid",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/radio/rrm/byNetwork"
+ resource = f"/organizations/{organizationId}/wireless/ssids/policies/clientExclusion/static/exclusions/bySsid"
query_params = [
- "networkIds",
+ "perPage",
"startingAfter",
"endingBefore",
- "perPage",
- "sortOrder",
+ "networkIds",
+ "includeDisabledSsids",
+ "ssidNumbers",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "ssidNumbers",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4899,66 +10925,61 @@ def getOrganizationWirelessRadioRrmByNetwork(self, organizationId: str, total_pa
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessRadioRrmByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsPoliciesClientExclusionStaticExclusionsBySsid: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessRfProfilesAssignmentsByDevice(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationWirelessSsidsProfiles(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **List the RF profiles of an organization by device**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-rf-profiles-assignments-by-device
+ **Returns the SSID profiles for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
+ - name (string): (Optional) Filter results by name. Case insensitive substring match.
+ - sortBy (string): Column to sort results by. Default is `name`.
+ - sortOrder (string): Direction to sort results by. Default is `asc`.
+ - profileIds (array): (Optional) Filter results by a list of SSID profile IDs.
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter devices by network.
- - productTypes (array): Optional parameter to filter devices by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
- - name (string): Optional parameter to filter RF profiles by device name. All returned devices will have a name that contains the search term or is an exact match.
- - mac (string): Optional parameter to filter RF profiles by device MAC address. All returned devices will have a MAC address that contains the search term or is an exact match.
- - serial (string): Optional parameter to filter RF profiles by device serial number. All returned devices will have a serial number that contains the search term or is an exact match.
- - model (string): Optional parameter to filter RF profiles by device model. All returned devices will have a model that contains the search term or is an exact match.
- - macs (array): Optional parameter to filter RF profiles by one or more device MAC addresses. All returned devices will have a MAC address that is an exact match.
- - serials (array): Optional parameter to filter RF profiles by one or more device serial numbers. All returned devices will have a serial number that is an exact match.
- - models (array): Optional parameter to filter RF profiles by one or more device models. All returned devices will have a model that is an exact match.
"""
kwargs.update(locals())
+ if "sortBy" in kwargs:
+ options = ["name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "rfProfiles", "assignments", "byDevice"],
- "operation": "getOrganizationWirelessRfProfilesAssignmentsByDevice",
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "getOrganizationWirelessSsidsProfiles",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/rfProfiles/assignments/byDevice"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles"
query_params = [
+ "name",
+ "sortBy",
+ "sortOrder",
+ "profileIds",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "productTypes",
- "name",
- "mac",
- "serial",
- "model",
- "macs",
- "serials",
- "models",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "networkIds",
- "productTypes",
- "macs",
- "serials",
- "models",
+ "profileIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4968,51 +10989,87 @@ def getOrganizationWirelessRfProfilesAssignmentsByDevice(
if self._session._validate_kwargs:
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationWirelessSsidsProfiles: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessSsidsProfile(self, organizationId: str, name: str, ssid: dict, **kwargs):
+ """
+ **Create a new SSID profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the SSID profile
+ - ssid (object): SSID configuration for the profile
+ - precedence (object): Precedence configuration for the SSID profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "createOrganizationWirelessSsidsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles"
+
+ body_params = [
+ "name",
+ "precedence",
+ "ssid",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessRfProfilesAssignmentsByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"createOrganizationWirelessSsidsProfile: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.post(metadata, resource, payload)
- def getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationWirelessSsidsProfilesAssignments(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **List the L2 isolation allow list MAC entry in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-firewall-isolation-allowlist-entries
+ **List the SSID profile assignments in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles-assignments
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): The network IDs to include in the result set.
+ - ssidIds (array): The SSID IDs to include in the result set.
+ - profileIds (array): The SSID profile IDs to include in the result set.
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): networkIds array to filter out results
- - ssids (array): ssids number array to filter out results
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments"],
+ "operation": "getOrganizationWirelessSsidsProfilesAssignments",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
query_params = [
+ "networkIds",
+ "ssidIds",
+ "profileIds",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "ssids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
- "ssids",
+ "ssidIds",
+ "profileIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -5024,37 +11081,33 @@ def getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsProfilesAssignments: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
- self, organizationId: str, client: dict, ssid: dict, network: dict, **kwargs
- ):
+ def createOrganizationWirelessSsidsProfilesAssignment(self, organizationId: str, profile: dict, ssid: dict, **kwargs):
"""
- **Create isolation allow list MAC entry for this organization**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-firewall-isolation-allowlist-entry
+ **Assigns an SSID profile to an SSID in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-profiles-assignment
- organizationId (string): Organization ID
- - client (object): The client of allowlist
- - ssid (object): The SSID that allowlist belongs to
- - network (object): The Network that allowlist belongs to
- - description (string): The description of mac address
+ - profile (object): SSID profile to assign
+ - ssid (object): SSID to assign the SSID profile to
+ - network (object): Network containing the SSID (required if SSID number is used)
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments"],
+ "operation": "createOrganizationWirelessSsidsProfilesAssignment",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
body_params = [
- "description",
- "client",
+ "profile",
"ssid",
"network",
]
@@ -5065,102 +11118,161 @@ def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
+ f"createOrganizationWirelessSsidsProfilesAssignment: ignoring unrecognized kwargs: {invalid}"
)
return self._session.post(metadata, resource, payload)
- def deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str):
+ def deleteOrganizationWirelessSsidsProfilesAssignments(self, organizationId: str, ssid: dict, **kwargs):
"""
- **Destroy isolation allow list MAC entry for this organization**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-firewall-isolation-allowlist-entry
+ **Unassigns the SSID profile assigned to an SSID**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-profiles-assignments
- organizationId (string): Organization ID
- - entryId (string): Entry ID
+ - ssid (object): SSID to delete the SSID profile assignment of
+ - network (object): Network containing the SSID (required if SSID number is used)
"""
+ kwargs.update(locals())
+
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments"],
+ "operation": "deleteOrganizationWirelessSsidsProfilesAssignments",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- entryId = urllib.parse.quote(str(entryId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
return self._session.delete(metadata, resource)
- def updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str, **kwargs):
+ def getOrganizationWirelessSsidsProfilesAssignmentsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Update isolation allow list MAC entry info**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-firewall-isolation-allowlist-entry
+ **List the SSID profile assignments in an organization, grouped by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles-assignments-by-network
- organizationId (string): Organization ID
- - entryId (string): Entry ID
- - description (string): The description of mac address
- - client (object): The client of allowlist
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): The network IDs to include in the result set.
+ - profileIds (array): The SSID profile IDs to include in the result set.
+ - networkGroupIds (array): The network group IDs to include in the result set.
+ - includeAllNetworks (boolean): When set to true, include all networks in the organization, even those without any SSID profile assignments. Defaults to false.
+ - excludeProfileIds (array): The SSID profile IDs to exclude from the result set.
+ - sortBy (string): Optional parameter to specify the field used to sort results. (default: network)
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is asc.
+ - search (string): Optional parameter to search on network name or network group name.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
kwargs.update(locals())
+ if "sortBy" in kwargs:
+ options = ["group", "network"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments", "byNetwork"],
+ "operation": "getOrganizationWirelessSsidsProfilesAssignmentsByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- entryId = urllib.parse.quote(str(entryId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments/byNetwork"
- body_params = [
- "description",
- "client",
+ query_params = [
+ "networkIds",
+ "profileIds",
+ "networkGroupIds",
+ "includeAllNetworks",
+ "excludeProfileIds",
+ "sortBy",
+ "sortOrder",
+ "search",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "profileIds",
+ "networkGroupIds",
+ "excludeProfileIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsProfilesAssignmentsByNetwork: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessSsidsOpenRoamingByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessSsidsProfilesOverviews(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Returns an array of objects, each containing SSID OpenRoaming configs for the corresponding network**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-open-roaming-by-network
+ **Returns the SSID profiles' overview information for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles-overviews
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
+ - name (string): (Optional) Filter results by name. Case insensitive substring match.
+ - sortBy (string): Column to sort results by. Default is `name`.
+ - sortOrder (string): Direction to sort results by. Default is `asc`.
+ - profileIds (array): (Optional) Filter results by a list of SSID profile IDs.
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter OpenRoaming configuration by Network Id.
- - includeDisabledSsids (boolean): Optional parameter to include OpenRoaming configuration for disabled ssids.
"""
kwargs.update(locals())
+ if "sortBy" in kwargs:
+ options = ["name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "ssids", "openRoaming", "byNetwork"],
- "operation": "getOrganizationWirelessSsidsOpenRoamingByNetwork",
+ "tags": ["wireless", "configure", "ssids", "profiles", "overviews"],
+ "operation": "getOrganizationWirelessSsidsProfilesOverviews",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/openRoaming/byNetwork"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/overviews"
query_params = [
+ "name",
+ "sortBy",
+ "sortOrder",
+ "profileIds",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "includeDisabledSsids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "networkIds",
+ "profileIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -5172,11 +11284,67 @@ def getOrganizationWirelessSsidsOpenRoamingByNetwork(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessSsidsOpenRoamingByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsProfilesOverviews: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def updateOrganizationWirelessSsidsProfile(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update this SSID profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the SSID profile
+ - ssid (object): SSID configuration for the profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "updateOrganizationWirelessSsidsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/{id}"
+
+ body_params = [
+ "name",
+ "ssid",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessSsidsProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationWirelessSsidsProfile(self, organizationId: str, id: str):
+ """
+ **Delete an SSID profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "deleteOrganizationWirelessSsidsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationWirelessSsidsStatusesByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List status information of all BSSIDs in your organization**
diff --git a/meraki/aio/api/wirelessController.py b/meraki/aio/api/wirelessController.py
index ee7a75b2..e4cb0e48 100644
--- a/meraki/aio/api/wirelessController.py
+++ b/meraki/aio/api/wirelessController.py
@@ -177,6 +177,59 @@ def getOrganizationWirelessControllerConnections(self, organizationId: str, tota
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationWirelessControllerConnectionsUnassigned(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List of unassigned Catalyst access points and summary information**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-controller-connections-unassigned
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - controllerSerials (array): Optional parameter to filter access points by wireless LAN controller cloud ID. This filter uses multiple exact matches.
+ - supported (boolean): Optional parameter to filter access points based on if they are supported for dashboard monitoring. Values can be true/false, if not provided then all unassigned APs will be returned
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wirelessController", "configure", "connections", "unassigned"],
+ "operation": "getOrganizationWirelessControllerConnectionsUnassigned",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wirelessController/connections/unassigned"
+
+ query_params = [
+ "controllerSerials",
+ "supported",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "controllerSerials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessControllerConnectionsUnassigned: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationWirelessControllerDevicesInterfacesL2ByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
@@ -861,3 +914,36 @@ def getOrganizationWirelessControllerOverviewByDevice(
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def generateOrganizationWirelessControllerRegulatoryDomainPackage(self, organizationId: str, **kwargs):
+ """
+ **Generate the regulatory domain package**
+ https://developer.cisco.com/meraki/api-v1/#!generate-organization-wireless-controller-regulatory-domain-package
+
+ - organizationId (string): Organization ID
+ - networkIds (array): A list of network IDs to filter by
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wirelessController", "configure", "regulatoryDomain", "package"],
+ "operation": "generateOrganizationWirelessControllerRegulatoryDomainPackage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wirelessController/regulatoryDomain/package/generate"
+
+ body_params = [
+ "networkIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"generateOrganizationWirelessControllerRegulatoryDomainPackage: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
diff --git a/meraki/aio/rest_session.py b/meraki/aio/rest_session.py
deleted file mode 100644
index aba94507..00000000
--- a/meraki/aio/rest_session.py
+++ /dev/null
@@ -1,507 +0,0 @@
-import asyncio
-import json
-import random
-import ssl
-import urllib.parse
-from datetime import datetime
-
-import aiohttp
-
-from meraki._version import __version__
-from meraki.common import (
- check_python_version,
- reject_v0_base_url,
- validate_user_agent,
-)
-from meraki.config import (
- ACTION_BATCH_RETRY_WAIT_TIME,
- AIO_MAXIMUM_CONCURRENT_REQUESTS,
- BE_GEO_ID,
- CERTIFICATE_PATH,
- DEFAULT_BASE_URL,
- MAXIMUM_RETRIES,
- MERAKI_PYTHON_SDK_CALLER,
- NETWORK_DELETE_RETRY_WAIT_TIME,
- NGINX_429_RETRY_WAIT_TIME,
- REQUESTS_PROXY,
- RETRY_4XX_ERROR,
- RETRY_4XX_ERROR_WAIT_TIME,
- SIMULATE_API_CALLS,
- SINGLE_REQUEST_TIMEOUT,
- USE_ITERATOR_FOR_GET_PAGES,
- WAIT_ON_RATE_LIMIT,
-)
-from meraki.exceptions import APIError, AsyncAPIError
-
-
-# Main module interface
-class AsyncRestSession:
- def __init__(
- self,
- logger,
- api_key,
- base_url=DEFAULT_BASE_URL,
- single_request_timeout=SINGLE_REQUEST_TIMEOUT,
- certificate_path=CERTIFICATE_PATH,
- requests_proxy=REQUESTS_PROXY,
- wait_on_rate_limit=WAIT_ON_RATE_LIMIT,
- nginx_429_retry_wait_time=NGINX_429_RETRY_WAIT_TIME,
- action_batch_retry_wait_time=ACTION_BATCH_RETRY_WAIT_TIME,
- network_delete_retry_wait_time=NETWORK_DELETE_RETRY_WAIT_TIME,
- retry_4xx_error=RETRY_4XX_ERROR,
- retry_4xx_error_wait_time=RETRY_4XX_ERROR_WAIT_TIME,
- maximum_retries=MAXIMUM_RETRIES,
- simulate=SIMULATE_API_CALLS,
- be_geo_id=BE_GEO_ID,
- caller=MERAKI_PYTHON_SDK_CALLER,
- use_iterator_for_get_pages=USE_ITERATOR_FOR_GET_PAGES,
- maximum_concurrent_requests=AIO_MAXIMUM_CONCURRENT_REQUESTS,
- validate_kwargs=False,
- ):
- super().__init__()
-
- # Initialize attributes and properties
- self._version = __version__
- self._api_key = str(api_key)
- self._base_url = str(base_url)
- self._single_request_timeout = single_request_timeout
- self._certificate_path = certificate_path
- self._requests_proxy = requests_proxy
- self._wait_on_rate_limit = wait_on_rate_limit
- self._nginx_429_retry_wait_time = nginx_429_retry_wait_time
- self._action_batch_retry_wait_time = action_batch_retry_wait_time
- self._network_delete_retry_wait_time = network_delete_retry_wait_time
- self._retry_4xx_error = retry_4xx_error
- self._retry_4xx_error_wait_time = retry_4xx_error_wait_time
- self._maximum_retries = maximum_retries
- self._simulate = simulate
- self._concurrent_requests_semaphore = asyncio.Semaphore(maximum_concurrent_requests)
- self._be_geo_id = be_geo_id
- self._caller = caller
- self.use_iterator_for_get_pages = use_iterator_for_get_pages
- self._validate_kwargs = validate_kwargs
-
- # Check minimum Python version
- check_python_version()
-
- # Check base URL
- reject_v0_base_url(self)
-
- # Update the headers for the session
- self._headers = {
- "Authorization": "Bearer " + self._api_key,
- "Content-Type": "application/json",
- "User-Agent": f"python-meraki/aio-{self._version} " + validate_user_agent(self._be_geo_id, self._caller),
- }
- if self._certificate_path:
- self._sslcontext = ssl.create_default_context()
- self._sslcontext.load_verify_locations(certificate_path)
-
- # Initialize a new `aiohttp` session
- self._req_session = aiohttp.ClientSession(
- headers=self._headers,
- timeout=aiohttp.ClientTimeout(total=single_request_timeout),
- )
-
- # Log API calls
- self._logger = logger
- self._parameters = {"version": self._version}
- self._parameters.update(locals())
- self._parameters.pop("self")
- self._parameters.pop("logger")
- self._parameters.pop("__class__")
- self._parameters["api_key"] = "*" * 36 + self._api_key[-4:]
- if self._logger:
- self._logger.info(f"Meraki dashboard API session initialized with these parameters: {self._parameters}")
-
- @property
- def use_iterator_for_get_pages(self):
- return self._use_iterator_for_get_pages
-
- @use_iterator_for_get_pages.setter
- def use_iterator_for_get_pages(self, value):
- if value:
- self.get_pages = self._get_pages_iterator
- else:
- self.get_pages = self._get_pages_legacy
-
- self._use_iterator_for_get_pages = value
-
- async def request(self, metadata, method, url, **kwargs):
- return await self._request(metadata, method, url, allow_redirects=False, **kwargs)
-
- async def _request(self, metadata, method, url, **kwargs):
- # Metadata on endpoint
- tag = metadata["tags"][0]
- operation = metadata["operation"]
-
- # Update request kwargs with session defaults
- if self._certificate_path:
- kwargs.setdefault("ssl", self._sslcontext)
- if self._requests_proxy:
- kwargs.setdefault("proxy", self._requests_proxy)
- kwargs.setdefault("timeout", self._single_request_timeout)
-
- # Ensure proper base URL
- allowed_domains = ["meraki.com", "meraki.cn"]
-
- # aiohttp manipulates URLs as instances of the yarl.URL class
- if not isinstance(url, str):
- url = str(url)
-
- parsed_url = urllib.parse.urlparse(url)
-
- if any(domain in parsed_url.netloc for domain in allowed_domains):
- abs_url = url
- else:
- abs_url = self._base_url + url
-
- # Set maximum number of retries
- retries = self._maximum_retries
-
- # Option to simulate non-safe API calls without actually sending them
- if self._logger:
- self._logger.debug(metadata)
- if self._simulate and method != "GET":
- if self._logger:
- self._logger.info(f"{tag}, {operation} > {abs_url} - SIMULATED")
- return None
- else:
- response = None
- message = None
- for _attempt in range(retries):
- # Make sure that the response object gets closed during retries
- if response:
- response.release()
- response = None
-
- # Acquire semaphore only for the HTTP call, not retry waits
- async with self._concurrent_requests_semaphore:
- try:
- if self._logger:
- self._logger.info(f"{method} {abs_url}")
- response = await self._req_session.request(method, abs_url, **kwargs)
- reason = response.reason if response.reason else None
- status = response.status
- except Exception as e:
- if self._logger:
- self._logger.warning(f"{tag}, {operation} > {abs_url} - {e}, retrying in 1 second")
- await asyncio.sleep(1)
- continue
-
- if 200 <= status < 300:
- if "page" in metadata:
- counter = metadata["page"]
- if self._logger:
- self._logger.info(f"{tag}, {operation}; page {counter} > {abs_url} - {status} {reason}")
- else:
- if self._logger:
- self._logger.info(f"{tag}, {operation} > {abs_url} - {status} {reason}")
- # For non-empty response to GET, ensure valid JSON
- try:
- if method == "GET":
- await response.json(content_type=None)
- return response
- except (
- json.decoder.JSONDecodeError,
- aiohttp.client_exceptions.ContentTypeError,
- ) as e:
- if self._logger:
- self._logger.warning(f"{tag}, {operation} > {abs_url} - {e}, retrying in 1 second")
- await asyncio.sleep(1)
- # Handle 3XX redirects automatically
- elif 300 <= status < 400:
- abs_url = response.headers["Location"]
- substring = "meraki.com/api/v"
- if substring not in abs_url:
- substring = "meraki.cn/api/v"
- self._base_url = abs_url[: abs_url.find(substring) + len(substring) + 1]
- # Rate limit 429 errors
- elif status == 429:
- if "Retry-After" in response.headers:
- wait = int(response.headers["Retry-After"])
- else:
- wait = min(
- (2**_attempt) * (1 + random.random()),
- self._nginx_429_retry_wait_time,
- )
- if self._logger:
- self._logger.warning(f"{tag}, {operation} > {abs_url} - {status} {reason}, retrying in {wait} seconds")
- await asyncio.sleep(wait)
- # 5XX errors
- elif status >= 500:
- request_id = response.headers.get("X-Request-Id") or "none"
- if self._logger:
- self._logger.warning(
- f"{tag}, {operation} > {abs_url} - {status} {reason} "
- f"(X-Request-Id: {request_id}), retrying in 1 second"
- )
- if _attempt == retries - 1:
- self._logger.error(
- f"{tag}, {operation} > {abs_url} - {status} {reason} failed after retries. "
- f"Provide this X-Request-Id to Meraki for log lookup: {request_id}"
- )
- await asyncio.sleep(1)
- # 4XX errors
- else:
- try:
- message = await response.json(content_type=None)
- if isinstance(message, dict):
- message_is_dict = True
- else:
- message_is_dict = False
- except (
- json.decoder.JSONDecodeError,
- aiohttp.client_exceptions.ContentTypeError,
- ):
- message_is_dict = False
- try:
- message = (await response.text())[:100]
- except Exception:
- message = None
-
- # Check for specific concurrency errors
- network_delete_concurrency_error_text = "This may be due to concurrent requests to delete networks."
- action_batch_concurrency_error = {
- "errors": [
- "Too many concurrently executing batches. Maximum is 5 confirmed but not yet executed batches."
- ]
- }
- # Check specifically for network delete concurrency error
- if (
- message_is_dict
- and "errors" in message.keys()
- and network_delete_concurrency_error_text in message["errors"][0]
- ):
- wait = random.randint(15, self._network_delete_retry_wait_time)
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
- await asyncio.sleep(wait)
- retries -= 1
- if retries == 0:
- raise APIError(metadata, response)
- # Check specifically for action batch concurrency error
- elif message == action_batch_concurrency_error:
- wait = self._action_batch_retry_wait_time
- if self._logger:
- self._logger.warning(
- f"{tag}, {operation} > {abs_url} - {status} {reason}, retrying in {wait} seconds"
- )
- await asyncio.sleep(wait)
-
- elif self._retry_4xx_error:
- wait = random.randint(1, self._retry_4xx_error_wait_time)
- if self._logger:
- self._logger.warning(
- f"{tag}, {operation} > {abs_url} - {status} {reason}, retrying in {wait} seconds"
- )
- await asyncio.sleep(wait)
-
- # All other client-side errors
- else:
- if self._logger:
- self._logger.error(f"{tag}, {operation} > {abs_url} - {status} {reason}, {message}")
- raise AsyncAPIError(metadata, response, message)
- raise AsyncAPIError(metadata, response, "Reached retry limit: " + str(message))
-
- async def get(self, metadata, url, params=None):
- metadata["method"] = "GET"
- metadata["url"] = url
- metadata["params"] = params
- async with await self.request(metadata, "GET", url, params=params) as response:
- return await response.json(content_type=None)
-
- async def get_pages(
- self,
- metadata,
- url,
- params=None,
- total_pages=-1,
- direction="next",
- event_log_end_time=None,
- ):
- pass
-
- async def _download_page(self, request):
- response = await request
- result = await response.json(content_type=None)
- return response, result
-
- async def _get_pages_iterator(
- self,
- metadata,
- url,
- params=None,
- total_pages=-1,
- direction="next",
- event_log_end_time=None,
- ):
- if isinstance(total_pages, str) and total_pages.lower() == "all":
- total_pages = -1
- elif isinstance(total_pages, str) and total_pages.isnumeric():
- total_pages = int(total_pages)
- metadata["page"] = 1
-
- request_task = asyncio.create_task(self._download_page(self.request(metadata, "GET", url, params=params)))
-
- # Get additional pages if more than one requested
- while total_pages != 0:
- response, results = await request_task
- links = response.links
-
- # GET the subsequent page
- if direction == "next" and "next" in links:
- # Prevent getNetworkEvents from infinite loop as time goes forward
- if metadata["operation"] == "getNetworkEvents":
- starting_after = urllib.parse.unquote(str(links["next"]["url"]).split("startingAfter=")[1])
- delta = datetime.utcnow() - datetime.fromisoformat(starting_after[:-1])
- # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
- if delta.total_seconds() < 300:
- break
- # Or if next page is past the specified window's end time
- elif event_log_end_time and starting_after > event_log_end_time:
- break
-
- metadata["page"] += 1
- nextlink = links["next"]["url"]
- elif direction == "prev" and "prev" in links:
- # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
- if metadata["operation"] == "getNetworkEvents":
- ending_before = urllib.parse.unquote(str(links["prev"]["url"]).split("endingBefore=")[1])
- # Break out of loop if endingBefore returned from prev link is before 2014
- if ending_before < "2014-01-01":
- break
-
- metadata["page"] += 1
- nextlink = links["prev"]["url"]
- else:
- total_pages = 1
-
- response.release()
-
- total_pages = total_pages - 1
-
- if total_pages != 0:
- request_task = asyncio.create_task(self._download_page(self.request(metadata, "GET", nextlink)))
-
- return_items = []
- # just prepare the list
- if isinstance(results, list):
- return_items = results
- elif isinstance(results, dict) and "items" in results:
- return_items = results["items"]
- # For event log endpoint
- elif isinstance(results, dict):
- if direction == "next":
- return_items = results["events"][::-1]
- else:
- return_items = results["events"]
-
- for item in return_items:
- yield item
-
- async def _get_pages_legacy(
- self,
- metadata,
- url,
- params=None,
- total_pages=-1,
- direction="next",
- event_log_end_time=None,
- ):
- if isinstance(total_pages, str) and total_pages.lower() == "all":
- total_pages = -1
- elif isinstance(total_pages, str) and total_pages.isnumeric():
- total_pages = int(total_pages)
- metadata["page"] = 1
-
- async with await self.request(metadata, "GET", url, params=params) as response:
- results = await response.json(content_type=None)
-
- # For event log endpoint when using 'next' direction, so results/events are sorted chronologically
- if isinstance(results, dict) and metadata["operation"] == "getNetworkEvents" and direction == "next":
- results["events"] = results["events"][::-1]
-
- links = response.links
-
- # Get additional pages if more than one requested
- while total_pages != 1:
- # GET the subsequent page
- if direction == "next" and "next" in links:
- # Prevent getNetworkEvents from infinite loop as time goes forward
- if metadata["operation"] == "getNetworkEvents":
- starting_after = urllib.parse.unquote(str(links["next"]["url"]).split("startingAfter=")[1])
- delta = datetime.utcnow() - datetime.fromisoformat(starting_after[:-1])
- # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
- if delta.total_seconds() < 300:
- break
- # Or if next page is past the specified window's end time
- elif event_log_end_time and starting_after > event_log_end_time:
- break
-
- metadata["page"] += 1
- nextlink = links["next"]["url"]
- elif direction == "prev" and "prev" in links:
- # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
- if metadata["operation"] == "getNetworkEvents":
- ending_before = urllib.parse.unquote(str(links["prev"]["url"]).split("endingBefore=")[1])
- # Break out of loop if endingBefore returned from prev link is before 2014
- if ending_before < "2014-01-01":
- break
-
- metadata["page"] += 1
- nextlink = links["prev"]["url"]
- else:
- break
-
- async with await self.request(metadata, "GET", nextlink) as response:
- links = response.links
- # Append that page's results, depending on the endpoint
- if isinstance(results, list):
- results.extend(await response.json(content_type=None))
- elif isinstance(results, dict) and "items" in results:
- json_response = await response.json(content_type=None)
- results["items"].extend(json_response["items"])
- if "meta" in results:
- results["meta"]["counts"]["items"]["remaining"] = json_response["meta"]["counts"]["items"]["remaining"]
- # For event log endpoint
- elif isinstance(results, dict):
- json_response = await response.json(content_type=None)
- start = json_response["pageStartAt"]
- end = json_response["pageEndAt"]
- events = json_response["events"]
- if direction == "next":
- events = events[::-1]
- if start < results["pageStartAt"]:
- results["pageStartAt"] = start
- if end > results["pageEndAt"]:
- results["pageEndAt"] = end
- results["events"].extend(events)
-
- total_pages = total_pages - 1
-
- return results
-
- async def post(self, metadata, url, json=None):
- metadata["method"] = "POST"
- metadata["url"] = url
- metadata["json"] = json
- async with await self.request(metadata, "POST", url, json=json) as response:
- return await response.json(content_type=None)
-
- async def put(self, metadata, url, json=None):
- metadata["method"] = "PUT"
- metadata["url"] = url
- metadata["json"] = json
- async with await self.request(metadata, "PUT", url, json=json) as response:
- return await response.json(content_type=None)
-
- async def delete(self, metadata, url, params=None):
- metadata["method"] = "DELETE"
- metadata["url"] = url
- metadata["params"] = params
- async with await self.request(metadata, "DELETE", url, params=params):
- return None
-
- async def close(self):
- await self._req_session.close()
diff --git a/meraki/api/administered.py b/meraki/api/administered.py
index 5f1be098..43620862 100644
--- a/meraki/api/administered.py
+++ b/meraki/api/administered.py
@@ -67,3 +67,36 @@ def revokeAdministeredIdentitiesMeApiKeys(self, suffix: str):
resource = f"/administered/identities/me/api/keys/{suffix}/revoke"
return self._session.post(metadata, resource)
+
+ def getAdministeredSearchLive(self, query: str, organizationId: str, networkId: str, **kwargs):
+ """
+ **List the appropriate results for a given global search utilizing live_search_react**
+ https://developer.cisco.com/meraki/api-v1/#!get-administered-search-live
+
+ - query (string): Search keywords
+ - organizationId (string): Id of Organization you want to search with
+ - networkId (string): Id of NodeGroup you want to seach with
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["administered", "configure", "search", "live"],
+ "operation": "getAdministeredSearchLive",
+ }
+ resource = "/administered/search/live"
+
+ query_params = [
+ "query",
+ "organizationId",
+ "networkId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getAdministeredSearchLive: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
diff --git a/meraki/api/appliance.py b/meraki/api/appliance.py
index 82023191..7b122133 100644
--- a/meraki/api/appliance.py
+++ b/meraki/api/appliance.py
@@ -34,10 +34,21 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
- personality (object): Describes the port's configurability
- uplink (object): The port's settings when in WAN mode
- downlink (object): The port's VLAN settings when in LAN mode
+ - speed (string): Link speed for the port, in Mbps
+ - duplex (string): Duplex configuration for the port
"""
kwargs.update(locals())
+ if "speed" in kwargs and kwargs["speed"] is not None:
+ options = ["10", "100", "1000", "10000", "2500", "25000", "5000", "auto"]
+ assert kwargs["speed"] in options, f'''"speed" cannot be "{kwargs["speed"]}", & must be set to one of: {options}'''
+ if "duplex" in kwargs and kwargs["duplex"] is not None:
+ options = ["auto", "full", "half"]
+ assert kwargs["duplex"] in options, (
+ f'''"duplex" cannot be "{kwargs["duplex"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
"tags": ["appliance", "configure", "interfaces", "ports", "update"],
"operation": "createDeviceApplianceInterfacesPortsUpdate",
@@ -51,6 +62,8 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
"personality",
"uplink",
"downlink",
+ "speed",
+ "duplex",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -64,6 +77,58 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
return self._session.post(metadata, resource, payload)
+ def updateDeviceApplianceInterfacesPort(self, serial: str, number: str, **kwargs):
+ """
+ **Update configurations for an appliance's specified port**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-appliance-interfaces-port
+
+ - serial (string): Serial
+ - number (string): Number
+ - enabled (boolean): Indicates whether the port is enabled
+ - personality (object): Describes the port's configurability
+ - uplink (object): The port's settings when in WAN mode
+ - downlink (object): The port's VLAN settings when in LAN mode
+ - speed (string): Link speed for the port, in Mbps
+ - duplex (string): Duplex configuration for the port
+ """
+
+ kwargs.update(locals())
+
+ if "speed" in kwargs and kwargs["speed"] is not None:
+ options = ["10", "100", "1000", "10000", "2500", "25000", "5000", "auto"]
+ assert kwargs["speed"] in options, f'''"speed" cannot be "{kwargs["speed"]}", & must be set to one of: {options}'''
+ if "duplex" in kwargs and kwargs["duplex"] is not None:
+ options = ["auto", "full", "half"]
+ assert kwargs["duplex"] in options, (
+ f'''"duplex" cannot be "{kwargs["duplex"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["appliance", "configure", "interfaces", "ports"],
+ "operation": "updateDeviceApplianceInterfacesPort",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/devices/{serial}/appliance/interfaces/ports/{number}"
+
+ body_params = [
+ "enabled",
+ "personality",
+ "uplink",
+ "downlink",
+ "speed",
+ "duplex",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceApplianceInterfacesPort: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getDeviceAppliancePerformance(self, serial: str, **kwargs):
"""
**Return the performance score for a single Secure Appliance or Secure Router**
@@ -1087,6 +1152,7 @@ def createNetworkApplianceInterfacesL3(self, networkId: str, ipv4: dict, **kwarg
- networkId (string): Network ID
- ipv4 (object): IPv4 configuration
- port (object): Port configuration
+ - vrf (object): VRF assignment for the L3 interface
"""
kwargs.update(locals())
@@ -1101,6 +1167,7 @@ def createNetworkApplianceInterfacesL3(self, networkId: str, ipv4: dict, **kwarg
body_params = [
"port",
"ipv4",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1121,6 +1188,7 @@ def updateNetworkApplianceInterfacesL3(self, networkId: str, interfaceId: str, *
- interfaceId (string): Interface ID
- port (object): Port configuration
- ipv4 (object): IPv4 configuration
+ - vrf (object): VRF assignment for the L3 interface
"""
kwargs.update(locals())
@@ -1136,6 +1204,7 @@ def updateNetworkApplianceInterfacesL3(self, networkId: str, interfaceId: str, *
body_params = [
"port",
"ipv4",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1215,6 +1284,8 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs):
- vlan (integer): Native VLAN when the port is in Trunk mode. Access VLAN when the port is in Access mode.
- allowedVlans (string): Comma-delimited list of VLAN IDs (e.g. '2,15') for all devices. Secure Routers also support VLAN ranges (e.g. '2-10,15'). Use 'all' to permit all VLANs on the port.
- accessPolicy (string): The name of the policy. Only applicable to Access ports. Valid values are: 'open', '8021x-radius', 'mac-radius', 'hybris-radius' for MX64 or Z3 or any MX supporting the per port authentication feature. Otherwise, 'open' is the only valid value and 'open' is the default value if the field is missing.
+ - peerSgtCapable (boolean): If true, Peer SGT is enabled for traffic through this port. Applicable to trunk port only, not access port.
+ - adaptivePolicyGroupId (string): Adaptive policy group ID that all traffic originating from this port is assigned to.
- sgt (object): Security Group Tag settings for the port.
"""
@@ -1235,6 +1306,8 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs):
"vlan",
"allowedVlans",
"accessPolicy",
+ "peerSgtCapable",
+ "adaptivePolicyGroupId",
"sgt",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1618,6 +1691,7 @@ def updateNetworkApplianceSecurityIntrusion(self, networkId: str, **kwargs):
- networkId (string): Network ID
- mode (string): Set mode to 'disabled'/'detection'/'prevention' (optional - omitting will leave current config unchanged)
- idsRulesets (string): Set the detection ruleset 'connectivity'/'balanced'/'security' (optional - omitting will leave current config unchanged). Default value is 'balanced' if none currently saved
+ - policy (object): Set a custom intrusion policy by id (optional - omitting will leave current config unchanged)
- protectedNetworks (object): Set the included/excluded networks from the intrusion engine (optional - omitting will leave current config unchanged). This is available only in 'passthrough' mode
"""
@@ -1642,6 +1716,7 @@ def updateNetworkApplianceSecurityIntrusion(self, networkId: str, **kwargs):
body_params = [
"mode",
"idsRulesets",
+ "policy",
"protectedNetworks",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1804,6 +1879,7 @@ def updateNetworkApplianceSingleLan(self, networkId: str, **kwargs):
- applianceIp (string): The appliance IP address of the single LAN
- ipv6 (object): IPv6 configuration on the VLAN
- mandatoryDhcp (object): Mandatory DHCP will enforce that clients connecting to this LAN must use the IP address assigned by the DHCP server. Clients who use a static IP address won't be able to associate. Only available on firmware versions 17.0 and above
+ - vrf (object): VRF configuration on the Single LAN. Omit this field to preserve the current VRF.
"""
kwargs.update(locals())
@@ -1820,6 +1896,7 @@ def updateNetworkApplianceSingleLan(self, networkId: str, **kwargs):
"applianceIp",
"ipv6",
"mandatoryDhcp",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1963,6 +2040,7 @@ def createNetworkApplianceStaticRoute(self, networkId: str, name: str, subnet: s
- subnet (string): Subnet of the route
- gatewayIp (string): Gateway IP address (next hop)
- gatewayVlanId (integer): Gateway VLAN ID
+ - vrf (object): VRF settings for the static route.
"""
kwargs.update(locals())
@@ -1979,6 +2057,7 @@ def createNetworkApplianceStaticRoute(self, networkId: str, name: str, subnet: s
"subnet",
"gatewayIp",
"gatewayVlanId",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2023,6 +2102,7 @@ def updateNetworkApplianceStaticRoute(self, networkId: str, staticRouteId: str,
- enabled (boolean): Whether the route should be enabled or not
- fixedIpAssignments (object): Fixed DHCP IP assignments on the route
- reservedIpRanges (array): DHCP reserved IP ranges
+ - vrf (object): VRF settings for the static route.
"""
kwargs.update(locals())
@@ -2043,6 +2123,7 @@ def updateNetworkApplianceStaticRoute(self, networkId: str, staticRouteId: str,
"enabled",
"fixedIpAssignments",
"reservedIpRanges",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2431,6 +2512,7 @@ def updateNetworkApplianceTrafficShapingVpnExclusions(self, networkId: str, **kw
- networkId (string): Network ID
- custom (array): Custom VPN exclusion rules. Pass an empty array to clear existing rules.
- majorApplications (array): Major Application based VPN exclusion rules. Pass an empty array to clear existing rules.
+ - applications (array): NBAR Application based VPN exclusion rules. Available for networks on >=19.2 firmware
"""
kwargs.update(locals())
@@ -2445,6 +2527,7 @@ def updateNetworkApplianceTrafficShapingVpnExclusions(self, networkId: str, **kw
body_params = [
"custom",
"majorApplications",
+ "applications",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2508,6 +2591,23 @@ def disconnectNetworkApplianceUmbrellaAccount(self, networkId: str):
return self._session.post(metadata, resource)
+ def disableNetworkApplianceUmbrellaProtection(self, networkId: str):
+ """
+ **Disable umbrella protection for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!disable-network-appliance-umbrella-protection
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella"],
+ "operation": "disableNetworkApplianceUmbrellaProtection",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/disableProtection"
+
+ return self._session.delete(metadata, resource)
+
def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs):
"""
**Specify one or more domain names to be excluded from being routed to Cisco Umbrella.**
@@ -2541,6 +2641,54 @@ def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: lis
return self._session.put(metadata, resource, payload)
+ def enableNetworkApplianceUmbrellaProtection(self, networkId: str):
+ """
+ **Enable umbrella protection for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!enable-network-appliance-umbrella-protection
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella"],
+ "operation": "enableNetworkApplianceUmbrellaProtection",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/enableProtection"
+
+ return self._session.post(metadata, resource)
+
+ def policiesNetworkApplianceUmbrella(self, networkId: str, policyIds: list, **kwargs):
+ """
+ **Update umbrella policies applied to MX network.**
+ https://developer.cisco.com/meraki/api-v1/#!policies-network-appliance-umbrella
+
+ - networkId (string): Network ID
+ - policyIds (array): Array of umbrella policy IDs
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella"],
+ "operation": "policiesNetworkApplianceUmbrella",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/policies"
+
+ body_params = [
+ "policyIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"policiesNetworkApplianceUmbrella: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs):
"""
**Add one Cisco Umbrella DNS security policy to an MX network by policy ID**
@@ -2746,6 +2894,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
- dhcpBootNextServer (string): DHCP boot option to direct boot clients to the server to load the boot file from
- dhcpBootFilename (string): DHCP boot option for boot filename
- dhcpOptions (array): The list of DHCP options that will be included in DHCP responses. Each object in the list should have "code", "type", and "value" properties.
+ - adaptivePolicyGroupId (string): Adaptive policy group ID this VLAN is assigned to.
- sgt (object): Security Group Tag settings for the VLAN.
- vrf (object): VRF configuration on the VLAN.
- uplinks (array): Per-uplink NAT exception override configuration on the VLAN. Applicable only for networks that support NAT exceptions.
@@ -2794,6 +2943,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
"dhcpBootNextServer",
"dhcpBootFilename",
"dhcpOptions",
+ "adaptivePolicyGroupId",
"sgt",
"vrf",
"uplinks",
@@ -2902,6 +3052,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
- mask (integer): Mask used for the subnet of all bound to the template networks. Applicable only for template network.
- ipv6 (object): IPv6 configuration on the VLAN
- mandatoryDhcp (object): Mandatory DHCP will enforce that clients connecting to this VLAN must use the IP address assigned by the DHCP server. Clients who use a static IP address won't be able to associate. Only available on firmware versions 17.0 and above
+ - adaptivePolicyGroupId (string): Adaptive policy group ID that all traffic originating from this VLAN is assigned to.
- sgt (object): Security Group Tag settings for the VLAN.
- vrf (object): VRF configuration on the VLAN.
- uplinks (array): Per-uplink NAT exception override configuration on the VLAN. Applicable only for networks that support NAT exceptions.
@@ -2954,6 +3105,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
"mask",
"ipv6",
"mandatoryDhcp",
+ "adaptivePolicyGroupId",
"sgt",
"vrf",
"uplinks",
@@ -3013,12 +3165,22 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
- enabled (boolean): Boolean value to enable or disable the BGP configuration. When BGP is enabled, the asNumber (ASN) will be autopopulated with the preconfigured ASN at other Hubs or a default value if there is no ASN configured.
- asNumber (integer): An Autonomous System Number (ASN) is required if you are to run BGP and peer with another BGP Speaker outside of the Auto VPN domain. This ASN will be applied to the entire Auto VPN domain and is only configurable for Auto VPN BGP networks. The entire 4-byte ASN range is supported. So, the ASN must be an integer between 1 and 4294967295. When absent, this field is not updated. If no value exists then it defaults to 64512.
- ibgpHoldTimer (integer): The iBGP holdtimer in seconds. The iBGP holdtimer must be an integer between 12 and 240. When absent, this field is not updated. If no value exists then it defaults to 240.
+ - ipv6 (object): Settings for IPv6 configurations on the organization.
+ - tunnelDownTermination (object): Settings for tunnel down termination on the organization.
+ - vpnAsNumber (integer): Network specific number of the Autonomous System to which the appliance belongs. This field is only configurable for Independent BGP networks.
+ - priorityRoute (string): Sets the priority route between eBGP and Auto VPN.
- routerId (string): The router ID of the appliance
- neighbors (array): List of BGP neighbors. This list replaces the existing set of neighbors. When absent, this field is not updated.
"""
kwargs.update(locals())
+ if "priorityRoute" in kwargs and kwargs["priorityRoute"] is not None:
+ options = ["Auto VPN", "eBGP"]
+ assert kwargs["priorityRoute"] in options, (
+ f'''"priorityRoute" cannot be "{kwargs["priorityRoute"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
"tags": ["appliance", "configure", "vpn", "bgp"],
"operation": "updateNetworkApplianceVpnBgp",
@@ -3030,6 +3192,10 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
"enabled",
"asNumber",
"ibgpHoldTimer",
+ "ipv6",
+ "tunnelDownTermination",
+ "vpnAsNumber",
+ "priorityRoute",
"routerId",
"neighbors",
]
@@ -3043,6 +3209,41 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkApplianceVpnSiteToSiteHubVrfs(self, networkId: str, hubNetworkId: str, _json: list, **kwargs):
+ """
+ **Update the VRF mappings for a source network and hub pair.**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-appliance-vpn-site-to-site-hub-vrfs
+
+ - networkId (string): Network ID
+ - hubNetworkId (string): Hub network ID
+ - _json (array): The list of VRFs for this source and hub mapping.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "vpn", "siteToSite", "hubs", "vrfs"],
+ "operation": "updateNetworkApplianceVpnSiteToSiteHubVrfs",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ hubNetworkId = urllib.parse.quote(str(hubNetworkId), safe="")
+ resource = f"/networks/{networkId}/appliance/vpn/siteToSite/hubs/{hubNetworkId}/vrfs"
+
+ body_params = [
+ "_json",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkApplianceVpnSiteToSiteHubVrfs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkApplianceVpnSiteToSiteVpn(self, networkId: str):
"""
**Return the site-to-site VPN settings of a network**
@@ -3069,6 +3270,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw
- mode (string): The site-to-site VPN mode. Can be one of 'none', 'spoke' or 'hub'
- hubs (array): The list of VPN hubs, in order of preference. In spoke mode, at least 1 hub is required.
- subnets (array): The list of subnets and their VPN presence.
+ - peerSgtCapable (boolean): Whether or not Peer SGT is enabled for traffic to this VPN peer.
- sgt (object): Security Group Tag settings for the VPN peer.
- subnet (object): Configuration of subnet features
- hostTranslations (array): The list of VPN host translations. Host translations are supported starting from MX firmware version 26.1.2
@@ -3091,6 +3293,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw
"mode",
"hubs",
"subnets",
+ "peerSgtCapable",
"sgt",
"subnet",
"hostTranslations",
@@ -3382,6 +3585,68 @@ def getOrganizationApplianceDevicesRedundancyByNetwork(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationApplianceDevicesSystemUtilizationByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return the appliance utilization history for devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-devices-system-utilization-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 2 hours.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 1200. The default is 1200.
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): Optional parameter to filter device utilization history by device serial numbers
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "devices", "system", "utilization", "byInterval"],
+ "operation": "getOrganizationApplianceDevicesSystemUtilizationByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/devices/system/utilization/byInterval"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceDevicesSystemUtilizationByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApplianceDnsLocalProfiles(self, organizationId: str, **kwargs):
"""
**Fetch the local DNS profiles used in the organization**
@@ -4167,6 +4432,55 @@ def updateOrganizationApplianceRoutingVrfsSettings(self, organizationId: str, en
return self._session.put(metadata, resource, payload)
+ def getOrganizationApplianceSdwanInternetPolicies(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get the SDWAN internet traffic preferences for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-sdwan-internet-policies
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 200. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - wanTrafficUplinkPreferences (array): policies with respective traffic filters for an MX network
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "sdwan", "internetPolicies"],
+ "operation": "getOrganizationApplianceSdwanInternetPolicies",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/sdwan/internetPolicies"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "wanTrafficUplinkPreferences",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "wanTrafficUplinkPreferences",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSdwanInternetPolicies: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApplianceSecurityEvents(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List the security events for an organization**
@@ -4220,6 +4534,58 @@ def getOrganizationApplianceSecurityEvents(self, organizationId: str, total_page
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def httpsiOrganizationApplianceSecurity(self, organizationId: str):
+ """
+ **Retrieve the HTTPS Inspection state for all security appliances in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!httpsi-organization-appliance-security
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security"],
+ "operation": "httpsiOrganizationApplianceSecurity",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/httpsi"
+
+ return self._session.get(metadata, resource)
+
+ def certificatesOrganizationApplianceSecurityHttpsi(self, organizationId: str, contents: str, serials: list, **kwargs):
+ """
+ **Upload an HTTPS Inspection certificate to MX devices in the same organization**
+ https://developer.cisco.com/meraki/api-v1/#!certificates-organization-appliance-security-httpsi
+
+ - organizationId (string): Organization ID
+ - contents (string): The private key and certificate used to inspect HTTPS traffic. The certificate must be in .pem format.
+ - serials (array): Serial numbers of the security appliances that will receive the new HTTPS certificate for HTTPS Inspection
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "httpsi"],
+ "operation": "certificatesOrganizationApplianceSecurityHttpsi",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/httpsi/certificates"
+
+ body_params = [
+ "contents",
+ "serials",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"certificatesOrganizationApplianceSecurityHttpsi: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getOrganizationApplianceSecurityIntrusion(self, organizationId: str):
"""
**Returns all supported intrusion settings for an organization**
@@ -4270,30 +4636,841 @@ def updateOrganizationApplianceSecurityIntrusion(self, organizationId: str, allo
return self._session.put(metadata, resource, payload)
- def getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork(
+ def getOrganizationApplianceSecurityIntrusionPolicies(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Display VPN exclusion rules for MX networks.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-traffic-shaping-vpn-exclusions-by-network
+ **List the intrusion policies configured for an organization along with base policies.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-policies
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter the results by network IDs
+ - mode (string): Controls which policy set is returned.
+ - policyIds (array): Identifiers of policies to filter
+ - search (string): Filter policies by case-insensitive partial match on name or description.
"""
kwargs.update(locals())
+ if "mode" in kwargs:
+ options = ["base", "intrusion"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
metadata = {
- "tags": ["appliance", "configure", "trafficShaping", "vpnExclusions", "byNetwork"],
- "operation": "getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork",
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "getOrganizationApplianceSecurityIntrusionPolicies",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/appliance/trafficShaping/vpnExclusions/byNetwork"
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "mode",
+ "policyIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionPolicies: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, **kwargs):
+ """
+ **Create a new intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policy (object): Attributes for the intrusion policy
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "createOrganizationApplianceSecurityIntrusionPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApplianceSecurityIntrusionPolicy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationApplianceSecurityIntrusionPoliciesOverviews(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List counts for the intrusion and base policies configured for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-policies-overviews
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Identifiers of policies to filter
+ - search (string): Filter policy overviews by case-insensitive partial match on policy name or description.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "overviews"],
+ "operation": "getOrganizationApplianceSecurityIntrusionPoliciesOverviews",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/overviews"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionPoliciesOverviews: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, policyId: str, policy: dict, **kwargs):
+ """
+ **Update a single intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - policy (object): Attributes for the intrusion policy
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "updateOrganizationApplianceSecurityIntrusionPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApplianceSecurityIntrusionPolicy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, policyId: str):
+ """
+ **Delete a single intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies"],
+ "operation": "deleteOrganizationApplianceSecurityIntrusionPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}"
+
+ return self._session.delete(metadata, resource)
+
+ def declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides(
+ self, organizationId: str, policyId: str, items: list, **kwargs
+ ):
+ """
+ **Declare the desired rule group overrides for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!declare-organization-appliance-security-intrusion-policy-rule-groups-overrides
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - items (array): Desired overrides state
+ - mode (string): Controls how the configuration payload in the request body is applied to the resource. This parameter dictates the declarative mode:
+
+ * **`complete`**: The request body represents the entire desired configuration for this resource. Any existing configurations that are not included in the payload will be removed.
+ * **`partial` (default)**: The request body contains only the configurations to be created or modified. Existing configurations that are not specified in the payload will be preserved.
+
+ - recursive (boolean): Controls how the configuration payload in the request body applies to the rule group hierarchy. When true, the API applies each declared override to the rule group itself and its descendants unless the payload explicitly sets a descendant override. When false (default), the API applies overrides only to the rule groups listed in the payload.
+
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["complete", "partial"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "ruleGroups", "overrides"],
+ "operation": "declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/overrides/declare"
+ )
+
+ body_params = [
+ "mode",
+ "recursive",
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride(
+ self, organizationId: str, policyId: str, ruleGroupId: str, override: dict, **kwargs
+ ):
+ """
+ **Create a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy-rule-group-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleGroupId (string): Rule group ID
+ - override (object): Attributes for the override for a rule group in a intrusion policy
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "ruleGroups", "override"],
+ "operation": "createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleGroupId = urllib.parse.quote(str(ruleGroupId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/{ruleGroupId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride(
+ self, organizationId: str, policyId: str, ruleGroupId: str, override: dict, **kwargs
+ ):
+ """
+ **Update a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy-rule-group-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleGroupId (string): Rule group ID
+ - override (object): Attributes for the override for a rule group in a intrusion policy
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "ruleGroups", "override"],
+ "operation": "updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleGroupId = urllib.parse.quote(str(ruleGroupId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/{ruleGroupId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides(
+ self, organizationId: str, policyId: str, items: list, **kwargs
+ ):
+ """
+ **Declare the desired rule overrides for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!declare-organization-appliance-security-intrusion-policy-rules-overrides
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - items (array): Desired overrides state
+ - mode (string): Controls how the configuration payload in the request body is applied to the resource. This parameter dictates the declarative mode:
+
+ * **`complete`**: The request body represents the entire desired configuration for this resource. Any existing configurations that are not included in the payload will be removed. This effectively performs a full replacement or overwrite of the resource's configuration.
+ * **`partial` (default)**: The request body contains only the configurations to be created or modified. Existing configurations that are not specified in the payload will be preserved. This performs a merge or partial update, applying only the changes specified.
+
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["complete", "partial"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "rules", "overrides"],
+ "operation": "declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/overrides/declare"
+
+ body_params = [
+ "mode",
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationApplianceSecurityIntrusionPolicyRuleOverride(
+ self, organizationId: str, policyId: str, ruleId: str, override: dict, **kwargs
+ ):
+ """
+ **Create a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy-rule-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - override (object): Rule override to create
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "rules", "override"],
+ "operation": "createOrganizationApplianceSecurityIntrusionPolicyRuleOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/{ruleId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApplianceSecurityIntrusionPolicyRuleOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride(
+ self, organizationId: str, policyId: str, ruleId: str, override: dict, **kwargs
+ ):
+ """
+ **Update a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy-rule-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - override (object): Override attributes
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "policies", "rules", "override"],
+ "operation": "updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/{ruleId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationApplianceSecurityIntrusionRuleGroups(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the rule groups that belong to a security policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rule-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Collection of base or intrusion policy identifiers to filter results by
+ - parentRuleGroupIds (array): Filter results to rule groups whose parent matches any of the provided identifiers
+ - search (string): Case-insensitive text filter applied to rule group name and description
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRuleGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "parentRuleGroupIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ "parentRuleGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRuleGroups: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceSecurityIntrusionRuleGroupsOverrides(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the rule group overrides configured for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rule-groups-overrides
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Collection of intrusion policy identifiers to filter the overrides by.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups", "overrides"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRuleGroupsOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overrides"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRuleGroupsOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationApplianceSecurityIntrusionRuleGroupsOverride(self, organizationId: str, overrideId: str):
+ """
+ **Delete a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-rule-groups-override
+
+ - organizationId (string): Organization ID
+ - overrideId (string): Override ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups", "overrides"],
+ "operation": "deleteOrganizationApplianceSecurityIntrusionRuleGroupsOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ overrideId = urllib.parse.quote(str(overrideId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overrides/{overrideId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationApplianceSecurityIntrusionRuleGroupsOverviews(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List counts for the child rule groups and rules for each rule group in a security policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rule-groups-overviews
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Collection of base or intrusion policy identifiers to filter results by
+ - parentRuleGroupIds (array): Filter results to rule groups whose parent matches any of the provided identifiers
+ - search (string): Case-insensitive text filter applied to rule group name and description
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "ruleGroups", "overviews"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRuleGroupsOverviews",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overviews"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "parentRuleGroupIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ "parentRuleGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRuleGroupsOverviews: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceSecurityIntrusionRules(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the rules that belong to a security policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Identifiers of the base or intrusion policies to query
+ - parentRuleGroupIds (array): Filter results to rules that belong to any of the specified rule groups
+ - search (string): Case-insensitive text filter applied to rule name and description
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "rules"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ "parentRuleGroupIds",
+ "search",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ "parentRuleGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceSecurityIntrusionRulesOverrides(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the rule overrides configured for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-security-intrusion-rules-overrides
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 25.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - policyIds (array): Identifiers of intrusion policies to filter
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "rules", "overrides"],
+ "operation": "getOrganizationApplianceSecurityIntrusionRulesOverrides",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules/overrides"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "policyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceSecurityIntrusionRulesOverrides: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationApplianceSecurityIntrusionRulesOverride(self, organizationId: str, overrideId: str):
+ """
+ **Delete a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-rules-override
+
+ - organizationId (string): Organization ID
+ - overrideId (string): Override ID
+ """
+
+ metadata = {
+ "tags": ["appliance", "configure", "security", "intrusion", "rules", "overrides"],
+ "operation": "deleteOrganizationApplianceSecurityIntrusionRulesOverride",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ overrideId = urllib.parse.quote(str(overrideId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules/overrides/{overrideId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Display VPN exclusion rules for MX networks.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-traffic-shaping-vpn-exclusions-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter the results by network IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "trafficShaping", "vpnExclusions", "byNetwork"],
+ "operation": "getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/trafficShaping/vpnExclusions/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceUmbrellaPoliciesByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List Umbrella policy IDs applied to MX networks in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-umbrella-policies-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Filter results to only the given network IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "umbrella", "policies", "byNetwork"],
+ "operation": "getOrganizationApplianceUmbrellaPoliciesByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/umbrella/policies/byNetwork"
query_params = [
"perPage",
@@ -4316,7 +5493,7 @@ def getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationApplianceTrafficShapingVpnExclusionsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationApplianceUmbrellaPoliciesByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
@@ -4506,6 +5683,282 @@ def getOrganizationApplianceUplinksUsageByNetwork(self, organizationId: str, **k
return self._session.get(metadata, resource, params)
+ def getOrganizationApplianceVlans(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the VLANs for an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vlans
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "vlans"],
+ "operation": "getOrganizationApplianceVlans",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vlans"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationApplianceVlans: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationApplianceVpnConnectivityVpnPeersByNetwork(self, organizationId: str, **kwargs):
+ """
+ **Summarizes by-device vpn peers for the organization in the given interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-connectivity-vpn-peers-by-network
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 3600, 14400, 86400. The default is 3600. Interval is calculated if time params are provided.
+ - networkIds (array): Filter results by network.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "connectivity", "vpnPeers", "byNetwork"],
+ "operation": "getOrganizationApplianceVpnConnectivityVpnPeersByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/connectivity/vpnPeers/byNetwork"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnConnectivityVpnPeersByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnRemoteAccessSecureClientAuthenticationByClient(self, organizationId: str, **kwargs):
+ """
+ **Get authentication for all clients in organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-remote-access-secure-client-authentication-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "remoteAccess", "secureClient", "authentication", "byClient"],
+ "operation": "getOrganizationApplianceVpnRemoteAccessSecureClientAuthenticationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/remoteAccess/secureClient/authentication/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnRemoteAccessSecureClientAuthenticationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnRemoteAccessSecureClientIpAssignmentByClient(self, organizationId: str, **kwargs):
+ """
+ **Get IP assignment for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-remote-access-secure-client-ip-assignment-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "remoteAccess", "secureClient", "ipAssignment", "byClient"],
+ "operation": "getOrganizationApplianceVpnRemoteAccessSecureClientIpAssignmentByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/remoteAccess/secureClient/ipAssignment/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnRemoteAccessSecureClientIpAssignmentByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnRemoteAccessSecureClientTunnelCreationByClient(self, organizationId: str, **kwargs):
+ """
+ **Get tunnel creation events for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-remote-access-secure-client-tunnel-creation-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "monitor", "vpn", "remoteAccess", "secureClient", "tunnelCreation", "byClient"],
+ "operation": "getOrganizationApplianceVpnRemoteAccessSecureClientTunnelCreationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/remoteAccess/secureClient/tunnelCreation/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnRemoteAccessSecureClientTunnelCreationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApplianceVpnSiteToSiteHubsVrfs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return source-to-hub VRF mappings for site-to-site VPN within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-vpn-site-to-site-hubs-vrfs
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter source-to-hub mappings by source network IDs.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["appliance", "configure", "vpn", "siteToSite", "hubs", "vrfs"],
+ "operation": "getOrganizationApplianceVpnSiteToSiteHubsVrfs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/vpn/siteToSite/hubs/vrfs"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApplianceVpnSiteToSiteHubsVrfs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApplianceVpnSiteToSiteIpsecPeersSlas(self, organizationId: str):
"""
**Get the list of available IPsec SLA policies for an organization**
diff --git a/meraki/api/assistant.py b/meraki/api/assistant.py
new file mode 100644
index 00000000..e76b269f
--- /dev/null
+++ b/meraki/api/assistant.py
@@ -0,0 +1,491 @@
+import urllib
+
+
+class Assistant(object):
+ def __init__(self, session):
+ super(Assistant, self).__init__()
+ self._session = session
+
+ def getOrganizationAssistantCapabilities(self, organizationId: str):
+ """
+ **List the AI assistant's available capabilities and agents for this organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-capabilities
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "capabilities"],
+ "operation": "getOrganizationAssistantCapabilities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/capabilities"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationAssistantChatCompletion(self, organizationId: str, **kwargs):
+ """
+ **Create a chat completion with the AI assistant**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-completion
+
+ - organizationId (string): Organization ID
+ - query (string): Simple text question or instruction to send to the AI assistant. Provide either 'query' for text-only requests or 'content' for multi-modal input.
+ - content (array): List of multi-modal content blocks. Use instead of 'query' to send text or images. Supports text and image types only; for audio and file support, use the messages endpoint. Maximum 8 parts.
+ - threadId (string): An existing thread ID to continue a conversation. If omitted, a new thread is created.
+ - networkId (string): Optional network ID to scope the query to a specific network. Defaults to the user's last visited network.
+ - platform (string): Platform identifier. Defaults to MERAKI when omitted. Case-insensitive.
+ - language (string): Optional language override. Defaults to the user's preferred language.
+ - country (string): Optional country override. Defaults to the user's country.
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs:
+ options = ["DIGITAL_TWIN", "DNAC", "MERAKI", "digital_twin", "dnac", "meraki"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "completions"],
+ "operation": "createOrganizationAssistantChatCompletion",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/completions"
+
+ body_params = [
+ "query",
+ "content",
+ "threadId",
+ "networkId",
+ "platform",
+ "language",
+ "country",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatCompletion: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantChatThreads(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List all active conversation threads for the authenticated user.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-threads
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of entries per page. Defaults to 100. Maximum 1000.
+ - sort (string): Field to sort results by. Defaults to dateModified.
+ - sortOrder (string): Sort direction for results. Defaults to desc.
+ - from (string): Filter threads modified after this timestamp.
+ - to (string): Filter threads modified before this timestamp.
+ """
+
+ kwargs.update(locals())
+
+ if "sort" in kwargs:
+ options = ["dateModified", "id", "name"]
+ assert kwargs["sort"] in options, f'''"sort" cannot be "{kwargs["sort"]}", & must be set to one of: {options}'''
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "getOrganizationAssistantChatThreads",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads"
+
+ query_params = [
+ "perPage",
+ "sort",
+ "sortOrder",
+ "from",
+ "to",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAssistantChatThreads: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationAssistantChatThread(self, organizationId: str, **kwargs):
+ """
+ **Create a new conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadName (string): Display name for the new thread.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "createOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads"
+
+ body_params = [
+ "threadName",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatThread: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantChatThread(self, organizationId: str, threadId: str):
+ """
+ **Return a single conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "getOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationAssistantChatThread(self, organizationId: str, threadId: str, threadName: str, **kwargs):
+ """
+ **Update the name of a conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - threadName (string): New display name for the thread.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "updateOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}"
+
+ body_params = [
+ "threadName",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationAssistantChatThread: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationAssistantChatThread(self, organizationId: str, threadId: str):
+ """
+ **Delete a conversation thread and all its messages.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-assistant-chat-thread
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads"],
+ "operation": "deleteOrganizationAssistantChatThread",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationAssistantChatThreadMessages(
+ self, organizationId: str, threadId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List messages in a conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-messages
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of entries per page. Defaults to 100. Maximum 1000.
+ - sortOrder (string): Sort direction for results by timestamp. Defaults to asc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages"],
+ "operation": "getOrganizationAssistantChatThreadMessages",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages"
+
+ query_params = [
+ "perPage",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssistantChatThreadMessages: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationAssistantChatThreadMessage(self, organizationId: str, threadId: str, content: list, **kwargs):
+ """
+ **Create a new chat message in a thread.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-thread-message
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - content (array): List of message content parts. Supports text, image, audio, and file types. Maximum 8 parts.
+ - networkName (string): Name of the target network.
+ - networkId (string): Optional Meraki network ID for thread context.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages"],
+ "operation": "createOrganizationAssistantChatThreadMessage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages"
+
+ body_params = [
+ "content",
+ "networkName",
+ "networkId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatThreadMessage: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantChatThreadMessage(self, organizationId: str, threadId: str, messageId: str):
+ """
+ **Return a single message in a conversation thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages"],
+ "operation": "getOrganizationAssistantChatThreadMessage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationAssistantChatThreadMessageArtifacts(self, organizationId: str, threadId: str, messageId: str):
+ """
+ **List artifacts attached to a specific message**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message-artifacts
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "artifacts"],
+ "operation": "getOrganizationAssistantChatThreadMessageArtifacts",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/artifacts"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationAssistantChatThreadMessageArtifact(
+ self, organizationId: str, threadId: str, messageId: str, artifactId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return a single artifact with its full content.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message-artifact
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ - artifactId (string): Artifact ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - page (integer): Page number for paginated artifact content, defaulting to 1
+ - perPage (integer): Number of entries per page. Defaults to 100. Maximum 1000.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "artifacts"],
+ "operation": "getOrganizationAssistantChatThreadMessageArtifact",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ artifactId = urllib.parse.quote(str(artifactId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/artifacts/{artifactId}"
+ )
+
+ query_params = [
+ "page",
+ "perPage",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssistantChatThreadMessageArtifact: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssistantChatThreadMessageFeedback(self, organizationId: str, threadId: str, messageId: str):
+ """
+ **Return all feedback entries previously submitted for a specific message in a thread.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-chat-thread-message-feedback
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "feedback"],
+ "operation": "getOrganizationAssistantChatThreadMessageFeedback",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/feedback"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationAssistantChatThreadMessageFeedback(
+ self, organizationId: str, threadId: str, messageId: str, vote: bool, **kwargs
+ ):
+ """
+ **Submit or replace feedback for a specific assistant message.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-assistant-chat-thread-message-feedback
+
+ - organizationId (string): Organization ID
+ - threadId (string): Thread ID
+ - messageId (string): Message ID
+ - vote (boolean): True for positive, false for negative.
+ - reason (string): Optional free-text reason for the feedback (e.g., 'inaccurate', 'incomplete', 'helpful'). Not constrained to a fixed set of values.
+ - comment (string): Optional free-text comment providing additional detail.
+ - message (string): The assistant message text the feedback refers to. Captured for analytics; not required.
+ - prompt (string): The user prompt that produced the assistant message. Captured for analytics; not required.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["assistant", "configure", "chat", "threads", "messages", "feedback"],
+ "operation": "createOrganizationAssistantChatThreadMessageFeedback",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ threadId = urllib.parse.quote(str(threadId), safe="")
+ messageId = urllib.parse.quote(str(messageId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/chat/threads/{threadId}/messages/{messageId}/feedback"
+
+ body_params = [
+ "vote",
+ "reason",
+ "comment",
+ "message",
+ "prompt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationAssistantChatThreadMessageFeedback: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAssistantQueryLimits(self, organizationId: str):
+ """
+ **Get query limits for the AI assistant for this organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assistant-query-limits
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["assistant", "configure", "queryLimits"],
+ "operation": "getOrganizationAssistantQueryLimits",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assistant/queryLimits"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/api/batch/appliance.py b/meraki/api/batch/appliance.py
index 9202a10e..e8ba8265 100644
--- a/meraki/api/batch/appliance.py
+++ b/meraki/api/batch/appliance.py
@@ -16,11 +16,22 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
- personality (object): Describes the port's configurability
- uplink (object): The port's settings when in WAN mode
- downlink (object): The port's VLAN settings when in LAN mode
+ - speed (string): Link speed for the port, in Mbps
+ - duplex (string): Duplex configuration for the port
"""
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ if "speed" in kwargs and kwargs["speed"] is not None:
+ options = ["10", "100", "1000", "10000", "2500", "25000", "5000", "auto"]
+ assert kwargs["speed"] in options, f'''"speed" cannot be "{kwargs["speed"]}", & must be set to one of: {options}'''
+ if "duplex" in kwargs and kwargs["duplex"] is not None:
+ options = ["auto", "full", "half"]
+ assert kwargs["duplex"] in options, (
+ f'''"duplex" cannot be "{kwargs["duplex"]}", & must be set to one of: {options}'''
+ )
+
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/appliance/interfaces/ports/update"
body_params = [
@@ -29,6 +40,54 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs):
"personality",
"uplink",
"downlink",
+ "speed",
+ "duplex",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateDeviceApplianceInterfacesPort(self, serial: str, number: str, **kwargs):
+ """
+ **Update configurations for an appliance's specified port**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-appliance-interfaces-port
+
+ - serial (string): Serial
+ - number (string): Number
+ - enabled (boolean): Indicates whether the port is enabled
+ - personality (object): Describes the port's configurability
+ - uplink (object): The port's settings when in WAN mode
+ - downlink (object): The port's VLAN settings when in LAN mode
+ - speed (string): Link speed for the port, in Mbps
+ - duplex (string): Duplex configuration for the port
+ """
+
+ kwargs.update(locals())
+
+ if "speed" in kwargs and kwargs["speed"] is not None:
+ options = ["10", "100", "1000", "10000", "2500", "25000", "5000", "auto"]
+ assert kwargs["speed"] in options, f'''"speed" cannot be "{kwargs["speed"]}", & must be set to one of: {options}'''
+ if "duplex" in kwargs and kwargs["duplex"] is not None:
+ options = ["auto", "full", "half"]
+ assert kwargs["duplex"] in options, (
+ f'''"duplex" cannot be "{kwargs["duplex"]}", & must be set to one of: {options}'''
+ )
+
+ serial = urllib.parse.quote(str(serial), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/devices/{serial}/appliance/interfaces/ports/{number}"
+
+ body_params = [
+ "enabled",
+ "personality",
+ "uplink",
+ "downlink",
+ "speed",
+ "duplex",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -51,7 +110,7 @@ def updateDeviceApplianceRadioSettings(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/appliance/radio/settings"
body_params = [
@@ -78,7 +137,7 @@ def updateDeviceApplianceUplinksSettings(self, serial: str, interfaces: dict, **
kwargs = locals()
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/appliance/uplinks/settings"
body_params = [
@@ -100,7 +159,7 @@ def createDeviceApplianceVmxAuthenticationToken(self, serial: str):
- serial (string): Serial
"""
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/appliance/vmx/authenticationToken"
action = {
@@ -120,7 +179,7 @@ def updateNetworkApplianceConnectivityMonitoringDestinations(self, networkId: st
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/connectivityMonitoringDestinations"
body_params = [
@@ -152,7 +211,7 @@ def updateNetworkApplianceDevicesRedundancy(self, networkId: str, enabled: bool,
options = ["active-active", "active-passive", "disabled"]
assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/devices/redundancy"
body_params = [
@@ -177,7 +236,7 @@ def createNetworkApplianceDevicesRedundancySwap(self, networkId: str):
- networkId (string): Network ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/devices/redundancy/swap"
action = {
@@ -197,7 +256,7 @@ def updateNetworkApplianceFirewallL7FirewallRules(self, networkId: str, **kwargs
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/firewall/l7FirewallRules"
body_params = [
@@ -222,7 +281,7 @@ def updateNetworkApplianceFirewallMulticastForwarding(self, networkId: str, rule
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/firewall/multicastForwarding"
body_params = [
@@ -244,16 +303,18 @@ def createNetworkApplianceInterfacesL3(self, networkId: str, ipv4: dict, **kwarg
- networkId (string): Network ID
- ipv4 (object): IPv4 configuration
- port (object): Port configuration
+ - vrf (object): VRF assignment for the L3 interface
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/interfaces/l3"
body_params = [
"port",
"ipv4",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -272,17 +333,19 @@ def updateNetworkApplianceInterfacesL3(self, networkId: str, interfaceId: str, *
- interfaceId (string): Interface ID
- port (object): Port configuration
- ipv4 (object): IPv4 configuration
+ - vrf (object): VRF assignment for the L3 interface
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/networks/{networkId}/appliance/interfaces/l3/{interfaceId}"
body_params = [
"port",
"ipv4",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -301,8 +364,8 @@ def deleteNetworkApplianceInterfacesL3(self, networkId: str, interfaceId: str):
- interfaceId (string): Interface ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/networks/{networkId}/appliance/interfaces/l3/{interfaceId}"
action = {
@@ -324,13 +387,15 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs):
- vlan (integer): Native VLAN when the port is in Trunk mode. Access VLAN when the port is in Access mode.
- allowedVlans (string): Comma-delimited list of VLAN IDs (e.g. '2,15') for all devices. Secure Routers also support VLAN ranges (e.g. '2-10,15'). Use 'all' to permit all VLANs on the port.
- accessPolicy (string): The name of the policy. Only applicable to Access ports. Valid values are: 'open', '8021x-radius', 'mac-radius', 'hybris-radius' for MX64 or Z3 or any MX supporting the per port authentication feature. Otherwise, 'open' is the only valid value and 'open' is the default value if the field is missing.
+ - peerSgtCapable (boolean): If true, Peer SGT is enabled for traffic through this port. Applicable to trunk port only, not access port.
+ - adaptivePolicyGroupId (string): Adaptive policy group ID that all traffic originating from this port is assigned to.
- sgt (object): Security Group Tag settings for the port.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- portId = urllib.parse.quote(portId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ portId = urllib.parse.quote(str(portId), safe="")
resource = f"/networks/{networkId}/appliance/ports/{portId}"
body_params = [
@@ -340,6 +405,8 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs):
"vlan",
"allowedVlans",
"accessPolicy",
+ "peerSgtCapable",
+ "adaptivePolicyGroupId",
"sgt",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -363,7 +430,7 @@ def createNetworkAppliancePrefixesDelegatedStatic(self, networkId: str, prefix:
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/prefixes/delegated/statics"
body_params = [
@@ -393,8 +460,8 @@ def updateNetworkAppliancePrefixesDelegatedStatic(self, networkId: str, staticDe
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- staticDelegatedPrefixId = urllib.parse.quote(staticDelegatedPrefixId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ staticDelegatedPrefixId = urllib.parse.quote(str(staticDelegatedPrefixId), safe="")
resource = f"/networks/{networkId}/appliance/prefixes/delegated/statics/{staticDelegatedPrefixId}"
body_params = [
@@ -419,8 +486,8 @@ def deleteNetworkAppliancePrefixesDelegatedStatic(self, networkId: str, staticDe
- staticDelegatedPrefixId (string): Static delegated prefix ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- staticDelegatedPrefixId = urllib.parse.quote(staticDelegatedPrefixId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ staticDelegatedPrefixId = urllib.parse.quote(str(staticDelegatedPrefixId), safe="")
resource = f"/networks/{networkId}/appliance/prefixes/delegated/statics/{staticDelegatedPrefixId}"
action = {
@@ -443,7 +510,7 @@ def createNetworkApplianceRfProfile(self, networkId: str, name: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/rfProfiles"
body_params = [
@@ -475,8 +542,8 @@ def updateNetworkApplianceRfProfile(self, networkId: str, rfProfileId: str, **kw
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- rfProfileId = urllib.parse.quote(rfProfileId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ rfProfileId = urllib.parse.quote(str(rfProfileId), safe="")
resource = f"/networks/{networkId}/appliance/rfProfiles/{rfProfileId}"
body_params = [
@@ -502,8 +569,8 @@ def deleteNetworkApplianceRfProfile(self, networkId: str, rfProfileId: str):
- rfProfileId (string): Rf profile ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- rfProfileId = urllib.parse.quote(rfProfileId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ rfProfileId = urllib.parse.quote(str(rfProfileId), safe="")
resource = f"/networks/{networkId}/appliance/rfProfiles/{rfProfileId}"
action = {
@@ -523,7 +590,7 @@ def updateNetworkApplianceSdwanInternetPolicies(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/sdwan/internetPolicies"
body_params = [
@@ -561,7 +628,7 @@ def updateNetworkApplianceSettings(self, networkId: str, **kwargs):
f'''"deploymentMode" cannot be "{kwargs["deploymentMode"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/settings"
body_params = [
@@ -587,11 +654,12 @@ def updateNetworkApplianceSingleLan(self, networkId: str, **kwargs):
- applianceIp (string): The appliance IP address of the single LAN
- ipv6 (object): IPv6 configuration on the VLAN
- mandatoryDhcp (object): Mandatory DHCP will enforce that clients connecting to this LAN must use the IP address assigned by the DHCP server. Clients who use a static IP address won't be able to associate. Only available on firmware versions 17.0 and above
+ - vrf (object): VRF configuration on the Single LAN. Omit this field to preserve the current VRF.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/singleLan"
body_params = [
@@ -599,6 +667,7 @@ def updateNetworkApplianceSingleLan(self, networkId: str, **kwargs):
"applianceIp",
"ipv6",
"mandatoryDhcp",
+ "vrf",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -646,8 +715,8 @@ def updateNetworkApplianceSsid(self, networkId: str, number: str, **kwargs):
f'''"wpaEncryptionMode" cannot be "{kwargs["wpaEncryptionMode"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/appliance/ssids/{number}"
body_params = [
@@ -685,7 +754,7 @@ def createNetworkApplianceTrafficShapingCustomPerformanceClass(self, networkId:
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/customPerformanceClasses"
body_params = [
@@ -719,8 +788,8 @@ def updateNetworkApplianceTrafficShapingCustomPerformanceClass(
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- customPerformanceClassId = urllib.parse.quote(customPerformanceClassId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ customPerformanceClassId = urllib.parse.quote(str(customPerformanceClassId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/customPerformanceClasses/{customPerformanceClassId}"
body_params = [
@@ -746,8 +815,8 @@ def deleteNetworkApplianceTrafficShapingCustomPerformanceClass(self, networkId:
- customPerformanceClassId (string): Custom performance class ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- customPerformanceClassId = urllib.parse.quote(customPerformanceClassId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ customPerformanceClassId = urllib.parse.quote(str(customPerformanceClassId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/customPerformanceClasses/{customPerformanceClassId}"
action = {
@@ -771,7 +840,7 @@ def updateNetworkApplianceTrafficShapingRules(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/rules"
body_params = [
@@ -797,7 +866,7 @@ def updateNetworkApplianceTrafficShapingUplinkBandwidth(self, networkId: str, **
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/uplinkBandwidth"
body_params = [
@@ -827,7 +896,7 @@ def updateNetworkApplianceTrafficShapingUplinkSelection(self, networkId: str, **
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/uplinkSelection"
body_params = [
@@ -854,16 +923,18 @@ def updateNetworkApplianceTrafficShapingVpnExclusions(self, networkId: str, **kw
- networkId (string): Network ID
- custom (array): Custom VPN exclusion rules. Pass an empty array to clear existing rules.
- majorApplications (array): Major Application based VPN exclusion rules. Pass an empty array to clear existing rules.
+ - applications (array): NBAR Application based VPN exclusion rules. Available for networks on >=19.2 firmware
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/trafficShaping/vpnExclusions"
body_params = [
"custom",
"majorApplications",
+ "applications",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -884,7 +955,7 @@ def connectNetworkApplianceUmbrellaAccount(self, networkId: str, api: dict, **kw
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/umbrella/account/connect"
body_params = [
@@ -906,7 +977,7 @@ def disconnectNetworkApplianceUmbrellaAccount(self, networkId: str):
- networkId (string): Network ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/umbrella/account/disconnect"
action = {
@@ -915,6 +986,23 @@ def disconnectNetworkApplianceUmbrellaAccount(self, networkId: str):
}
return action
+ def disableNetworkApplianceUmbrellaProtection(self, networkId: str):
+ """
+ **Disable umbrella protection for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!disable-network-appliance-umbrella-protection
+
+ - networkId (string): Network ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/disableProtection"
+
+ action = {
+ "resource": resource,
+ "operation": "action",
+ }
+ return action
+
def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs):
"""
**Specify one or more domain names to be excluded from being routed to Cisco Umbrella.**
@@ -926,7 +1014,7 @@ def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: lis
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/umbrella/domains/exclusions"
body_params = [
@@ -940,6 +1028,48 @@ def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: lis
}
return action
+ def enableNetworkApplianceUmbrellaProtection(self, networkId: str):
+ """
+ **Enable umbrella protection for an MX network**
+ https://developer.cisco.com/meraki/api-v1/#!enable-network-appliance-umbrella-protection
+
+ - networkId (string): Network ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/enableProtection"
+
+ action = {
+ "resource": resource,
+ "operation": "action",
+ }
+ return action
+
+ def policiesNetworkApplianceUmbrella(self, networkId: str, policyIds: list, **kwargs):
+ """
+ **Update umbrella policies applied to MX network.**
+ https://developer.cisco.com/meraki/api-v1/#!policies-network-appliance-umbrella
+
+ - networkId (string): Network ID
+ - policyIds (array): Array of umbrella policy IDs
+ """
+
+ kwargs = locals()
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/appliance/umbrella/policies"
+
+ body_params = [
+ "policyIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "action",
+ "body": payload,
+ }
+ return action
+
def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs):
"""
**Add one Cisco Umbrella DNS security policy to an MX network by policy ID. Idempotent — if the policy is already applied, the request succeeds and returns the current policy set unchanged.**
@@ -951,7 +1081,7 @@ def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kw
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/umbrella/policies/add"
body_params = [
@@ -976,7 +1106,7 @@ def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, *
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/umbrella/policies/remove"
body_params = [
@@ -1001,7 +1131,7 @@ def protectionNetworkApplianceUmbrella(self, networkId: str, enabled: bool, **kw
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/umbrella/protection"
body_params = [
@@ -1026,7 +1156,7 @@ def updateNetworkApplianceUplinksNat(self, networkId: str, uplinks: list, **kwar
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/uplinks/nat"
body_params = [
@@ -1063,6 +1193,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
- dhcpBootNextServer (string): DHCP boot option to direct boot clients to the server to load the boot file from
- dhcpBootFilename (string): DHCP boot option for boot filename
- dhcpOptions (array): The list of DHCP options that will be included in DHCP responses. Each object in the list should have "code", "type", and "value" properties.
+ - adaptivePolicyGroupId (string): Adaptive policy group ID this VLAN is assigned to.
- sgt (object): Security Group Tag settings for the VLAN.
- vrf (object): VRF configuration on the VLAN.
- uplinks (array): Per-uplink NAT exception override configuration on the VLAN. Applicable only for networks that support NAT exceptions.
@@ -1086,7 +1217,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
f'''"dhcpLeaseTime" cannot be "{kwargs["dhcpLeaseTime"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/vlans"
body_params = [
@@ -1107,6 +1238,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg
"dhcpBootNextServer",
"dhcpBootFilename",
"dhcpOptions",
+ "adaptivePolicyGroupId",
"sgt",
"vrf",
"uplinks",
@@ -1130,7 +1262,7 @@ def updateNetworkApplianceVlansSettings(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/vlans/settings"
body_params = [
@@ -1171,6 +1303,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
- mask (integer): Mask used for the subnet of all bound to the template networks. Applicable only for template network.
- ipv6 (object): IPv6 configuration on the VLAN
- mandatoryDhcp (object): Mandatory DHCP will enforce that clients connecting to this VLAN must use the IP address assigned by the DHCP server. Clients who use a static IP address won't be able to associate. Only available on firmware versions 17.0 and above
+ - adaptivePolicyGroupId (string): Adaptive policy group ID that all traffic originating from this VLAN is assigned to.
- sgt (object): Security Group Tag settings for the VLAN.
- vrf (object): VRF configuration on the VLAN.
- uplinks (array): Per-uplink NAT exception override configuration on the VLAN. Applicable only for networks that support NAT exceptions.
@@ -1194,8 +1327,8 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
f'''"templateVlanType" cannot be "{kwargs["templateVlanType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- vlanId = urllib.parse.quote(vlanId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ vlanId = urllib.parse.quote(str(vlanId), safe="")
resource = f"/networks/{networkId}/appliance/vlans/{vlanId}"
body_params = [
@@ -1219,6 +1352,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs):
"mask",
"ipv6",
"mandatoryDhcp",
+ "adaptivePolicyGroupId",
"sgt",
"vrf",
"uplinks",
@@ -1240,8 +1374,8 @@ def deleteNetworkApplianceVlan(self, networkId: str, vlanId: str):
- vlanId (string): Vlan ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- vlanId = urllib.parse.quote(vlanId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ vlanId = urllib.parse.quote(str(vlanId), safe="")
resource = f"/networks/{networkId}/appliance/vlans/{vlanId}"
action = {
@@ -1259,19 +1393,33 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
- enabled (boolean): Boolean value to enable or disable the BGP configuration. When BGP is enabled, the asNumber (ASN) will be autopopulated with the preconfigured ASN at other Hubs or a default value if there is no ASN configured.
- asNumber (integer): An Autonomous System Number (ASN) is required if you are to run BGP and peer with another BGP Speaker outside of the Auto VPN domain. This ASN will be applied to the entire Auto VPN domain and is only configurable for Auto VPN BGP networks. The entire 4-byte ASN range is supported. So, the ASN must be an integer between 1 and 4294967295. When absent, this field is not updated. If no value exists then it defaults to 64512.
- ibgpHoldTimer (integer): The iBGP holdtimer in seconds. The iBGP holdtimer must be an integer between 12 and 240. When absent, this field is not updated. If no value exists then it defaults to 240.
+ - ipv6 (object): Settings for IPv6 configurations on the organization.
+ - tunnelDownTermination (object): Settings for tunnel down termination on the organization.
+ - vpnAsNumber (integer): Network specific number of the Autonomous System to which the appliance belongs. This field is only configurable for Independent BGP networks.
+ - priorityRoute (string): Sets the priority route between eBGP and Auto VPN.
- routerId (string): The router ID of the appliance
- neighbors (array): List of BGP neighbors. This list replaces the existing set of neighbors. When absent, this field is not updated.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ if "priorityRoute" in kwargs and kwargs["priorityRoute"] is not None:
+ options = ["Auto VPN", "eBGP"]
+ assert kwargs["priorityRoute"] in options, (
+ f'''"priorityRoute" cannot be "{kwargs["priorityRoute"]}", & must be set to one of: {options}'''
+ )
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/vpn/bgp"
body_params = [
"enabled",
"asNumber",
"ibgpHoldTimer",
+ "ipv6",
+ "tunnelDownTermination",
+ "vpnAsNumber",
+ "priorityRoute",
"routerId",
"neighbors",
]
@@ -1283,6 +1431,33 @@ def updateNetworkApplianceVpnBgp(self, networkId: str, enabled: bool, **kwargs):
}
return action
+ def updateNetworkApplianceVpnSiteToSiteHubVrfs(self, networkId: str, hubNetworkId: str, _json: list, **kwargs):
+ """
+ **Update the VRF mappings for a source network and hub pair.**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-appliance-vpn-site-to-site-hub-vrfs
+
+ - networkId (string): Network ID
+ - hubNetworkId (string): Hub network ID
+ - _json (array): The list of VRFs for this source and hub mapping.
+ """
+
+ kwargs = locals()
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ hubNetworkId = urllib.parse.quote(str(hubNetworkId), safe="")
+ resource = f"/networks/{networkId}/appliance/vpn/siteToSite/hubs/{hubNetworkId}/vrfs"
+
+ body_params = [
+ "_json",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kwargs):
"""
**Update the site-to-site VPN settings of a network. Only valid for MX networks in NAT mode.**
@@ -1292,6 +1467,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw
- mode (string): The site-to-site VPN mode. Can be one of 'none', 'spoke' or 'hub'
- hubs (array): The list of VPN hubs, in order of preference. In spoke mode, at least 1 hub is required.
- subnets (array): The list of subnets and their VPN presence.
+ - peerSgtCapable (boolean): Whether or not Peer SGT is enabled for traffic to this VPN peer.
- sgt (object): Security Group Tag settings for the VPN peer.
- subnet (object): Configuration of subnet features
- hostTranslations (array): The list of VPN host translations. Host translations are supported starting from MX firmware version 26.1.2
@@ -1303,13 +1479,14 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw
options = ["hub", "none", "spoke"]
assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/vpn/siteToSiteVpn"
body_params = [
"mode",
"hubs",
"subnets",
+ "peerSgtCapable",
"sgt",
"subnet",
"hostTranslations",
@@ -1337,7 +1514,7 @@ def updateNetworkApplianceWarmSpare(self, networkId: str, enabled: bool, **kwarg
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/warmSpare"
body_params = [
@@ -1363,7 +1540,7 @@ def swapNetworkApplianceWarmSpare(self, networkId: str):
- networkId (string): Network ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/appliance/warmSpare/swap"
action = {
@@ -1383,7 +1560,7 @@ def createOrganizationApplianceDnsLocalProfile(self, organizationId: str, name:
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/profiles"
body_params = [
@@ -1408,7 +1585,7 @@ def bulkOrganizationApplianceDnsLocalProfilesAssignmentsCreate(self, organizatio
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/profiles/assignments/bulkCreate"
body_params = [
@@ -1433,7 +1610,7 @@ def createOrganizationApplianceDnsLocalProfilesAssignmentsBulkDelete(self, organ
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/profiles/assignments/bulkDelete"
body_params = [
@@ -1459,8 +1636,8 @@ def updateOrganizationApplianceDnsLocalProfile(self, organizationId: str, profil
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/profiles/{profileId}"
body_params = [
@@ -1483,8 +1660,8 @@ def deleteOrganizationApplianceDnsLocalProfile(self, organizationId: str, profil
- profileId (string): Profile ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/profiles/{profileId}"
action = {
@@ -1508,7 +1685,7 @@ def createOrganizationApplianceDnsLocalRecord(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/records"
body_params = [
@@ -1538,8 +1715,8 @@ def updateOrganizationApplianceDnsLocalRecord(self, organizationId: str, recordI
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- recordId = urllib.parse.quote(recordId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ recordId = urllib.parse.quote(str(recordId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/records/{recordId}"
body_params = [
@@ -1564,8 +1741,8 @@ def deleteOrganizationApplianceDnsLocalRecord(self, organizationId: str, recordI
- recordId (string): Record ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- recordId = urllib.parse.quote(recordId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ recordId = urllib.parse.quote(str(recordId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/local/records/{recordId}"
action = {
@@ -1589,7 +1766,7 @@ def createOrganizationApplianceDnsSplitProfile(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/split/profiles"
body_params = [
@@ -1616,7 +1793,7 @@ def createOrganizationApplianceDnsSplitProfilesAssignmentsBulkCreate(self, organ
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/split/profiles/assignments/bulkCreate"
body_params = [
@@ -1641,7 +1818,7 @@ def createOrganizationApplianceDnsSplitProfilesAssignmentsBulkDelete(self, organ
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/split/profiles/assignments/bulkDelete"
body_params = [
@@ -1669,8 +1846,8 @@ def updateOrganizationApplianceDnsSplitProfile(self, organizationId: str, profil
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/split/profiles/{profileId}"
body_params = [
@@ -1695,8 +1872,8 @@ def deleteOrganizationApplianceDnsSplitProfile(self, organizationId: str, profil
- profileId (string): Profile ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/organizations/{organizationId}/appliance/dns/split/profiles/{profileId}"
action = {
@@ -1716,7 +1893,7 @@ def updateOrganizationApplianceRoutingVrfsSettings(self, organizationId: str, en
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/routing/vrfs/settings"
body_params = [
@@ -1730,6 +1907,322 @@ def updateOrganizationApplianceRoutingVrfsSettings(self, organizationId: str, en
}
return action
+ def createOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, **kwargs):
+ """
+ **Create a new intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policy (object): Attributes for the intrusion policy
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, policyId: str, policy: dict, **kwargs):
+ """
+ **Update a single intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - policy (object): Attributes for the intrusion policy
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationApplianceSecurityIntrusionPolicy(self, organizationId: str, policyId: str):
+ """
+ **Delete a single intrusion policy for the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-policy
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def declareOrganizationApplianceSecurityIntrusionPolicyRuleGroupsOverrides(
+ self, organizationId: str, policyId: str, items: list, **kwargs
+ ):
+ """
+ **Declare the desired rule group overrides for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!declare-organization-appliance-security-intrusion-policy-rule-groups-overrides
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - items (array): Desired overrides state
+ - mode (string): Controls how the configuration payload in the request body is applied to the resource. This parameter dictates the declarative mode:
+
+ * **`complete`**: The request body represents the entire desired configuration for this resource. Any existing configurations that are not included in the payload will be removed.
+ * **`partial` (default)**: The request body contains only the configurations to be created or modified. Existing configurations that are not specified in the payload will be preserved.
+
+ - recursive (boolean): Controls how the configuration payload in the request body applies to the rule group hierarchy. When true, the API applies each declared override to the rule group itself and its descendants unless the payload explicitly sets a descendant override. When false (default), the API applies overrides only to the rule groups listed in the payload.
+
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["complete", "partial"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/overrides/declare"
+ )
+
+ body_params = [
+ "mode",
+ "recursive",
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "declare",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride(
+ self, organizationId: str, policyId: str, ruleGroupId: str, override: dict, **kwargs
+ ):
+ """
+ **Create a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy-rule-group-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleGroupId (string): Rule group ID
+ - override (object): Attributes for the override for a rule group in a intrusion policy
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleGroupId = urllib.parse.quote(str(ruleGroupId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/{ruleGroupId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationApplianceSecurityIntrusionPolicyRuleGroupOverride(
+ self, organizationId: str, policyId: str, ruleGroupId: str, override: dict, **kwargs
+ ):
+ """
+ **Update a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy-rule-group-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleGroupId (string): Rule group ID
+ - override (object): Attributes for the override for a rule group in a intrusion policy
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleGroupId = urllib.parse.quote(str(ruleGroupId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/ruleGroups/{ruleGroupId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def declareOrganizationApplianceSecurityIntrusionPolicyRulesOverrides(
+ self, organizationId: str, policyId: str, items: list, **kwargs
+ ):
+ """
+ **Declare the desired rule overrides for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!declare-organization-appliance-security-intrusion-policy-rules-overrides
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - items (array): Desired overrides state
+ - mode (string): Controls how the configuration payload in the request body is applied to the resource. This parameter dictates the declarative mode:
+
+ * **`complete`**: The request body represents the entire desired configuration for this resource. Any existing configurations that are not included in the payload will be removed. This effectively performs a full replacement or overwrite of the resource's configuration.
+ * **`partial` (default)**: The request body contains only the configurations to be created or modified. Existing configurations that are not specified in the payload will be preserved. This performs a merge or partial update, applying only the changes specified.
+
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["complete", "partial"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/overrides/declare"
+
+ body_params = [
+ "mode",
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "declare",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationApplianceSecurityIntrusionPolicyRuleOverride(
+ self, organizationId: str, policyId: str, ruleId: str, override: dict, **kwargs
+ ):
+ """
+ **Create a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-appliance-security-intrusion-policy-rule-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - override (object): Rule override to create
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/{ruleId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationApplianceSecurityIntrusionPolicyRuleOverride(
+ self, organizationId: str, policyId: str, ruleId: str, override: dict, **kwargs
+ ):
+ """
+ **Update a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-appliance-security-intrusion-policy-rule-override
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - override (object): Override attributes
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/policies/{policyId}/rules/{ruleId}/override"
+
+ body_params = [
+ "override",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationApplianceSecurityIntrusionRuleGroupsOverride(self, organizationId: str, overrideId: str):
+ """
+ **Delete a rule group override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-rule-groups-override
+
+ - organizationId (string): Organization ID
+ - overrideId (string): Override ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ overrideId = urllib.parse.quote(str(overrideId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/ruleGroups/overrides/{overrideId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def deleteOrganizationApplianceSecurityIntrusionRulesOverride(self, organizationId: str, overrideId: str):
+ """
+ **Delete a rule override for an intrusion policy.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-appliance-security-intrusion-rules-override
+
+ - organizationId (string): Organization ID
+ - overrideId (string): Override ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ overrideId = urllib.parse.quote(str(overrideId), safe="")
+ resource = f"/organizations/{organizationId}/appliance/security/intrusion/rules/overrides/{overrideId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def updateOrganizationApplianceVpnSiteToSiteIpsecPeersSlas(self, organizationId: str, **kwargs):
"""
**Update the IPsec SLA policies for an organization**
@@ -1741,7 +2234,7 @@ def updateOrganizationApplianceVpnSiteToSiteIpsecPeersSlas(self, organizationId:
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/vpn/siteToSite/ipsec/peers/slas"
body_params = [
@@ -1769,7 +2262,7 @@ def updateOrganizationApplianceVpnThirdPartyVPNPeers(self, organizationId: str,
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/appliance/vpn/thirdPartyVPNPeers"
body_params = [
@@ -1797,7 +2290,7 @@ def assignOrganizationPoliciesGlobalGroupPoliciesApplianceVlans(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/appliance/vlans/assign"
body_params = [
@@ -1826,7 +2319,7 @@ def removeOrganizationPoliciesGlobalGroupPoliciesApplianceVlans(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/appliance/vlans/remove"
body_params = [
diff --git a/meraki/api/batch/assistant.py b/meraki/api/batch/assistant.py
new file mode 100644
index 00000000..31bf6782
--- /dev/null
+++ b/meraki/api/batch/assistant.py
@@ -0,0 +1,3 @@
+class ActionBatchAssistant(object):
+ def __init__(self):
+ super(ActionBatchAssistant, self).__init__()
diff --git a/meraki/api/batch/camera.py b/meraki/api/batch/camera.py
index 9a2e7b2d..de7d5709 100644
--- a/meraki/api/batch/camera.py
+++ b/meraki/api/batch/camera.py
@@ -18,7 +18,7 @@ def updateDeviceCameraCustomAnalytics(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/camera/customAnalytics"
body_params = [
@@ -67,7 +67,7 @@ def updateDeviceCameraQualityAndRetention(self, serial: str, **kwargs):
f'''"motionDetectorVersion" cannot be "{kwargs["motionDetectorVersion"]}", & must be set to one of: {options}'''
)
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/camera/qualityAndRetention"
body_params = [
@@ -101,7 +101,7 @@ def updateDeviceCameraSense(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/camera/sense"
body_params = [
@@ -129,7 +129,7 @@ def updateDeviceCameraVideoSettings(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/camera/video/settings"
body_params = [
@@ -154,7 +154,7 @@ def updateDeviceCameraWirelessProfiles(self, serial: str, ids: dict, **kwargs):
kwargs = locals()
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/camera/wirelessProfiles"
body_params = [
@@ -167,3 +167,82 @@ def updateDeviceCameraWirelessProfiles(self, serial: str, ids: dict, **kwargs):
"body": payload,
}
return action
+
+ def createNetworkCameraVideoWall(self, networkId: str, name: str, tiles: list, **kwargs):
+ """
+ **Create a new video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - name (string): The name of the video wall.
+ - tiles (array): The tiles that should appear on the video wall.
+ - index (integer): The order that this wall should appear on the video wall list.
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls"
+
+ body_params = [
+ "name",
+ "index",
+ "tiles",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkCameraVideoWall(self, networkId: str, id: str, name: str, tiles: list, **kwargs):
+ """
+ **Update the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - id (string): ID
+ - name (string): The name of the video wall.
+ - tiles (array): The tiles that should appear on the video wall.
+ - index (integer): The order that this wall should appear on the video wall list.
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls/{id}"
+
+ body_params = [
+ "name",
+ "index",
+ "tiles",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteNetworkCameraVideoWall(self, networkId: str, id: str):
+ """
+ **Delete the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - id (string): ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
diff --git a/meraki/api/batch/campusGateway.py b/meraki/api/batch/campusGateway.py
index c2a6b8e9..fb9aa940 100644
--- a/meraki/api/batch/campusGateway.py
+++ b/meraki/api/batch/campusGateway.py
@@ -24,7 +24,7 @@ def createNetworkCampusGatewayCluster(
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/campusGateway/clusters"
body_params = [
@@ -62,8 +62,8 @@ def updateNetworkCampusGatewayCluster(self, networkId: str, clusterId: str, **kw
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- clusterId = urllib.parse.quote(clusterId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clusterId = urllib.parse.quote(str(clusterId), safe="")
resource = f"/networks/{networkId}/campusGateway/clusters/{clusterId}"
body_params = [
@@ -82,3 +82,130 @@ def updateNetworkCampusGatewayCluster(self, networkId: str, clusterId: str, **kw
"body": payload,
}
return action
+
+ def deleteNetworkCampusGatewayCluster(self, networkId: str, clusterId: str):
+ """
+ **Delete a cluster**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-campus-gateway-cluster
+
+ - networkId (string): Network ID
+ - clusterId (string): Cluster ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clusterId = urllib.parse.quote(str(clusterId), safe="")
+ resource = f"/networks/{networkId}/campusGateway/clusters/{clusterId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateNetworkCampusGatewaySsidMdns(self, networkId: str, number: str, **kwargs):
+ """
+ **Update the mDNS gateway settings and rules for a SSID and cluster**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-campus-gateway-ssid-mdns
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - enabled (boolean): If true, mDNS gateway is enabled for this SSID and cluster.
+ - rules (array): List of mDNS forwarding rules.
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/campusGateway/ssids/{number}/mdns"
+
+ body_params = [
+ "enabled",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def provisionOrganizationCampusGatewayClusters(
+ self,
+ organizationId: str,
+ clusterId: str,
+ network: dict,
+ name: str,
+ uplinks: list,
+ tunnels: list,
+ nameservers: dict,
+ portChannels: list,
+ **kwargs,
+ ):
+ """
+ **Provisions a cluster,adds campus gateways to it and associate/dissociate failover targets.**
+ https://developer.cisco.com/meraki/api-v1/#!provision-organization-campus-gateway-clusters
+
+ - organizationId (string): Organization ID
+ - clusterId (string): ID of the cluster to be provisioned
+ - network (object): Network to be provisioned
+ - name (string): Name of the new cluster
+ - uplinks (array): Uplink interface settings of the cluster
+ - tunnels (array): Tunnel interface settings of the cluster: Reuse uplink or specify tunnel interface
+ - nameservers (object): Nameservers of the cluster
+ - portChannels (array): Port channel settings of the cluster
+ - devices (array): Devices to be added to the cluster
+ - failover (object): Failover targets for the cluster
+ - notes (string): Notes about cluster with max size of 511 characters allowed
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/provision"
+
+ body_params = [
+ "clusterId",
+ "network",
+ "name",
+ "uplinks",
+ "tunnels",
+ "nameservers",
+ "portChannels",
+ "devices",
+ "failover",
+ "notes",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "provision",
+ "body": payload,
+ }
+ return action
+
+ def batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate(self, organizationId: str, **kwargs):
+ """
+ **Update MCG cluster-network tunnel settings for multiple networks**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-campus-gateway-clusters-tunneling-by-cluster-by-network-update
+
+ - organizationId (string): Organization ID
+ - items (array): MCG cluster-network tunnel settings
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/tunneling/byCluster/byNetwork/batchUpdate"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "batch_update",
+ "body": payload,
+ }
+ return action
diff --git a/meraki/api/batch/cellularGateway.py b/meraki/api/batch/cellularGateway.py
index e57b9508..2c2f7a62 100644
--- a/meraki/api/batch/cellularGateway.py
+++ b/meraki/api/batch/cellularGateway.py
@@ -17,7 +17,7 @@ def updateDeviceCellularGatewayLan(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/cellularGateway/lan"
body_params = [
@@ -43,7 +43,7 @@ def updateDeviceCellularGatewayPortForwardingRules(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/cellularGateway/portForwardingRules"
body_params = [
@@ -68,7 +68,7 @@ def updateNetworkCellularGatewayConnectivityMonitoringDestinations(self, network
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/cellularGateway/connectivityMonitoringDestinations"
body_params = [
@@ -95,7 +95,7 @@ def updateNetworkCellularGatewayDhcp(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/cellularGateway/dhcp"
body_params = [
@@ -123,7 +123,7 @@ def updateNetworkCellularGatewaySubnetPool(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/cellularGateway/subnetPool"
body_params = [
@@ -149,7 +149,7 @@ def updateNetworkCellularGatewayUplink(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/cellularGateway/uplink"
body_params = [
@@ -175,8 +175,8 @@ def updateOrganizationCellularGatewayEsimsInventory(self, organizationId: str, i
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/cellularGateway/esims/inventory/{id}"
body_params = [
@@ -207,7 +207,7 @@ def createOrganizationCellularGatewayEsimsServiceProvidersAccount(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/cellularGateway/esims/serviceProviders/accounts"
body_params = [
@@ -238,8 +238,8 @@ def updateOrganizationCellularGatewayEsimsServiceProvidersAccount(self, organiza
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- accountId = urllib.parse.quote(accountId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ accountId = urllib.parse.quote(str(accountId), safe="")
resource = f"/organizations/{organizationId}/cellularGateway/esims/serviceProviders/accounts/{accountId}"
body_params = [
@@ -263,8 +263,8 @@ def deleteOrganizationCellularGatewayEsimsServiceProvidersAccount(self, organiza
- accountId (string): Account ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- accountId = urllib.parse.quote(accountId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ accountId = urllib.parse.quote(str(accountId), safe="")
resource = f"/organizations/{organizationId}/cellularGateway/esims/serviceProviders/accounts/{accountId}"
action = {
@@ -284,7 +284,7 @@ def createOrganizationCellularGatewayEsimsSwap(self, organizationId: str, swaps:
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/cellularGateway/esims/swap"
body_params = [
@@ -307,8 +307,8 @@ def updateOrganizationCellularGatewayEsimsSwap(self, id: str, organizationId: st
- organizationId (string): Organization ID
"""
- id = urllib.parse.quote(id, safe="")
- organizationId = urllib.parse.quote(organizationId, safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/cellularGateway/esims/swap/{id}"
action = {
diff --git a/meraki/api/batch/devices.py b/meraki/api/batch/devices.py
index c970b84e..130c2fae 100644
--- a/meraki/api/batch/devices.py
+++ b/meraki/api/batch/devices.py
@@ -24,7 +24,7 @@ def updateDevice(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}"
body_params = [
@@ -57,7 +57,7 @@ def updateDeviceCellularGeolocations(self, serial: str, enabled: bool, **kwargs)
kwargs = locals()
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/cellular/geolocations"
body_params = [
@@ -91,7 +91,7 @@ def createDeviceCellularUplinksBandsMasksUpdate(self, serial: str, slot: str, ty
options = ["5GNSA", "5GSA", "LTE"]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/cellular/uplinks/bands/masks/update"
body_params = [
@@ -107,6 +107,50 @@ def createDeviceCellularUplinksBandsMasksUpdate(self, serial: str, slot: str, ty
}
return action
+ def revokeDeviceCertificate(self, serial: str, certificateSerial: str, **kwargs):
+ """
+ **Revoke a device certificate. The device and certificate are identified by the path parameters. You may supply a revocation reason in the request body; if omitted, a default reason is applied.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-device-certificate
+
+ - serial (string): Serial
+ - certificateSerial (string): Certificate serial
+ - reason (string): Revocation reason per RFC 5280; omit to use `unspecified`
+ """
+
+ kwargs.update(locals())
+
+ if "reason" in kwargs:
+ options = [
+ "aACompromise",
+ "affiliationChanged",
+ "cACompromise",
+ "certificateHold",
+ "cessationOfOperation",
+ "keyCompromise",
+ "privilegeWithdrawn",
+ "removeFromCRL",
+ "superseded",
+ "unspecified",
+ ]
+ assert kwargs["reason"] in options, (
+ f'''"reason" cannot be "{kwargs["reason"]}", & must be set to one of: {options}'''
+ )
+
+ serial = urllib.parse.quote(str(serial), safe="")
+ certificateSerial = urllib.parse.quote(str(certificateSerial), safe="")
+ resource = f"/devices/{serial}/certificates/{certificateSerial}/revoke"
+
+ body_params = [
+ "reason",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "revoke",
+ "body": payload,
+ }
+ return action
+
def createDeviceLiveToolsLedsBlink(self, serial: str, duration: int, **kwargs):
"""
**Enqueue a job to blink LEDs on a device. This endpoint has a rate limit of one request every 10 seconds.**
@@ -119,7 +163,7 @@ def createDeviceLiveToolsLedsBlink(self, serial: str, duration: int, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/liveTools/leds/blink"
body_params = [
@@ -145,7 +189,7 @@ def createDeviceLiveToolsPortsStatus(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/liveTools/ports/status"
body_params = [
@@ -170,7 +214,7 @@ def createDeviceLiveToolsPowerUsage(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/liveTools/power/usage"
body_params = [
@@ -184,6 +228,31 @@ def createDeviceLiveToolsPowerUsage(self, serial: str, **kwargs):
}
return action
+ def createDeviceLiveToolsReboot(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to reboot a device. This endpoint has a rate limit of one request every 60 seconds.**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-reboot
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/reboot"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "device",
+ "body": payload,
+ }
+ return action
+
def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs):
"""
**Enqueue a job to perform a routing table lookup request for a device. The routing table lookup request fetches a specific set of routes based on filters. Any combination of search filters can be applied. Only Cisco Secure Routers are supported.**
@@ -219,7 +288,7 @@ def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs):
]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/liveTools/routingTable/lookups"
body_params = [
@@ -248,7 +317,7 @@ def createDeviceLiveToolsRoutingTableSummary(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/liveTools/routingTable/summaries"
body_params = [
@@ -273,7 +342,7 @@ def createDeviceLiveToolsThroughputTest(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/liveTools/throughputTest"
body_params = [
@@ -299,7 +368,7 @@ def updateDeviceManagementInterface(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/managementInterface"
body_params = [
diff --git a/meraki/api/batch/insight.py b/meraki/api/batch/insight.py
index 7e850f1c..aa6666ff 100644
--- a/meraki/api/batch/insight.py
+++ b/meraki/api/batch/insight.py
@@ -5,6 +5,83 @@ class ActionBatchInsight(object):
def __init__(self):
super(ActionBatchInsight, self).__init__()
+ def createOrganizationInsightApplication(self, organizationId: str, counterSetRuleId: int, **kwargs):
+ """
+ **Add an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - counterSetRuleId (integer): The id of the counter set rule
+ - enableSmartThresholds (boolean): Enable Smart Thresholds
+ - thresholds (object): Thresholds defined by a user for each application
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications"
+
+ body_params = [
+ "counterSetRuleId",
+ "enableSmartThresholds",
+ "thresholds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationInsightApplication(self, organizationId: str, applicationId: str, **kwargs):
+ """
+ **Update an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - applicationId (string): Application ID
+ - enableSmartThresholds (boolean): Enable Smart Thresholds
+ - thresholds (object): Thresholds defined by a user for each application
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ applicationId = urllib.parse.quote(str(applicationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications/{applicationId}"
+
+ body_params = [
+ "enableSmartThresholds",
+ "thresholds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationInsightApplication(self, organizationId: str, applicationId: str):
+ """
+ **Delete an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - applicationId (string): Application ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ applicationId = urllib.parse.quote(str(applicationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications/{applicationId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def createOrganizationInsightMonitoredMediaServer(self, organizationId: str, name: str, address: str, **kwargs):
"""
**Add a media server to be monitored for this organization. Only valid for organizations with Meraki Insight.**
@@ -18,7 +95,7 @@ def createOrganizationInsightMonitoredMediaServer(self, organizationId: str, nam
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/insight/monitoredMediaServers"
body_params = [
@@ -48,8 +125,8 @@ def updateOrganizationInsightMonitoredMediaServer(self, organizationId: str, mon
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- monitoredMediaServerId = urllib.parse.quote(monitoredMediaServerId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ monitoredMediaServerId = urllib.parse.quote(str(monitoredMediaServerId), safe="")
resource = f"/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}"
body_params = [
@@ -74,8 +151,8 @@ def deleteOrganizationInsightMonitoredMediaServer(self, organizationId: str, mon
- monitoredMediaServerId (string): Monitored media server ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- monitoredMediaServerId = urllib.parse.quote(monitoredMediaServerId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ monitoredMediaServerId = urllib.parse.quote(str(monitoredMediaServerId), safe="")
resource = f"/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}"
action = {
@@ -83,3 +160,78 @@ def deleteOrganizationInsightMonitoredMediaServer(self, organizationId: str, mon
"operation": "destroy",
}
return action
+
+ def createOrganizationInsightWebApp(self, organizationId: str, name: str, hostname: str, **kwargs):
+ """
+ **Add a custom web application for Insight to be able to track**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the Web Application
+ - hostname (string): The hostname of Web Application
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps"
+
+ body_params = [
+ "name",
+ "hostname",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationInsightWebApp(self, organizationId: str, customCounterSetRuleId: str, **kwargs):
+ """
+ **Update a custom web application for Insight to be able to track**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - customCounterSetRuleId (string): Custom counter set rule ID
+ - name (string): The name of the Web Application
+ - hostname (string): The hostname of Web Application
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ customCounterSetRuleId = urllib.parse.quote(str(customCounterSetRuleId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps/{customCounterSetRuleId}"
+
+ body_params = [
+ "name",
+ "hostname",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationInsightWebApp(self, organizationId: str, customCounterSetRuleId: str):
+ """
+ **Delete a custom web application by counter set rule id.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - customCounterSetRuleId (string): Custom counter set rule ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ customCounterSetRuleId = urllib.parse.quote(str(customCounterSetRuleId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps/{customCounterSetRuleId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
diff --git a/meraki/api/batch/nac.py b/meraki/api/batch/nac.py
new file mode 100644
index 00000000..6852539a
--- /dev/null
+++ b/meraki/api/batch/nac.py
@@ -0,0 +1,316 @@
+import urllib
+
+
+class ActionBatchNac(object):
+ def __init__(self):
+ super(ActionBatchNac, self).__init__()
+
+ def createOrganizationNacCertificatesAuthoritiesCrl(
+ self, organizationId: str, caId: str, content: str, isDelta: bool, **kwargs
+ ):
+ """
+ **Create a new CRL (either base or delta) for an existing CA**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-certificates-authorities-crl
+
+ - organizationId (string): Organization ID
+ - caId (string): ID of the CRL issuer
+ - content (string): CRL content in PEM format
+ - isDelta (boolean): Whether it's a delta CRL or not
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls"
+
+ body_params = [
+ "caId",
+ "content",
+ "isDelta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationNacCertificatesAuthoritiesCrl(self, organizationId: str, crlId: str):
+ """
+ **Deletes a whole CRL, including all its deltas (in case of base CRL removal)**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-certificates-authorities-crl
+
+ - organizationId (string): Organization ID
+ - crlId (string): Crl ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ crlId = urllib.parse.quote(str(crlId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls/{crlId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationNacCertificatesImport(self, organizationId: str, contents: str, **kwargs):
+ """
+ **Import certificate for this organization or validate without persisting**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-certificates-import
+
+ - organizationId (string): Organization ID
+ - contents (string): Certificate content in valid PEM format
+ - dryRun (boolean): If true, validates the certificate without persisting it
+ - profile (object): Profile object containing certificate config fields
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/import"
+
+ body_params = [
+ "contents",
+ "dryRun",
+ "profile",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationNacCertificate(self, organizationId: str, certificateId: str, profile: dict, **kwargs):
+ """
+ **Update certificate configuration by certificateId for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-certificate
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ - profile (object): Profile object containing certificate config fields
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/{certificateId}"
+
+ body_params = [
+ "profile",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "action",
+ "body": payload,
+ }
+ return action
+
+ def bulkOrganizationNacClientsDelete(self, organizationId: str, clientIds: list, **kwargs):
+ """
+ **Delete existing client(s) for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-nac-clients-delete
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of ids for specific client retrieval
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkDelete"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationNacClientsBulkEdit(self, organizationId: str, clientIds: list, **kwargs):
+ """
+ **Bulk Update of existing clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-bulk-edit
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of clients ids to apply the bulk edit operation on.
+ - description (string): User provided description to be applied on the list of clients provided
+ - groups (object): Client group information to be applied on the list of clients provided
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkEdit"
+
+ body_params = [
+ "clientIds",
+ "description",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "edit",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationNacClientsBulkUpload(
+ self, organizationId: str, contents: str, updateClients: bool, createClientGroups: bool, **kwargs
+ ):
+ """
+ **Bulk upload of clients, client groups and their associations for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-bulk-upload
+
+ - organizationId (string): Organization ID
+ - contents (string): CSV file content in Base64 encoded string format
+ - updateClients (boolean): The updateClients indicates whether existing clients must be updated with new data from the CSV
+ - createClientGroups (boolean): The createClientGroups indicates whether new client groups must be created or not
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkUpload"
+
+ body_params = [
+ "contents",
+ "updateClients",
+ "createClientGroups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationNacClientsGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a client group for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the group for access control model
+ - description (string): User provided description of the group
+ - members (array): List of client members associated with the group
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups"
+
+ body_params = [
+ "name",
+ "description",
+ "members",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationNacClientsGroup(self, organizationId: str, groupId: str, **kwargs):
+ """
+ **Update an existing client group for the organization with bulk member operations**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - name (string): The name of the group for access control model
+ - description (string): User provided description of the group
+ - members (object): Bulk member operations with addList/removeList arrays
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups/{groupId}"
+
+ body_params = [
+ "name",
+ "description",
+ "members",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationNacClientsGroup(self, organizationId: str, groupId: str):
+ """
+ **Delete an existing client group for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups/{groupId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateOrganizationNacClient(self, organizationId: str, clientId: str, mac: str, **kwargs):
+ """
+ **Update an existing client for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-client
+
+ - organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - mac (string): The MAC address of the client
+ - type (string): Type describes if the network client belongs to an individual user or corporate
+ - owner (string): The username of the owner of the client
+ - description (string): User provided description for the client
+ - uuid (string): Universally unique identifier of the client
+ - userDetails (array): List of users of this network client
+ - oui (object): Organizationally unique identifier assigned to a vendor of the client
+ - groups (object): Client group membership changes
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["BYOD", "corporate"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/{clientId}"
+
+ body_params = [
+ "type",
+ "owner",
+ "mac",
+ "description",
+ "uuid",
+ "userDetails",
+ "oui",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
diff --git a/meraki/api/batch/networks.py b/meraki/api/batch/networks.py
index 58672c98..5099ef43 100644
--- a/meraki/api/batch/networks.py
+++ b/meraki/api/batch/networks.py
@@ -20,7 +20,7 @@ def updateNetwork(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}"
body_params = [
@@ -46,7 +46,7 @@ def deleteNetwork(self, networkId: str):
- networkId (string): Network ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}"
action = {
@@ -67,7 +67,7 @@ def bindNetwork(self, networkId: str, configTemplateId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/bind"
body_params = [
@@ -103,7 +103,7 @@ def provisionNetworkClients(self, networkId: str, clients: list, devicePolicy: s
f'''"devicePolicy" cannot be "{kwargs["devicePolicy"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/clients/provision"
body_params = [
@@ -134,7 +134,7 @@ def claimNetworkDevices(self, networkId: str, serials: list, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/devices/claim"
body_params = [
@@ -164,7 +164,7 @@ def vmxNetworkDevicesClaim(self, networkId: str, size: str, **kwargs):
options = ["100", "large", "medium", "small", "xlarge"]
assert kwargs["size"] in options, f'''"size" cannot be "{kwargs["size"]}", & must be set to one of: {options}'''
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/devices/claim/vmx"
body_params = [
@@ -189,7 +189,7 @@ def removeNetworkDevices(self, networkId: str, serial: str, **kwargs):
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/devices/remove"
body_params = [
@@ -214,7 +214,7 @@ def updateNetworkDevicesSyslogServers(self, networkId: str, servers: list, **kwa
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/devices/syslog/servers"
body_params = [
@@ -241,7 +241,7 @@ def updateNetworkFirmwareUpgrades(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/firmwareUpgrades"
body_params = [
@@ -287,7 +287,7 @@ def createNetworkFirmwareUpgradesRollback(self, networkId: str, reasons: list, *
f'''"product" cannot be "{kwargs["product"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/firmwareUpgrades/rollbacks"
body_params = [
@@ -319,7 +319,7 @@ def createNetworkFirmwareUpgradesStagedGroup(self, networkId: str, name: str, is
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/firmwareUpgrades/staged/groups"
body_params = [
@@ -345,8 +345,8 @@ def deleteNetworkFirmwareUpgradesStagedGroup(self, networkId: str, groupId: str)
- groupId (string): Group ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- groupId = urllib.parse.quote(groupId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
resource = f"/networks/{networkId}/firmwareUpgrades/staged/groups/{groupId}"
action = {
@@ -366,7 +366,7 @@ def batchNetworkFloorPlansAutoLocateJobs(self, networkId: str, jobs: list, **kwa
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/floorPlans/autoLocate/jobs/batch"
body_params = [
@@ -389,8 +389,8 @@ def cancelNetworkFloorPlansAutoLocateJob(self, networkId: str, jobId: str):
- jobId (string): Job ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- jobId = urllib.parse.quote(jobId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ jobId = urllib.parse.quote(str(jobId), safe="")
resource = f"/networks/{networkId}/floorPlans/autoLocate/jobs/{jobId}/cancel"
action = {
@@ -411,8 +411,8 @@ def publishNetworkFloorPlansAutoLocateJob(self, networkId: str, jobId: str, **kw
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- jobId = urllib.parse.quote(jobId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ jobId = urllib.parse.quote(str(jobId), safe="")
resource = f"/networks/{networkId}/floorPlans/autoLocate/jobs/{jobId}/publish"
body_params = [
@@ -438,8 +438,8 @@ def recalculateNetworkFloorPlansAutoLocateJob(self, networkId: str, jobId: str,
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- jobId = urllib.parse.quote(jobId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ jobId = urllib.parse.quote(str(jobId), safe="")
resource = f"/networks/{networkId}/floorPlans/autoLocate/jobs/{jobId}/recalculate"
body_params = [
@@ -464,7 +464,7 @@ def batchNetworkFloorPlansDevicesUpdate(self, networkId: str, assignments: list,
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/floorPlans/devices/batchUpdate"
body_params = [
@@ -492,13 +492,14 @@ def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
- topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan.
- topRightCorner (object): The longitude and latitude of the top right corner of your floor plan.
- floorNumber (number): The floor number of the floors within the building
+ - buildingId (string): The ID of the building that this floor belongs to.
- imageContents (string): The file contents (a base 64 encoded string) of your new image. Supported formats are PNG, GIF, and JPG. Note that all images are saved as PNG files, regardless of the format they are uploaded in. If you upload a new image, and you do NOT specify any new geolocation fields ('center, 'topLeftCorner', etc), the floor plan will be recentered with no rotation in order to maintain the aspect ratio of your new image.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- floorPlanId = urllib.parse.quote(floorPlanId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ floorPlanId = urllib.parse.quote(str(floorPlanId), safe="")
resource = f"/networks/{networkId}/floorPlans/{floorPlanId}"
body_params = [
@@ -509,6 +510,7 @@ def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
"topLeftCorner",
"topRightCorner",
"floorNumber",
+ "buildingId",
"imageContents",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -528,8 +530,8 @@ def deleteNetworkFloorPlan(self, networkId: str, floorPlanId: str):
- floorPlanId (string): Floor plan ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- floorPlanId = urllib.parse.quote(floorPlanId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ floorPlanId = urllib.parse.quote(str(floorPlanId), safe="")
resource = f"/networks/{networkId}/floorPlans/{floorPlanId}"
action = {
@@ -565,7 +567,7 @@ def createNetworkGroupPolicy(self, networkId: str, name: str, **kwargs):
f'''"splashAuthSettings" cannot be "{kwargs["splashAuthSettings"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/groupPolicies"
body_params = [
@@ -614,8 +616,8 @@ def updateNetworkGroupPolicy(self, networkId: str, groupPolicyId: str, **kwargs)
f'''"splashAuthSettings" cannot be "{kwargs["splashAuthSettings"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- groupPolicyId = urllib.parse.quote(groupPolicyId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ groupPolicyId = urllib.parse.quote(str(groupPolicyId), safe="")
resource = f"/networks/{networkId}/groupPolicies/{groupPolicyId}"
body_params = [
@@ -648,8 +650,8 @@ def deleteNetworkGroupPolicy(self, networkId: str, groupPolicyId: str, **kwargs)
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- groupPolicyId = urllib.parse.quote(groupPolicyId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ groupPolicyId = urllib.parse.quote(str(groupPolicyId), safe="")
resource = f"/networks/{networkId}/groupPolicies/{groupPolicyId}"
action = {
@@ -658,6 +660,58 @@ def deleteNetworkGroupPolicy(self, networkId: str, groupPolicyId: str, **kwargs)
}
return action
+ def updateNetworkLocationScanning(self, networkId: str, **kwargs):
+ """
+ **Change scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-location-scanning
+
+ - networkId (string): Network ID
+ - analyticsEnabled (boolean): Collect location and scanning analytics
+ - scanningApiEnabled (boolean): Enable push API for scanning events, analytics must be enabled
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning"
+
+ body_params = [
+ "analyticsEnabled",
+ "scanningApiEnabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkLocationScanningHttpServers(self, networkId: str, endpoints: list, **kwargs):
+ """
+ **Set the list of scanning API receivers. Old receivers will be removed**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-location-scanning-http-servers
+
+ - networkId (string): Network ID
+ - endpoints (array): A set of http server configurations
+ """
+
+ kwargs = locals()
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning/httpServers"
+
+ body_params = [
+ "endpoints",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def createNetworkMerakiAuthUser(self, networkId: str, email: str, authorizations: list, **kwargs):
"""
**Authorize a user configured with Meraki Authentication for a network (currently supports 802.1X, splash guest, and client VPN users, and currently, organizations have a 50,000 user cap)**
@@ -681,7 +735,7 @@ def createNetworkMerakiAuthUser(self, networkId: str, email: str, authorizations
f'''"accountType" cannot be "{kwargs["accountType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/merakiAuthUsers"
body_params = [
@@ -713,8 +767,8 @@ def deleteNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **k
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- merakiAuthUserId = urllib.parse.quote(merakiAuthUserId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ merakiAuthUserId = urllib.parse.quote(str(merakiAuthUserId), safe="")
resource = f"/networks/{networkId}/merakiAuthUsers/{merakiAuthUserId}"
action = {
@@ -738,8 +792,8 @@ def updateNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **k
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- merakiAuthUserId = urllib.parse.quote(merakiAuthUserId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ merakiAuthUserId = urllib.parse.quote(str(merakiAuthUserId), safe="")
resource = f"/networks/{networkId}/merakiAuthUsers/{merakiAuthUserId}"
body_params = [
@@ -767,11 +821,18 @@ def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: in
- port (integer): Host port though which the MQTT broker can be reached.
- security (object): Security settings of the MQTT broker.
- authentication (object): Authentication settings of the MQTT broker
+ - productType (string): The product type for which the MQTT broker is being created.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ if "productType" in kwargs:
+ options = ["camera", "wireless"]
+ assert kwargs["productType"] in options, (
+ f'''"productType" cannot be "{kwargs["productType"]}", & must be set to one of: {options}'''
+ )
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/mqttBrokers"
body_params = [
@@ -780,6 +841,7 @@ def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: in
"port",
"security",
"authentication",
+ "productType",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -805,8 +867,8 @@ def updateNetworkMqttBroker(self, networkId: str, mqttBrokerId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- mqttBrokerId = urllib.parse.quote(mqttBrokerId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ mqttBrokerId = urllib.parse.quote(str(mqttBrokerId), safe="")
resource = f"/networks/{networkId}/mqttBrokers/{mqttBrokerId}"
body_params = [
@@ -833,8 +895,8 @@ def deleteNetworkMqttBroker(self, networkId: str, mqttBrokerId: str):
- mqttBrokerId (string): Mqtt broker ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- mqttBrokerId = urllib.parse.quote(mqttBrokerId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ mqttBrokerId = urllib.parse.quote(str(mqttBrokerId), safe="")
resource = f"/networks/{networkId}/mqttBrokers/{mqttBrokerId}"
action = {
@@ -853,12 +915,13 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
- remoteStatusPageEnabled (boolean): Enables / disables access to the device status page (http://[device's LAN IP]). Optional. Can only be set if localStatusPageEnabled is set to true
- localStatusPage (object): A hash of Local Status page(s)' authentication options applied to the Network.
- securePort (object): A hash of SecureConnect options applied to the Network.
+ - fips (object): A hash of FIPS options applied to the Network
- namedVlans (object): A hash of Named VLANs options applied to the Network.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/settings"
body_params = [
@@ -866,6 +929,7 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
"remoteStatusPageEnabled",
"localStatusPage",
"securePort",
+ "fips",
"namedVlans",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -876,6 +940,116 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
}
return action
+ def createNetworkSitesBuilding(self, networkId: str, name: str, **kwargs):
+ """
+ **Create a new building**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sites-building
+
+ - networkId (string): Network ID
+ - name (string): The name of the building
+ - floors (array): The floors of the building
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings"
+
+ body_params = [
+ "name",
+ "floors",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def deleteNetworkSitesBuilding(self, networkId: str, buildingId: str):
+ """
+ **Delete a building**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-sites-building
+
+ - networkId (string): Network ID
+ - buildingId (string): Building ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ buildingId = urllib.parse.quote(str(buildingId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings/{buildingId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateNetworkSitesBuilding(self, networkId: str, buildingId: str, **kwargs):
+ """
+ **Update a building**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-sites-building
+
+ - networkId (string): Network ID
+ - buildingId (string): Building ID
+ - name (string): The name of the building
+ - floors (array): The floors of the building
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ buildingId = urllib.parse.quote(str(buildingId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings/{buildingId}"
+
+ body_params = [
+ "name",
+ "floors",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkSnmpTraps(self, networkId: str, **kwargs):
+ """
+ **Update the SNMP trap configuration for the specified network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-snmp-traps
+
+ - networkId (string): Network ID
+ - mode (string): SNMP trap protocol version
+ - receiver (object): Stores the port and address
+ - v2 (object): V2 mode
+ - v3 (object): V3 mode
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["disabled", "v1/v2c", "v3"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/snmp/traps"
+
+ body_params = [
+ "mode",
+ "receiver",
+ "v2",
+ "v3",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def splitNetwork(self, networkId: str):
"""
**Split a combined network into individual networks for each type of device**
@@ -884,7 +1058,7 @@ def splitNetwork(self, networkId: str):
- networkId (string): Network ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/split"
action = {
@@ -904,7 +1078,7 @@ def unbindNetwork(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/unbind"
body_params = [
@@ -928,15 +1102,17 @@ def createNetworkVlanProfile(self, networkId: str, name: str, vlanNames: list, v
- vlanNames (array): An array of named VLANs
- vlanGroups (array): An array of VLAN groups
- iname (string): IName of the profile
+ - allowedVlans (string): The VLANs allowed on the VLAN profile. Only applicable to trunk ports. The given range must be inclusive of all named VLANs.
"""
- kwargs = locals()
+ kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/vlanProfiles"
body_params = [
"name",
+ "allowedVlans",
"vlanNames",
"vlanGroups",
"iname",
@@ -958,8 +1134,8 @@ def deleteNetworkVlanProfile(self, networkId: str, iname: str):
- iname (string): Iname
"""
- networkId = urllib.parse.quote(networkId, safe="")
- iname = urllib.parse.quote(iname, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
resource = f"/networks/{networkId}/vlanProfiles/{iname}"
action = {
@@ -983,7 +1159,7 @@ def createNetworkWebhooksPayloadTemplate(self, networkId: str, name: str, **kwar
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/webhooks/payloadTemplates"
body_params = [
@@ -1010,8 +1186,8 @@ def deleteNetworkWebhooksPayloadTemplate(self, networkId: str, payloadTemplateId
- payloadTemplateId (string): Payload template ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- payloadTemplateId = urllib.parse.quote(payloadTemplateId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
resource = f"/networks/{networkId}/webhooks/payloadTemplates/{payloadTemplateId}"
action = {
@@ -1036,8 +1212,8 @@ def updateNetworkWebhooksPayloadTemplate(self, networkId: str, payloadTemplateId
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- payloadTemplateId = urllib.parse.quote(payloadTemplateId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
resource = f"/networks/{networkId}/webhooks/payloadTemplates/{payloadTemplateId}"
body_params = [
diff --git a/meraki/api/batch/organizations.py b/meraki/api/batch/organizations.py
index 172a8b98..b19c2bf2 100644
--- a/meraki/api/batch/organizations.py
+++ b/meraki/api/batch/organizations.py
@@ -19,7 +19,7 @@ def updateOrganization(self, organizationId: str, **kwargs):
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}"
body_params = [
@@ -56,7 +56,7 @@ def createOrganizationAdaptivePolicyAcl(self, organizationId: str, name: str, ru
f'''"ipVersion" cannot be "{kwargs["ipVersion"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/acls"
body_params = [
@@ -94,8 +94,8 @@ def updateOrganizationAdaptivePolicyAcl(self, organizationId: str, aclId: str, *
f'''"ipVersion" cannot be "{kwargs["ipVersion"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
- aclId = urllib.parse.quote(aclId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ aclId = urllib.parse.quote(str(aclId), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/acls/{aclId}"
body_params = [
@@ -121,8 +121,8 @@ def deleteOrganizationAdaptivePolicyAcl(self, organizationId: str, aclId: str):
- aclId (string): Acl ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- aclId = urllib.parse.quote(aclId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ aclId = urllib.parse.quote(str(aclId), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/acls/{aclId}"
action = {
@@ -145,7 +145,7 @@ def createOrganizationAdaptivePolicyGroup(self, organizationId: str, name: str,
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/groups"
body_params = [
@@ -177,8 +177,8 @@ def updateOrganizationAdaptivePolicyGroup(self, organizationId: str, id: str, **
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/groups/{id}"
body_params = [
@@ -204,8 +204,8 @@ def deleteOrganizationAdaptivePolicyGroup(self, organizationId: str, id: str):
- id (string): ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/groups/{id}"
action = {
@@ -234,7 +234,7 @@ def createOrganizationAdaptivePolicyPolicy(self, organizationId: str, sourceGrou
f'''"lastEntryRule" cannot be "{kwargs["lastEntryRule"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/policies"
body_params = [
@@ -272,8 +272,8 @@ def updateOrganizationAdaptivePolicyPolicy(self, organizationId: str, id: str, *
f'''"lastEntryRule" cannot be "{kwargs["lastEntryRule"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/policies/{id}"
body_params = [
@@ -299,8 +299,8 @@ def deleteOrganizationAdaptivePolicyPolicy(self, organizationId: str, id: str):
- id (string): ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/policies/{id}"
action = {
@@ -320,7 +320,7 @@ def updateOrganizationAdaptivePolicySettings(self, organizationId: str, **kwargs
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/adaptivePolicy/settings"
body_params = [
@@ -364,7 +364,7 @@ def createOrganizationAlertsProfile(
]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/alerts/profiles"
body_params = [
@@ -412,8 +412,8 @@ def updateOrganizationAlertsProfile(self, organizationId: str, alertConfigId: st
]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- organizationId = urllib.parse.quote(organizationId, safe="")
- alertConfigId = urllib.parse.quote(alertConfigId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ alertConfigId = urllib.parse.quote(str(alertConfigId), safe="")
resource = f"/organizations/{organizationId}/alerts/profiles/{alertConfigId}"
body_params = [
@@ -441,8 +441,8 @@ def deleteOrganizationAlertsProfile(self, organizationId: str, alertConfigId: st
- alertConfigId (string): Alert config ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- alertConfigId = urllib.parse.quote(alertConfigId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ alertConfigId = urllib.parse.quote(str(alertConfigId), safe="")
resource = f"/organizations/{organizationId}/alerts/profiles/{alertConfigId}"
action = {
@@ -451,6 +451,255 @@ def deleteOrganizationAlertsProfile(self, organizationId: str, alertConfigId: st
}
return action
+ def createOrganizationApiPushProfile(self, organizationId: str, iname: str, topic: dict, receiver: dict, **kwargs):
+ """
+ **Create a new push profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Immutable name of the resource. Must be unique within resources of this type.
+ - topic (object): Push topic
+ - receiver (object): Push receiver profile
+ - name (string): Name of push profile
+ - description (string): Description of push profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles"
+
+ body_params = [
+ "iname",
+ "name",
+ "description",
+ "topic",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationApiPushProfile(self, organizationId: str, iname: str, **kwargs):
+ """
+ **Update a push profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ - name (string): Name of push profile
+ - description (string): Description of push profile
+ - topic (object): Push topic
+ - receiver (object): Push receiver profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles/{iname}"
+
+ body_params = [
+ "name",
+ "description",
+ "topic",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationApiPushProfile(self, organizationId: str, iname: str):
+ """
+ **Delete a push profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles/{iname}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str, receiver: dict, **kwargs):
+ """
+ **Create a new push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Immutable name of the resource. Must be unique within resources of this type.
+ - receiver (object): Webhook receiver
+ - name (string): Name of receiver profile
+ - description (string): Description of receiver profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles"
+
+ body_params = [
+ "iname",
+ "name",
+ "description",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str):
+ """
+ **Delete a push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles/{iname}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str, **kwargs):
+ """
+ **Update a push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ - name (string): Name of the receiver profile
+ - description (string): Description of the receiver profile
+ - receiver (object): API Push Receiver details
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles/{iname}"
+
+ body_params = [
+ "name",
+ "description",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationAuthRadiusServer(self, organizationId: str, address: str, secret: str, **kwargs):
+ """
+ **Add an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - address (string): The IP address or FQDN of the RADIUS server
+ - secret (string): Shared secret of the RADIUS server
+ - name (string): The name of the RADIUS server
+ - modes (array): Available server modes
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers"
+
+ body_params = [
+ "name",
+ "address",
+ "modes",
+ "secret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationAuthRadiusServer(self, organizationId: str, serverId: str, **kwargs):
+ """
+ **Update an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ - name (string): The name of the RADIUS server
+ - address (string): The IP address or FQDN of the RADIUS server
+ - modes (array): Available server modes
+ - secret (string): Shared secret of the RADIUS server
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ body_params = [
+ "name",
+ "address",
+ "modes",
+ "secret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationAuthRadiusServer(self, organizationId: str, serverId: str):
+ """
+ **Delete an organization-wide RADIUS server from a organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def createOrganizationBrandingPolicy(self, organizationId: str, name: str, **kwargs):
"""
**Add a new branding policy to an organization**
@@ -470,7 +719,7 @@ def createOrganizationBrandingPolicy(self, organizationId: str, name: str, **kwa
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/brandingPolicies"
body_params = [
@@ -500,7 +749,7 @@ def updateOrganizationBrandingPoliciesPriorities(self, organizationId: str, **kw
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
body_params = [
@@ -534,8 +783,8 @@ def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- brandingPolicyId = urllib.parse.quote(brandingPolicyId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
body_params = [
@@ -562,8 +811,8 @@ def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId
- brandingPolicyId (string): Branding policy ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- brandingPolicyId = urllib.parse.quote(brandingPolicyId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
action = {
@@ -572,6 +821,216 @@ def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId
}
return action
+ def createOrganizationCertificatesAuthority(self, organizationId: str, featureType: str, **kwargs):
+ """
+ **Create a certificate authority for an organization. The response includes job information for tracking progress.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-certificates-authority
+
+ - organizationId (string): Organization ID
+ - featureType (string): Feature this CA serves (e.g., radsec, openroaming, zigbee)
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ body_params = [
+ "featureType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, **kwargs):
+ """
+ **Trust a newly created certificate authority (transition from untrusted to trusted).**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the certificate authority to trust. The CA must currently be untrusted.
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ body_params = [
+ "authorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, name: str):
+ """
+ **Delete a certificate authority. The feature CA must be untrusted or revoked. Deletion takes effect immediately and the response confirms the deleted authority.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the certificate authority to delete
+ - name (string): Certificate authority name
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ action = {
+ "resource": resource,
+ "operation": "delete",
+ }
+ return action
+
+ def revokeOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, **kwargs):
+ """
+ **Revoke a trusted feature certificate authority.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the feature certificate authority to revoke
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities/revoke"
+
+ body_params = [
+ "authorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "revoke",
+ "body": payload,
+ }
+ return action
+
+ def importOrganizationCertificates(self, organizationId: str, managedBy: str, contents: str, description: str, **kwargs):
+ """
+ **Import certificate for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!import-organization-certificates
+
+ - organizationId (string): Organization ID
+ - managedBy (string): Certificate managed by type [system_manager, mr, encrypted_syslog, grpc_dial_out]
+ - contents (string): Certificate content in valid PEM format
+ - description (string): Certificate description
+ """
+
+ kwargs = locals()
+
+ if "managedBy" in kwargs:
+ options = ["encrypted_syslog", "grpc_dial_out", "mr", "system_manager"]
+ assert kwargs["managedBy"] in options, (
+ f'''"managedBy" cannot be "{kwargs["managedBy"]}", & must be set to one of: {options}'''
+ )
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/import"
+
+ body_params = [
+ "managedBy",
+ "contents",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationComputeApplicationDeploymentsBulkCreate(
+ self, organizationId: str, hosts: list, application: dict, enabled: bool, **kwargs
+ ):
+ """
+ **Add Application Deployment agents for a list of hosts. Only valid for hosts with access to Meraki Insight.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-compute-application-deployments-bulk-create
+
+ - organizationId (string): Organization ID
+ - hosts (array): List of hosts to deploy applications on
+ - application (object): Application information
+ - enabled (boolean): Whether the deployment should be enabled
+ - applicationConfiguration (object): Optional: Generic object for application-specific configuration
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/bulkCreate"
+
+ body_params = [
+ "hosts",
+ "application",
+ "enabled",
+ "applicationConfiguration",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "action",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationComputeApplicationDeployment(self, organizationId: str, deploymentId: str, enabled: bool, **kwargs):
+ """
+ **Update a Deployment agent configuration. Only valid for hosts with access to Meraki Insight.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-compute-application-deployment
+
+ - organizationId (string): Organization ID
+ - deploymentId (string): Deployment ID
+ - enabled (boolean): Whether or not the Application Deployment agent is enabled for the host.
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/{deploymentId}"
+
+ body_params = [
+ "enabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "action",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationComputeApplicationDeployment(self, organizationId: str, deploymentId: str):
+ """
+ **Delete a Application Deployment agent from the host. Only valid for host with access to Meraki Insight.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-compute-application-deployment
+
+ - organizationId (string): Organization ID
+ - deploymentId (string): Deployment ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/{deploymentId}"
+
+ action = {
+ "resource": resource,
+ "operation": "action",
+ }
+ return action
+
def createOrganizationConfigTemplate(self, organizationId: str, name: str, **kwargs):
"""
**Create a new configuration template**
@@ -585,7 +1044,7 @@ def createOrganizationConfigTemplate(self, organizationId: str, name: str, **kwa
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/configTemplates"
body_params = [
@@ -614,8 +1073,8 @@ def updateOrganizationConfigTemplate(self, organizationId: str, configTemplateId
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- configTemplateId = urllib.parse.quote(configTemplateId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
resource = f"/organizations/{organizationId}/configTemplates/{configTemplateId}"
body_params = [
@@ -645,7 +1104,7 @@ def createOrganizationDevicesCellularDataProfile(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/cellular/data/profiles"
body_params = [
@@ -672,7 +1131,7 @@ def batchOrganizationDevicesCellularDataProfilesAssignmentsCreate(self, organiza
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/cellular/data/profiles/assignments/batchCreate"
body_params = [
@@ -697,7 +1156,7 @@ def bulkOrganizationDevicesCellularDataProfilesAssignmentsDelete(self, organizat
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/cellular/data/profiles/assignments/bulkDelete"
action = {
@@ -719,8 +1178,8 @@ def updateOrganizationDevicesCellularDataProfile(self, organizationId: str, rule
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/organizations/{organizationId}/devices/cellular/data/profiles/{profileId}"
body_params = [
@@ -745,8 +1204,8 @@ def deleteOrganizationDevicesCellularDataProfile(self, organizationId: str, prof
- profileId (string): Profile ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/organizations/{organizationId}/devices/cellular/data/profiles/{profileId}"
action = {
@@ -773,7 +1232,7 @@ def createOrganizationDevicesControllerMigration(self, organizationId: str, seri
f'''"target" cannot be "{kwargs["target"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/controller/migrations"
body_params = [
@@ -800,7 +1259,7 @@ def bulkUpdateOrganizationDevicesDetails(self, organizationId: str, serials: lis
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/details/bulkUpdate"
body_params = [
@@ -826,7 +1285,7 @@ def bulkOrganizationDevicesPacketCaptureCapturesDelete(self, organizationId: str
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/packetCapture/captures/bulkDelete"
action = {
@@ -844,8 +1303,8 @@ def deleteOrganizationDevicesPacketCaptureCapture(self, organizationId: str, cap
- captureId (string): Capture ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- captureId = urllib.parse.quote(captureId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ captureId = urllib.parse.quote(str(captureId), safe="")
resource = f"/organizations/{organizationId}/devices/packetCapture/captures/{captureId}"
action = {
@@ -871,7 +1330,7 @@ def createOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, de
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/packetCapture/schedules"
body_params = [
@@ -891,6 +1350,26 @@ def createOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, de
}
return action
+ def bulkOrganizationDevicesPacketCaptureSchedulesDelete(self, organizationId: str, scheduleIds: list, **kwargs):
+ """
+ **Delete packet capture schedules**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-devices-packet-capture-schedules-delete
+
+ - organizationId (string): Organization ID
+ - scheduleIds (array): Delete the packet capture schedules of the specified schedule ids
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/bulkDelete"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def reorderOrganizationDevicesPacketCaptureSchedules(self, organizationId: str, order: list, **kwargs):
"""
**Bulk update priorities of pcap schedules**
@@ -902,7 +1381,7 @@ def reorderOrganizationDevicesPacketCaptureSchedules(self, organizationId: str,
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/reorder"
body_params = [
@@ -934,8 +1413,8 @@ def updateOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, sc
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- scheduleId = urllib.parse.quote(scheduleId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ scheduleId = urllib.parse.quote(str(scheduleId), safe="")
resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
body_params = [
@@ -950,55 +1429,279 @@ def updateOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, sc
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
"resource": resource,
- "operation": "update",
- "body": payload,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, scheduleId: str):
+ """
+ **Delete schedule from cloud**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-devices-packet-capture-schedule
+
+ - organizationId (string): Organization ID
+ - scheduleId (string): Delete the capture schedules of the specified capture schedule id
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ scheduleId = urllib.parse.quote(str(scheduleId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def tasksOrganizationDevicesPacketCapture(self, organizationId: str, packetId: str, task: str, **kwargs):
+ """
+ **Enqueues a task for a specific packet capture. This endpoint has a sustained rate limit of one request every 60 seconds.**
+ https://developer.cisco.com/meraki/api-v1/#!tasks-organization-devices-packet-capture
+
+ - organizationId (string): Organization ID
+ - packetId (string): Packet ID
+ - task (string): Type of task to enqueue. It can be one of: ["analysis", "reasoning", "summary", "highlights", "title", "flow"]
+ - networkId (string): Parameter to validate authorization by network access
+ """
+
+ kwargs.update(locals())
+
+ if "task" in kwargs:
+ options = ["analysis", "flow", "highlights", "reasoning", "summary", "title"]
+ assert kwargs["task"] in options, f'''"task" cannot be "{kwargs["task"]}", & must be set to one of: {options}'''
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ packetId = urllib.parse.quote(str(packetId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCaptures/{packetId}/tasks"
+
+ body_params = [
+ "networkId",
+ "task",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "enqueue_task",
+ "body": payload,
+ }
+ return action
+
+ def bulkOrganizationDevicesPlacementPositionsUpdate(self, organizationId: str, serials: list, **kwargs):
+ """
+ **Bulk update the attributes related to positions for provided devices**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-devices-placement-positions-update
+
+ - organizationId (string): Organization ID
+ - serials (array): List of device serials on a floor plan to update
+ - height (object): Height of the devices on the floor plan
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/placement/positions/bulkUpdate"
+
+ body_params = [
+ "serials",
+ "height",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "bulk_update",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationEarlyAccessFeaturesOptIn(self, organizationId: str, optInId: str, **kwargs):
+ """
+ **Update an early access feature opt-in for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-early-access-features-opt-in
+
+ - organizationId (string): Organization ID
+ - optInId (string): Opt in ID
+ - limitScopeToNetworks (array): A list of network IDs to apply the opt-in to
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ optInId = urllib.parse.quote(str(optInId), safe="")
+ resource = f"/organizations/{organizationId}/earlyAccess/features/optIns/{optInId}"
+
+ body_params = [
+ "limitScopeToNetworks",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationExtensionsSdwanmanagerInterconnect(
+ self, organizationId: str, interconnectId: str, name: str, status: str, **kwargs
+ ):
+ """
+ **Update name and status of an Interconnect**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-extensions-sdwanmanager-interconnect
+
+ - organizationId (string): Organization ID
+ - interconnectId (string): Interconnect ID
+ - name (string): Interconnect name
+ - status (string): Interconnect status
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ interconnectId = urllib.parse.quote(str(interconnectId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/sdwanmanager/interconnects/{interconnectId}"
+
+ body_params = [
+ "name",
+ "status",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, enabled: bool, networkId: str, **kwargs):
+ """
+ **Add a ThousandEyes agent for this network. Only valid for networks with access to Meraki Insight. Organization must have a ThousandEyes account connected to perform this action.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - enabled (boolean): Whether or not the ThousandEyes agent is enabled for the network.
+ - networkId (string): Network that will have the ThousandEyes agent installed on.
+ - tests (array): An array of tests to be created
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks"
+
+ body_params = [
+ "enabled",
+ "networkId",
+ "tests",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str, enabled: bool, **kwargs):
+ """
+ **Update a ThousandEyes agent from this network. Only valid for networks with access to Meraki Insight. Organization must have a ThousandEyes account connected to perform this action.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ - enabled (boolean): Whether or not the ThousandEyes agent is enabled for the network.
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ body_params = [
+ "enabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str):
+ """
+ **Delete a ThousandEyes agent from this network. Only valid for networks with access to Meraki Insight. Organization must have a ThousandEyes account connected to perform this action.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
}
return action
- def deleteOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, scheduleId: str):
+ def createOrganizationExtensionsThousandEyesTest(self, organizationId: str, **kwargs):
"""
- **Delete schedule from cloud**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-devices-packet-capture-schedule
+ **Create a ThousandEyes test based on a provided test template. Only valid for networks with access to Meraki Insight. Organization must have a ThousandEyes account connected to perform this action.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-extensions-thousand-eyes-test
- organizationId (string): Organization ID
- - scheduleId (string): Delete the capture schedules of the specified capture schedule id
+ - tests (array): An array of tests to be created
"""
- kwargs = locals()
+ kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- scheduleId = urllib.parse.quote(scheduleId, safe="")
- resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/tests"
+ body_params = [
+ "tests",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
"resource": resource,
- "operation": "destroy",
+ "operation": "create",
+ "body": payload,
}
return action
- def updateOrganizationEarlyAccessFeaturesOptIn(self, organizationId: str, optInId: str, **kwargs):
+ def resolveOrganizationIamAdminsAdministratorsMePermissions(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Update an early access feature opt-in for an organization**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-early-access-features-opt-in
+ **List the authenticated caller admin's permissions for an organization. Org-wide read and write admins receive a single organization-scoped permission item instead of per-network items. Scoped callers receive the network resources they can access in the requested organization, along with the effective allowed action for each resource.**
+ https://developer.cisco.com/meraki/api-v1/#!resolve-organization-iam-admins-administrators-me-permissions
- organizationId (string): Organization ID
- - optInId (string): Opt in ID
- - limitScopeToNetworks (array): A list of network IDs to apply the opt-in to
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- optInId = urllib.parse.quote(optInId, safe="")
- resource = f"/organizations/{organizationId}/earlyAccess/features/optIns/{optInId}"
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/admins/administrators/me/permissions/resolve"
body_params = [
- "limitScopeToNetworks",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
"resource": resource,
- "operation": "update",
+ "operation": "permissions/resolve",
"body": payload,
}
return action
@@ -1014,7 +1717,7 @@ def disableOrganizationIntegrationsXdrNetworks(self, organizationId: str, networ
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/integrations/xdr/networks/disable"
body_params = [
@@ -1039,7 +1742,7 @@ def enableOrganizationIntegrationsXdrNetworks(self, organizationId: str, network
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/integrations/xdr/networks/enable"
body_params = [
@@ -1065,7 +1768,7 @@ def claimOrganizationInventoryOrders(self, organizationId: str, claimId: str, **
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/inventory/orders/claim"
body_params = [
@@ -1093,7 +1796,7 @@ def assignOrganizationLicensesSeats(self, organizationId: str, licenseId: str, n
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/licenses/assignSeats"
body_params = [
@@ -1121,7 +1824,7 @@ def moveOrganizationLicenses(self, organizationId: str, destOrganizationId: str,
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/licenses/move"
body_params = [
@@ -1151,7 +1854,7 @@ def moveOrganizationLicensesSeats(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/licenses/moveSeats"
body_params = [
@@ -1179,7 +1882,7 @@ def renewOrganizationLicensesSeats(self, organizationId: str, licenseIdToRenew:
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/licenses/renewSeats"
body_params = [
@@ -1206,8 +1909,8 @@ def updateOrganizationLicense(self, organizationId: str, licenseId: str, **kwarg
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- licenseId = urllib.parse.quote(licenseId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ licenseId = urllib.parse.quote(str(licenseId), safe="")
resource = f"/organizations/{organizationId}/licenses/{licenseId}"
body_params = [
@@ -1246,7 +1949,7 @@ def updateOrganizationLoginSecurity(self, organizationId: str, **kwargs):
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/loginSecurity"
body_params = [
@@ -1286,11 +1989,12 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
- timeZone (string): The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
- copyFromNetworkId (string): The ID of the network to copy configuration from. Other provided parameters will override the copied configuration, except type which must match this network's type exactly.
- notes (string): Add any notes or additional information about this network here.
+ - details (array): An array of details
"""
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/networks"
body_params = [
@@ -1300,6 +2004,7 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
"timeZone",
"copyFromNetworkId",
"notes",
+ "details",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -1322,7 +2027,7 @@ def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/networks/combine"
body_params = [
@@ -1338,6 +2043,150 @@ def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds
}
return action
+ def createOrganizationNetworksGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a network group**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the network group
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups"
+
+ body_params = [
+ "name",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationNetworksGroup(self, organizationId: str, groupId: str, name: str, **kwargs):
+ """
+ **Update a network group**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - name (string): The new name of the network group
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}"
+
+ body_params = [
+ "name",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationNetworksGroup(self, organizationId: str, groupId: str):
+ """
+ **Delete a network group**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def bulkOrganizationNetworksGroupAssign(self, organizationId: str, groupId: str, networkIds: list, **kwargs):
+ """
+ **Add networks to a network group**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-networks-group-assign
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - networkIds (array): A list of network IDs to add to the network group
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}/bulkAssign"
+
+ body_params = [
+ "networkIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "bulk_assign",
+ "body": payload,
+ }
+ return action
+
+ def bulkOrganizationNetworksGroupUnassign(self, organizationId: str, groupId: str, networkIds: list, **kwargs):
+ """
+ **Remove networks from a network group**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-networks-group-unassign
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - networkIds (array): A list of network IDs to remove from the network group
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}/bulkUnassign"
+
+ body_params = [
+ "networkIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "bulk_unassign",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationOpenRoamingCertificate(self, organizationId: str, id: str):
+ """
+ **Delete an open roaming certificate.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-open-roaming-certificate
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/openRoaming/certificates/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def createOrganizationPoliciesGlobalFirewallRuleset(self, organizationId: str, name: str, **kwargs):
"""
**Create an Organization-Wide Policy Firewall Ruleset**
@@ -1350,7 +2199,7 @@ def createOrganizationPoliciesGlobalFirewallRuleset(self, organizationId: str, n
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/firewall/rulesets"
body_params = [
@@ -1391,7 +2240,7 @@ def createOrganizationPoliciesGlobalFirewallRulesetsRule(
f'''"policy" cannot be "{kwargs["policy"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/firewall/rulesets/rules"
body_params = [
@@ -1421,8 +2270,8 @@ def deleteOrganizationPoliciesGlobalFirewallRulesetsRule(self, organizationId: s
- ruleId (string): Rule ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- ruleId = urllib.parse.quote(ruleId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
resource = f"/organizations/{organizationId}/policies/global/firewall/rulesets/rules/{ruleId}"
action = {
@@ -1456,8 +2305,8 @@ def updateOrganizationPoliciesGlobalFirewallRulesetsRule(self, organizationId: s
f'''"policy" cannot be "{kwargs["policy"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
- ruleId = urllib.parse.quote(ruleId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
resource = f"/organizations/{organizationId}/policies/global/firewall/rulesets/rules/{ruleId}"
body_params = [
@@ -1491,8 +2340,8 @@ def updateOrganizationPoliciesGlobalFirewallRuleset(self, organizationId: str, r
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- rulesetId = urllib.parse.quote(rulesetId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ rulesetId = urllib.parse.quote(str(rulesetId), safe="")
resource = f"/organizations/{organizationId}/policies/global/firewall/rulesets/{rulesetId}"
body_params = [
@@ -1516,8 +2365,8 @@ def deleteOrganizationPoliciesGlobalFirewallRuleset(self, organizationId: str, r
- rulesetId (string): Ruleset ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- rulesetId = urllib.parse.quote(rulesetId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ rulesetId = urllib.parse.quote(str(rulesetId), safe="")
resource = f"/organizations/{organizationId}/policies/global/firewall/rulesets/{rulesetId}"
action = {
@@ -1538,7 +2387,7 @@ def createOrganizationPoliciesGlobalGroupPolicy(self, organizationId: str, name:
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies"
body_params = [
@@ -1567,7 +2416,7 @@ def assignOrganizationPoliciesGlobalGroupPoliciesAdaptivePolicyGroups(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/adaptivePolicyGroups/assign"
body_params = [
@@ -1596,7 +2445,7 @@ def removeOrganizationPoliciesGlobalGroupPoliciesAdaptivePolicyGroups(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/adaptivePolicyGroups/remove"
body_params = [
@@ -1622,17 +2471,19 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
- rulesetId (string): ID of the ruleset to assign
- policyId (string): ID of the policy to assign the ruleset to
- priority (integer): Priority of the ruleset assignment (lower numbers = higher priority)
+ - staged (boolean): Stage an assignment without applying it immediately to the policy
"""
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/firewall/rulesets/assignments"
body_params = [
"rulesetId",
"policyId",
"priority",
+ "staged",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -1642,6 +2493,33 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
}
return action
+ def commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
+ self, organizationId: str, policy: dict, **kwargs
+ ):
+ """
+ **Commit staged Organization-Wide Policy Ruleset Assignments**
+ https://developer.cisco.com/meraki/api-v1/#!commit-organization-policies-global-group-policies-firewall-rulesets-assignments
+
+ - organizationId (string): Organization ID
+ - policy (object): Policy in which all staged rulesets will be committed
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/policies/global/group/policies/firewall/rulesets/assignments/commit"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "commit",
+ "body": payload,
+ }
+ return action
+
def updateOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
self, organizationId: str, assignmentId: str, **kwargs
):
@@ -1658,8 +2536,8 @@ def updateOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- assignmentId = urllib.parse.quote(assignmentId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ assignmentId = urllib.parse.quote(str(assignmentId), safe="")
resource = (
f"/organizations/{organizationId}/policies/global/group/policies/firewall/rulesets/assignments/{assignmentId}"
)
@@ -1686,8 +2564,8 @@ def deleteOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(self
- assignmentId (string): Assignment ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- assignmentId = urllib.parse.quote(assignmentId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ assignmentId = urllib.parse.quote(str(assignmentId), safe="")
resource = (
f"/organizations/{organizationId}/policies/global/group/policies/firewall/rulesets/assignments/{assignmentId}"
)
@@ -1711,8 +2589,8 @@ def updateOrganizationPoliciesGlobalGroupPolicy(self, organizationId: str, polic
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- policyId = urllib.parse.quote(policyId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/{policyId}"
body_params = [
@@ -1736,8 +2614,8 @@ def deleteOrganizationPoliciesGlobalGroupPolicy(self, organizationId: str, polic
- policyId (string): Policy ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- policyId = urllib.parse.quote(policyId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
resource = f"/organizations/{organizationId}/policies/global/group/policies/{policyId}"
action = {
@@ -1768,7 +2646,7 @@ def createOrganizationPolicyObject(self, organizationId: str, name: str, categor
options = ["adaptivePolicyIpv4Cidr", "cidr", "fqdn"]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policyObjects"
body_params = [
@@ -1802,7 +2680,7 @@ def createOrganizationPolicyObjectsGroup(self, organizationId: str, name: str, *
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/policyObjects/groups"
body_params = [
@@ -1831,8 +2709,8 @@ def updateOrganizationPolicyObjectsGroup(self, organizationId: str, policyObject
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- policyObjectGroupId = urllib.parse.quote(policyObjectGroupId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyObjectGroupId = urllib.parse.quote(str(policyObjectGroupId), safe="")
resource = f"/organizations/{organizationId}/policyObjects/groups/{policyObjectGroupId}"
body_params = [
@@ -1856,8 +2734,8 @@ def deleteOrganizationPolicyObjectsGroup(self, organizationId: str, policyObject
- policyObjectGroupId (string): Policy object group ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- policyObjectGroupId = urllib.parse.quote(policyObjectGroupId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyObjectGroupId = urllib.parse.quote(str(policyObjectGroupId), safe="")
resource = f"/organizations/{organizationId}/policyObjects/groups/{policyObjectGroupId}"
action = {
@@ -1883,8 +2761,8 @@ def updateOrganizationPolicyObject(self, organizationId: str, policyObjectId: st
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- policyObjectId = urllib.parse.quote(policyObjectId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyObjectId = urllib.parse.quote(str(policyObjectId), safe="")
resource = f"/organizations/{organizationId}/policyObjects/{policyObjectId}"
body_params = [
@@ -1912,8 +2790,8 @@ def deleteOrganizationPolicyObject(self, organizationId: str, policyObjectId: st
- policyObjectId (string): Policy object ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- policyObjectId = urllib.parse.quote(policyObjectId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyObjectId = urllib.parse.quote(str(policyObjectId), safe="")
resource = f"/organizations/{organizationId}/policyObjects/{policyObjectId}"
action = {
@@ -1922,6 +2800,93 @@ def deleteOrganizationPolicyObject(self, organizationId: str, policyObjectId: st
}
return action
+ def createOrganizationRoutingVrf(self, organizationId: str, name: str, **kwargs):
+ """
+ **Add an organization-wide VRF (Virtual Routing and Forwarding)**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the VRF (Virtual Routing and Forwarding)
+ - description (string): Description of the VRF (Virtual Routing and Forwarding)
+ - routeDistinguisher (string): RD (Route Distinguisher) for the VRF (Virtual Routing and Forwarding)
+ - routeTarget (string): Route target are used to control the import and export of routes between VRFs
+ - appliance (object): This parameter is used to enable or disable the VRF on the WAN appliance
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs"
+
+ body_params = [
+ "name",
+ "description",
+ "routeDistinguisher",
+ "routeTarget",
+ "appliance",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationRoutingVrf(self, organizationId: str, vrfId: str, **kwargs):
+ """
+ **Update an organization-wide VRF (Virtual Routing and Forwarding)**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - vrfId (string): Vrf ID
+ - name (string): The name of the VRF (Virtual Routing and Forwarding)
+ - description (string): Description of the VRF (Virtual Routing and Forwarding)
+ - routeDistinguisher (string): RD (Route Distinguisher) for the VRF (Virtual Routing and Forwarding)
+ - routeTarget (string): Route target are used to control the import and export of routes between VRFs
+ - appliance (object): This parameter is used to enable or disable the VRF on the WAN appliance
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ vrfId = urllib.parse.quote(str(vrfId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/{vrfId}"
+
+ body_params = [
+ "name",
+ "description",
+ "routeDistinguisher",
+ "routeTarget",
+ "appliance",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationRoutingVrf(self, organizationId: str, vrfId: str):
+ """
+ **Delete a VRF (Virtual Routing and Forwarding) from a organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - vrfId (string): Vrf ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ vrfId = urllib.parse.quote(str(vrfId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/{vrfId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def createOrganizationSamlIdp(self, organizationId: str, x509certSha1Fingerprint: str, **kwargs):
"""
**Create a SAML IdP for your organization.**
@@ -1935,7 +2900,7 @@ def createOrganizationSamlIdp(self, organizationId: str, x509certSha1Fingerprint
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/saml/idps"
body_params = [
@@ -1965,8 +2930,8 @@ def updateOrganizationSamlIdp(self, organizationId: str, idpId: str, **kwargs):
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- idpId = urllib.parse.quote(idpId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
resource = f"/organizations/{organizationId}/saml/idps/{idpId}"
body_params = [
@@ -1991,8 +2956,8 @@ def deleteOrganizationSamlIdp(self, organizationId: str, idpId: str):
- idpId (string): Idp ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- idpId = urllib.parse.quote(idpId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
resource = f"/organizations/{organizationId}/saml/idps/{idpId}"
action = {
@@ -2012,7 +2977,7 @@ def batchOrganizationSaseConnectorsDelete(self, organizationId: str, **kwargs):
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/sase/connectors/batchDelete"
body_params = [
@@ -2037,7 +3002,7 @@ def createOrganizationSaseIntegration(self, organizationId: str, api: dict, **kw
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/sase/integrations"
body_params = [
@@ -2060,8 +3025,8 @@ def deleteOrganizationSaseIntegration(self, organizationId: str, integrationId:
- integrationId (string): Integration ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- integrationId = urllib.parse.quote(integrationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ integrationId = urllib.parse.quote(str(integrationId), safe="")
resource = f"/organizations/{organizationId}/sase/integrations/{integrationId}"
action = {
@@ -2070,7 +3035,7 @@ def deleteOrganizationSaseIntegration(self, organizationId: str, integrationId:
}
return action
- def attachOrganizationSaseSites(self, organizationId: str, **kwargs):
+ def attachOrganizationSaseSites(self, organizationId: str, items: list, **kwargs):
"""
**Attach sites in this organization to Secure Access. For an organization, a maximum of 2500 sites can be attached if they are in spoke mode or a maximum of 10 sites can be attached in hub mode.**
https://developer.cisco.com/meraki/api-v1/#!attach-organization-sase-sites
@@ -2079,9 +3044,9 @@ def attachOrganizationSaseSites(self, organizationId: str, **kwargs):
- items (array): List of Meraki SD-WAN sites with the associated regions to be attached.
"""
- kwargs.update(locals())
+ kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/sase/sites/attach"
body_params = [
@@ -2106,7 +3071,7 @@ def detachOrganizationSaseSites(self, organizationId: str, **kwargs):
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/sase/sites/detach"
action = {
@@ -2127,8 +3092,8 @@ def updateOrganizationSaseSite(self, organizationId: str, siteId: str, **kwargs)
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- siteId = urllib.parse.quote(siteId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ siteId = urllib.parse.quote(str(siteId), safe="")
resource = f"/organizations/{organizationId}/sase/sites/{siteId}"
body_params = [
@@ -2171,7 +3136,7 @@ def updateOrganizationSnmp(self, organizationId: str, **kwargs):
f'''"v3PrivMode" cannot be "{kwargs["v3PrivMode"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/snmp"
body_params = [
@@ -2200,8 +3165,8 @@ def deleteOrganizationSplashAsset(self, organizationId: str, id: str):
- id (string): ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/splash/assets/{id}"
action = {
@@ -2222,7 +3187,7 @@ def createOrganizationSplashTheme(self, organizationId: str, **kwargs):
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/splash/themes"
body_params = [
@@ -2246,8 +3211,8 @@ def deleteOrganizationSplashTheme(self, organizationId: str, id: str):
- id (string): ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/splash/themes/{id}"
action = {
@@ -2269,8 +3234,8 @@ def createOrganizationSplashThemeAsset(self, organizationId: str, themeIdentifie
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- themeIdentifier = urllib.parse.quote(themeIdentifier, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ themeIdentifier = urllib.parse.quote(str(themeIdentifier), safe="")
resource = f"/organizations/{organizationId}/splash/themes/{themeIdentifier}/assets"
body_params = [
@@ -2284,3 +3249,94 @@ def createOrganizationSplashThemeAsset(self, organizationId: str, themeIdentifie
"body": payload,
}
return action
+
+ def createOrganizationWebhooksPayloadTemplate(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the new template
+ - body (string): The liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
+ - headers (array): The liquid template used with the webhook headers.
+ - bodyFile (string): A file containing liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
+ - headersFile (string): A file containing the liquid template used with the webhook headers.
+ - sharing (object): Information on which entities have access to the template
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates"
+
+ body_params = [
+ "name",
+ "body",
+ "headers",
+ "bodyFile",
+ "headersFile",
+ "sharing",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str):
+ """
+ **Destroy a webhook payload template for an organization. Does not work for included templates ('wpt_00001', 'wpt_00002', 'wpt_00003', 'wpt_00004', 'wpt_00005', 'wpt_00006', 'wpt_00007' or 'wpt_00008')**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str, **kwargs):
+ """
+ **Update a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ - name (string): The name of the template
+ - body (string): The liquid template used for the body of the webhook message.
+ - headers (array): The liquid template used with the webhook headers.
+ - bodyFile (string): A file containing liquid template used for the body of the webhook message.
+ - headersFile (string): A file containing the liquid template used with the webhook headers.
+ - sharing (object): Information on which entities have access to the template
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ body_params = [
+ "name",
+ "body",
+ "headers",
+ "bodyFile",
+ "headersFile",
+ "sharing",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
diff --git a/meraki/api/batch/secureConnect.py b/meraki/api/batch/secureConnect.py
new file mode 100644
index 00000000..20a5f645
--- /dev/null
+++ b/meraki/api/batch/secureConnect.py
@@ -0,0 +1,224 @@
+import urllib
+
+
+class ActionBatchSecureConnect(object):
+ def __init__(self):
+ super(ActionBatchSecureConnect, self).__init__()
+
+ def createOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Adds a new private resource group to an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - name (string): Name of group. This is required and should be unique across all groups for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - description (string): Optional text description for a group.
+ - resourceIds (array): List of resource ids assigned to this group.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups"
+
+ body_params = [
+ "name",
+ "description",
+ "resourceIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, id: str, name: str, **kwargs):
+ """
+ **Updates a specific private resource group.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of group. This is required and should be unique across all groups for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - description (string): Optional text description for a group.
+ - resourceIds (array): List of resource ids assigned to this group.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "resourceIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, id: str):
+ """
+ **Deletes a specific private resource group.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationSecureConnectPrivateResource(
+ self, organizationId: str, name: str, accessTypes: list, resourceAddresses: list, **kwargs
+ ):
+ """
+ **Adds a new private resource to the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - name (string): Name of resource. This is required and should be unique across all resources for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - accessTypes (array): List of access types.
+ - resourceAddresses (array): List of resource addresses Protocols must be unique in this list.
+ - description (string): Optional text description for a resource.
+ - resourceGroupIds (array): List of resource group ids attached to this resource.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources"
+
+ body_params = [
+ "name",
+ "description",
+ "accessTypes",
+ "resourceAddresses",
+ "resourceGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationSecureConnectPrivateResource(
+ self, organizationId: str, id: str, name: str, accessTypes: list, resourceAddresses: list, **kwargs
+ ):
+ """
+ **Updates a specific private resource.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of resource. This is required and should be unique across all resources for a given organization.Name cannot have any special characters other than spaces and hyphens.
+ - accessTypes (array): List of access types.
+ - resourceAddresses (array): List of resource addresses Protocols must be unique in this list.
+ - description (string): Optional text description for resource.
+ - resourceGroupIds (array): List of resource group ids attached to this resource.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "accessTypes",
+ "resourceAddresses",
+ "resourceGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSecureConnectPrivateResource(self, organizationId: str, id: str):
+ """
+ **Deletes a specific private resource. If this is the last resource in a resource group you must remove it from that resource group before deleting.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationSecureConnectSite(self, organizationId: str, **kwargs):
+ """
+ **Enroll sites in this organization to Secure Connect. For an organization, a maximum of 4000 sites can be enrolled if they are in spoke mode or a maximum of 10 sites can be enrolled in hub mode.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-site
+
+ - organizationId (string): Organization ID
+ - enrollments (array): List of Meraki SD-WAN sites with the associated regions to be enrolled.
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ body_params = [
+ "enrollments",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSecureConnectSites(self, organizationId: str, **kwargs):
+ """
+ **Detach given sites from Secure Connect**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-sites
+
+ - organizationId (string): Organization ID
+ - sites (array): List of site IDs to detach
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
diff --git a/meraki/api/batch/sensor.py b/meraki/api/batch/sensor.py
index 777ea1c2..567ac668 100644
--- a/meraki/api/batch/sensor.py
+++ b/meraki/api/batch/sensor.py
@@ -12,9 +12,10 @@ def createDeviceSensorCommand(self, serial: str, operation: str, **kwargs):
- serial (string): Serial
- operation (string): Operation to run on the sensor. 'enableDownstreamPower', 'disableDownstreamPower', and 'cycleDownstreamPower' turn power on/off to the device that is connected downstream of an MT40 power monitor. 'refreshData' causes an MT15 or MT40 device to upload its latest readings so that they are immediately available in the Dashboard API.
+ - arguments (array): Additional options to provide to commands run on the sensor, each with a corresponding 'name' and 'value'.
"""
- kwargs = locals()
+ kwargs.update(locals())
if "operation" in kwargs:
options = ["cycleDownstreamPower", "disableDownstreamPower", "enableDownstreamPower", "refreshData"]
@@ -22,10 +23,11 @@ def createDeviceSensorCommand(self, serial: str, operation: str, **kwargs):
f'''"operation" cannot be "{kwargs["operation"]}", & must be set to one of: {options}'''
)
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/sensor/commands"
body_params = [
+ "arguments",
"operation",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -47,7 +49,7 @@ def updateDeviceSensorRelationships(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/sensor/relationships"
body_params = [
@@ -78,7 +80,7 @@ def createNetworkSensorAlertsProfile(self, networkId: str, name: str, conditions
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/sensor/alerts/profiles"
body_params = [
@@ -116,8 +118,8 @@ def updateNetworkSensorAlertsProfile(self, networkId: str, id: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- id = urllib.parse.quote(id, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/networks/{networkId}/sensor/alerts/profiles/{id}"
body_params = [
@@ -146,8 +148,8 @@ def deleteNetworkSensorAlertsProfile(self, networkId: str, id: str):
- id (string): ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- id = urllib.parse.quote(id, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/networks/{networkId}/sensor/alerts/profiles/{id}"
action = {
@@ -168,8 +170,8 @@ def updateNetworkSensorMqttBroker(self, networkId: str, mqttBrokerId: str, enabl
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
- mqttBrokerId = urllib.parse.quote(mqttBrokerId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ mqttBrokerId = urllib.parse.quote(str(mqttBrokerId), safe="")
resource = f"/networks/{networkId}/sensor/mqttBrokers/{mqttBrokerId}"
body_params = [
diff --git a/meraki/api/batch/sm.py b/meraki/api/batch/sm.py
index fab4bc90..a3a15496 100644
--- a/meraki/api/batch/sm.py
+++ b/meraki/api/batch/sm.py
@@ -5,6 +5,166 @@ class ActionBatchSm(object):
def __init__(self):
super(ActionBatchSm, self).__init__()
+ def createNetworkSmScript(self, networkId: str, name: str, platform: str, **kwargs):
+ """
+ **Create a new script**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-script
+
+ - networkId (string): Network ID
+ - name (string): Unique name to identify this script.
+ - platform (string): Platform that this script will run on.
+ - scope (string): The target scope of the script. (Either scope or targetGroupId must be present.)
+ - tags (array): The target tags of the script as an array of strings. Required if scope is one of withAny, withoutAny, withAll, withoutAll.
+ - targetGroupId (string): The tag target group ID that should be used to scope devices. Either scope or targetGroupId must be present.
+ - description (string): Description of this script.
+ - runAsUsername (string): Username that script should run as.
+ - externalSource (object): Properties for a script provided by a url instead of an upload
+ - upload (object): Properties for a script provided as an upload instead of a url
+ - schedule (object): When the script is intended to run
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs and kwargs["platform"] is not None:
+ options = ["Windows", "macOS"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+ if "scope" in kwargs:
+ options = ["all", "none", "withAll", "withAny", "withoutAll", "withoutAny"]
+ assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts"
+
+ body_params = [
+ "name",
+ "platform",
+ "scope",
+ "tags",
+ "targetGroupId",
+ "description",
+ "runAsUsername",
+ "externalSource",
+ "upload",
+ "schedule",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def createNetworkSmScriptsJob(self, networkId: str, scriptId: str, **kwargs):
+ """
+ **Create a job that will run a script on a set of devices**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-scripts-job
+
+ - networkId (string): Network ID
+ - scriptId (string): ID of script that should be run on the matching devices
+ - deviceIds (array): List of device IDs to run that should run this script
+ - deviceFilter (string): Create job on all devices in-scope or devices that have failed to run this script
+ """
+
+ kwargs.update(locals())
+
+ if "deviceFilter" in kwargs:
+ options = ["All", "Failed"]
+ assert kwargs["deviceFilter"] in options, (
+ f'''"deviceFilter" cannot be "{kwargs["deviceFilter"]}", & must be set to one of: {options}'''
+ )
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs"
+
+ body_params = [
+ "scriptId",
+ "deviceIds",
+ "deviceFilter",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkSmScript(self, networkId: str, scriptId: str, **kwargs):
+ """
+ **Update an existing script**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ - name (string): Unique name to identify this script.
+ - platform (string): Platform that this script will run on.
+ - scope (string): The target scope of the script. (Either scope or targetGroupId must be present.)
+ - tags (array): The target tags of the script as an array of strings. Required if scope is one of withAny, withoutAny, withAll, withoutAll.
+ - targetGroupId (string): The tag target group ID that should be used to scope devices. Either scope or targetGroupId must be present.
+ - description (string): Description of this script.
+ - runAsUsername (string): Username that script should run as.
+ - externalSource (object): Properties for a script provided by a url instead of an upload
+ - upload (object): Properties for a script provided as an upload instead of a url
+ - schedule (object): When the script is intended to run
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs and kwargs["platform"] is not None:
+ options = ["Windows", "macOS"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+ if "scope" in kwargs:
+ options = ["all", "none", "withAll", "withAny", "withoutAll", "withoutAny"]
+ assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ body_params = [
+ "name",
+ "platform",
+ "scope",
+ "tags",
+ "targetGroupId",
+ "description",
+ "runAsUsername",
+ "externalSource",
+ "upload",
+ "schedule",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteNetworkSmScript(self, networkId: str, scriptId: str):
+ """
+ **Delete a script**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def deleteNetworkSmUserAccessDevice(self, networkId: str, userAccessDeviceId: str):
"""
**Delete a User Access Device**
@@ -14,8 +174,8 @@ def deleteNetworkSmUserAccessDevice(self, networkId: str, userAccessDeviceId: st
- userAccessDeviceId (string): User access device ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- userAccessDeviceId = urllib.parse.quote(userAccessDeviceId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ userAccessDeviceId = urllib.parse.quote(str(userAccessDeviceId), safe="")
resource = f"/networks/{networkId}/sm/userAccessDevices/{userAccessDeviceId}"
action = {
@@ -41,7 +201,7 @@ def createOrganizationSmAdminsRole(self, organizationId: str, name: str, **kwarg
options = ["all_tags", "some", "without_all_tags", "without_some"]
assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/sm/admins/roles"
body_params = [
@@ -75,8 +235,8 @@ def updateOrganizationSmAdminsRole(self, organizationId: str, roleId: str, **kwa
options = ["all_tags", "some", "without_all_tags", "without_some"]
assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
- organizationId = urllib.parse.quote(organizationId, safe="")
- roleId = urllib.parse.quote(roleId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ roleId = urllib.parse.quote(str(roleId), safe="")
resource = f"/organizations/{organizationId}/sm/admins/roles/{roleId}"
body_params = [
@@ -101,8 +261,8 @@ def deleteOrganizationSmAdminsRole(self, organizationId: str, roleId: str):
- roleId (string): Role ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- roleId = urllib.parse.quote(roleId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ roleId = urllib.parse.quote(str(roleId), safe="")
resource = f"/organizations/{organizationId}/sm/admins/roles/{roleId}"
action = {
@@ -111,6 +271,108 @@ def deleteOrganizationSmAdminsRole(self, organizationId: str, roleId: str):
}
return action
+ def createOrganizationSmAppleCloudEnrollmentSyncJob(self, organizationId: str, **kwargs):
+ """
+ **Enqueue a sync job for an ADE account**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-sm-apple-cloud-enrollment-sync-job
+
+ - organizationId (string): Organization ID
+ - adeAccountId (string): ADE Account ID
+ - fullSync (boolean): Whether or not job is full sync (defaults to full sync)
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/apple/cloudEnrollment/syncJobs"
+
+ body_params = [
+ "adeAccountId",
+ "fullSync",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationSmBulkEnrollmentToken(self, organizationId: str, networkId: str, expiresAt: str, **kwargs):
+ """
+ **Create a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - networkId (string): The id of the associated node_group.
+ - expiresAt (string): The expiration date.
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token"
+
+ body_params = [
+ "networkId",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str, **kwargs):
+ """
+ **Update a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ - networkId (string): The id of the associated node_group.
+ - expiresAt (string): The expiration date.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ body_params = [
+ "networkId",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str):
+ """
+ **Delete a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def updateOrganizationSmSentryPoliciesAssignments(self, organizationId: str, items: list, **kwargs):
"""
**Update an Organizations Sentry Policies using the provided list. Sentry Policies are ordered in descending order of priority (i.e. highest priority at the bottom, this is opposite the Dashboard UI). Policies not present in the request will be deleted.**
@@ -122,7 +384,7 @@ def updateOrganizationSmSentryPoliciesAssignments(self, organizationId: str, ite
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/sm/sentry/policies/assignments"
body_params = [
diff --git a/meraki/api/batch/spaces.py b/meraki/api/batch/spaces.py
index 990bdcaa..66623f39 100644
--- a/meraki/api/batch/spaces.py
+++ b/meraki/api/batch/spaces.py
@@ -13,7 +13,7 @@ def removeOrganizationSpacesIntegration(self, organizationId: str):
- organizationId (string): Organization ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/spaces/integration/remove"
action = {
diff --git a/meraki/api/batch/support.py b/meraki/api/batch/support.py
new file mode 100644
index 00000000..e884c292
--- /dev/null
+++ b/meraki/api/batch/support.py
@@ -0,0 +1,3 @@
+class ActionBatchSupport(object):
+ def __init__(self):
+ super(ActionBatchSupport, self).__init__()
diff --git a/meraki/api/batch/switch.py b/meraki/api/batch/switch.py
index 092b9a51..b7b81635 100644
--- a/meraki/api/batch/switch.py
+++ b/meraki/api/batch/switch.py
@@ -16,7 +16,7 @@ def cycleDeviceSwitchPorts(self, serial: str, ports: list, **kwargs):
kwargs = locals()
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/switch/ports/cycle"
body_params = [
@@ -30,6 +30,40 @@ def cycleDeviceSwitchPorts(self, serial: str, ports: list, **kwargs):
}
return action
+ def updateDeviceSwitchPortsMirror(self, serial: str, source: dict, destination: dict, **kwargs):
+ """
+ **Update a port mirror**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-switch-ports-mirror
+
+ - serial (string): The switch identifier
+ - source (object): Source ports mirror configuration
+ - destination (object): Destination port mirror configuration
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/switch/ports/mirror"
+
+ body_params = [
+ "serial",
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "mirrors/update",
+ "body": payload,
+ }
+ return action
+
def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
"""
**Update a switch port**
@@ -45,6 +79,7 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
- vlan (integer): The VLAN of the switch port. For a trunk port, this is the native VLAN. A null value will clear the value set for trunk ports.
- voiceVlan (integer): The voice VLAN of the switch port. Only applicable to access ports.
- allowedVlans (string): The VLANs allowed on the switch port. Only applicable to trunk ports.
+ - activeVlans (string): The VLANs that are active on the switch port. Only applicable to trunk ports.
- isolationEnabled (boolean): The isolation status of the switch port.
- rstpEnabled (boolean): The rapid spanning tree protocol status.
- stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard').
@@ -88,8 +123,8 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
f'''"accessPolicyType" cannot be "{kwargs["accessPolicyType"]}", & must be set to one of: {options}'''
)
- serial = urllib.parse.quote(serial, safe="")
- portId = urllib.parse.quote(portId, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
+ portId = urllib.parse.quote(str(portId), safe="")
resource = f"/devices/{serial}/switch/ports/{portId}"
body_params = [
@@ -101,6 +136,7 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
"vlan",
"voiceVlan",
"allowedVlans",
+ "activeVlans",
"isolationEnabled",
"rstpEnabled",
"stpGuard",
@@ -146,6 +182,12 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -163,7 +205,7 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
f'''"multicastRouting" cannot be "{kwargs["multicastRouting"]}", & must be set to one of: {options}'''
)
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/switch/routing/interfaces"
body_params = [
@@ -176,6 +218,12 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -204,6 +252,12 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -218,8 +272,8 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
f'''"multicastRouting" cannot be "{kwargs["multicastRouting"]}", & must be set to one of: {options}'''
)
- serial = urllib.parse.quote(serial, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/devices/{serial}/switch/routing/interfaces/{interfaceId}"
body_params = [
@@ -231,6 +285,12 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -253,8 +313,8 @@ def deleteDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str):
- interfaceId (string): Interface ID
"""
- serial = urllib.parse.quote(serial, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/devices/{serial}/switch/routing/interfaces/{interfaceId}"
action = {
@@ -306,8 +366,8 @@ def updateDeviceSwitchRoutingInterfaceDhcp(self, serial: str, interfaceId: str,
f'''"dnsNameserversOption" cannot be "{kwargs["dnsNameserversOption"]}", & must be set to one of: {options}'''
)
- serial = urllib.parse.quote(serial, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/devices/{serial}/switch/routing/interfaces/{interfaceId}/dhcp"
body_params = [
@@ -347,7 +407,7 @@ def createDeviceSwitchRoutingStaticRoute(self, serial: str, subnet: str, nextHop
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/switch/routing/staticRoutes"
body_params = [
@@ -384,8 +444,8 @@ def updateDeviceSwitchRoutingStaticRoute(self, serial: str, staticRouteId: str,
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
- staticRouteId = urllib.parse.quote(staticRouteId, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
+ staticRouteId = urllib.parse.quote(str(staticRouteId), safe="")
resource = f"/devices/{serial}/switch/routing/staticRoutes/{staticRouteId}"
body_params = [
@@ -414,8 +474,8 @@ def deleteDeviceSwitchRoutingStaticRoute(self, serial: str, staticRouteId: str):
- staticRouteId (string): Static route ID
"""
- serial = urllib.parse.quote(serial, safe="")
- staticRouteId = urllib.parse.quote(staticRouteId, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
+ staticRouteId = urllib.parse.quote(str(staticRouteId), safe="")
resource = f"/devices/{serial}/switch/routing/staticRoutes/{staticRouteId}"
action = {
@@ -436,7 +496,7 @@ def updateDeviceSwitchWarmSpare(self, serial: str, enabled: bool, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/switch/warmSpare"
body_params = [
@@ -493,7 +553,7 @@ def createNetworkSwitchAccessPolicy(
f'''"accessPolicyType" cannot be "{kwargs["accessPolicyType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/accessPolicies"
body_params = [
@@ -566,8 +626,8 @@ def updateNetworkSwitchAccessPolicy(self, networkId: str, accessPolicyNumber: st
f'''"accessPolicyType" cannot be "{kwargs["accessPolicyType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- accessPolicyNumber = urllib.parse.quote(accessPolicyNumber, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ accessPolicyNumber = urllib.parse.quote(str(accessPolicyNumber), safe="")
resource = f"/networks/{networkId}/switch/accessPolicies/{accessPolicyNumber}"
body_params = [
@@ -608,8 +668,8 @@ def deleteNetworkSwitchAccessPolicy(self, networkId: str, accessPolicyNumber: st
- accessPolicyNumber (string): Access policy number
"""
- networkId = urllib.parse.quote(networkId, safe="")
- accessPolicyNumber = urllib.parse.quote(accessPolicyNumber, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ accessPolicyNumber = urllib.parse.quote(str(accessPolicyNumber), safe="")
resource = f"/networks/{networkId}/switch/accessPolicies/{accessPolicyNumber}"
action = {
@@ -632,7 +692,7 @@ def updateNetworkSwitchAlternateManagementInterface(self, networkId: str, **kwar
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/alternateManagementInterface"
body_params = [
@@ -670,7 +730,7 @@ def updateNetworkSwitchDhcpServerPolicy(self, networkId: str, **kwargs):
f'''"defaultPolicy" cannot be "{kwargs["defaultPolicy"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/dhcpServerPolicy"
body_params = [
@@ -703,7 +763,7 @@ def createNetworkSwitchDhcpServerPolicyArpInspectionTrustedServer(
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/dhcpServerPolicy/arpInspection/trustedServers"
body_params = [
@@ -733,8 +793,8 @@ def updateNetworkSwitchDhcpServerPolicyArpInspectionTrustedServer(self, networkI
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- trustedServerId = urllib.parse.quote(trustedServerId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ trustedServerId = urllib.parse.quote(str(trustedServerId), safe="")
resource = f"/networks/{networkId}/switch/dhcpServerPolicy/arpInspection/trustedServers/{trustedServerId}"
body_params = [
@@ -759,8 +819,8 @@ def deleteNetworkSwitchDhcpServerPolicyArpInspectionTrustedServer(self, networkI
- trustedServerId (string): Trusted server ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- trustedServerId = urllib.parse.quote(trustedServerId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ trustedServerId = urllib.parse.quote(str(trustedServerId), safe="")
resource = f"/networks/{networkId}/switch/dhcpServerPolicy/arpInspection/trustedServers/{trustedServerId}"
action = {
@@ -780,7 +840,7 @@ def updateNetworkSwitchDscpToCosMappings(self, networkId: str, mappings: list, *
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/dscpToCosMappings"
body_params = [
@@ -802,16 +862,18 @@ def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
- networkId (string): Network ID
- switchPorts (array): Array of switch or stack ports for creating aggregation group. Minimum 2 and maximum 8 ports are supported.
- switchProfilePorts (array): Array of switch profile ports for creating aggregation group. Minimum 2 and maximum 8 ports are supported.
+ - esiMhPairId (string): ESI-MH pair ID. Required when creating a downstream aggregation across ESI-MH pair member switches.
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/linkAggregations"
body_params = [
"switchPorts",
"switchProfilePorts",
+ "esiMhPairId",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -834,8 +896,8 @@ def updateNetworkSwitchLinkAggregation(self, networkId: str, linkAggregationId:
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- linkAggregationId = urllib.parse.quote(linkAggregationId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ linkAggregationId = urllib.parse.quote(str(linkAggregationId), safe="")
resource = f"/networks/{networkId}/switch/linkAggregations/{linkAggregationId}"
body_params = [
@@ -859,8 +921,8 @@ def deleteNetworkSwitchLinkAggregation(self, networkId: str, linkAggregationId:
- linkAggregationId (string): Link aggregation ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- linkAggregationId = urllib.parse.quote(linkAggregationId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ linkAggregationId = urllib.parse.quote(str(linkAggregationId), safe="")
resource = f"/networks/{networkId}/switch/linkAggregations/{linkAggregationId}"
action = {
@@ -881,7 +943,7 @@ def updateNetworkSwitchMtu(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/mtu"
body_params = [
@@ -912,8 +974,8 @@ def updateNetworkSwitchPortSchedule(self, networkId: str, portScheduleId: str, *
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- portScheduleId = urllib.parse.quote(portScheduleId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ portScheduleId = urllib.parse.quote(str(portScheduleId), safe="")
resource = f"/networks/{networkId}/switch/portSchedules/{portScheduleId}"
body_params = [
@@ -928,6 +990,97 @@ def updateNetworkSwitchPortSchedule(self, networkId: str, portScheduleId: str, *
}
return action
+ def createNetworkSwitchPortsProfile(self, networkId: str, **kwargs):
+ """
+ **Create a port profile in a network**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles"
+
+ body_params = [
+ "name",
+ "description",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "profiles/create",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkSwitchPortsProfile(self, networkId: str, id: str, **kwargs):
+ """
+ **Update a port profile in a network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - id (string): ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "profiles/update",
+ "body": payload,
+ }
+ return action
+
+ def deleteNetworkSwitchPortsProfile(self, networkId: str, id: str):
+ """
+ **Delete a port profile from a network**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - id (string): ID
+ """
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "profiles/destroy",
+ }
+ return action
+
def createNetworkSwitchQosRule(self, networkId: str, vlan: int, **kwargs):
"""
**Add a quality of service rule**
@@ -951,7 +1104,7 @@ def createNetworkSwitchQosRule(self, networkId: str, vlan: int, **kwargs):
f'''"protocol" cannot be "{kwargs["protocol"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/qosRules"
body_params = [
@@ -982,7 +1135,7 @@ def updateNetworkSwitchQosRulesOrder(self, networkId: str, ruleIds: list, **kwar
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/qosRules/order"
body_params = [
@@ -1005,8 +1158,8 @@ def deleteNetworkSwitchQosRule(self, networkId: str, qosRuleId: str):
- qosRuleId (string): Qos rule ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- qosRuleId = urllib.parse.quote(qosRuleId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ qosRuleId = urllib.parse.quote(str(qosRuleId), safe="")
resource = f"/networks/{networkId}/switch/qosRules/{qosRuleId}"
action = {
@@ -1039,8 +1192,8 @@ def updateNetworkSwitchQosRule(self, networkId: str, qosRuleId: str, **kwargs):
f'''"protocol" cannot be "{kwargs["protocol"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- qosRuleId = urllib.parse.quote(qosRuleId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ qosRuleId = urllib.parse.quote(str(qosRuleId), safe="")
resource = f"/networks/{networkId}/switch/qosRules/{qosRuleId}"
body_params = [
@@ -1072,7 +1225,7 @@ def updateNetworkSwitchRoutingMulticast(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/routing/multicast"
body_params = [
@@ -1102,7 +1255,7 @@ def createNetworkSwitchRoutingMulticastRendezvousPoint(
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/routing/multicast/rendezvousPoints"
body_params = [
@@ -1127,8 +1280,8 @@ def deleteNetworkSwitchRoutingMulticastRendezvousPoint(self, networkId: str, ren
- rendezvousPointId (string): Rendezvous point ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- rendezvousPointId = urllib.parse.quote(rendezvousPointId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ rendezvousPointId = urllib.parse.quote(str(rendezvousPointId), safe="")
resource = f"/networks/{networkId}/switch/routing/multicast/rendezvousPoints/{rendezvousPointId}"
action = {
@@ -1153,8 +1306,8 @@ def updateNetworkSwitchRoutingMulticastRendezvousPoint(
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- rendezvousPointId = urllib.parse.quote(rendezvousPointId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ rendezvousPointId = urllib.parse.quote(str(rendezvousPointId), safe="")
resource = f"/networks/{networkId}/switch/routing/multicast/rendezvousPoints/{rendezvousPointId}"
body_params = [
@@ -1188,7 +1341,7 @@ def updateNetworkSwitchRoutingOspf(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/routing/ospf"
body_params = [
@@ -1225,7 +1378,7 @@ def updateNetworkSwitchSettings(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/settings"
body_params = [
@@ -1245,6 +1398,39 @@ def updateNetworkSwitchSettings(self, networkId: str, **kwargs):
}
return action
+ def updateNetworkSwitchSpanningTree(self, networkId: str, **kwargs):
+ """
+ **Updates Spanning Tree configuration**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-spanning-tree
+
+ - networkId (string): Network ID
+ - enabled (boolean): Network-level spanning Tree enable
+ - mode (string): Catalyst Spanning Tree Protocol mode (mst, rpvst+)
+ - priorities (array): Spanning tree priority for switches/stacks or switch templates. An empty array will clear the priority settings.
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["mst", "rpvst+"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/spanningTree"
+
+ body_params = [
+ "enabled",
+ "mode",
+ "priorities",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def updateNetworkSwitchStack(self, networkId: str, switchStackId: str, **kwargs):
"""
**Update a switch stack. At least one of 'name' or 'members' must be provided. If 'members' is provided, it replaces the entire stack membership.**
@@ -1258,8 +1444,8 @@ def updateNetworkSwitchStack(self, networkId: str, switchStackId: str, **kwargs)
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}"
body_params = [
@@ -1274,6 +1460,43 @@ def updateNetworkSwitchStack(self, networkId: str, switchStackId: str, **kwargs)
}
return action
+ def updateNetworkSwitchStackPortsMirror(
+ self, networkId: str, switchStackId: str, source: dict, destination: dict, **kwargs
+ ):
+ """
+ **Update switch port mirrors for switch stacks**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-stack-ports-mirror
+
+ - networkId (string): Network ID
+ - switchStackId (string): Switch stack ID
+ - source (object): Source port details
+ - destination (object): Destination port Details
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/ports/mirror"
+
+ body_params = [
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId: str, name: str, **kwargs):
"""
**Create a layer 3 interface for a switch stack**
@@ -1290,6 +1513,12 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -1307,8 +1536,8 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
f'''"multicastRouting" cannot be "{kwargs["multicastRouting"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/interfaces"
body_params = [
@@ -1321,6 +1550,12 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -1350,6 +1585,12 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -1364,9 +1605,9 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
f'''"multicastRouting" cannot be "{kwargs["multicastRouting"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/interfaces/{interfaceId}"
body_params = [
@@ -1378,6 +1619,12 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -1401,9 +1648,9 @@ def deleteNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- interfaceId (string): Interface ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/interfaces/{interfaceId}"
action = {
@@ -1457,9 +1704,9 @@ def updateNetworkSwitchStackRoutingInterfaceDhcp(self, networkId: str, switchSta
f'''"dnsNameserversOption" cannot be "{kwargs["dnsNameserversOption"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
- interfaceId = urllib.parse.quote(interfaceId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ interfaceId = urllib.parse.quote(str(interfaceId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/interfaces/{interfaceId}/dhcp"
body_params = [
@@ -1502,8 +1749,8 @@ def createNetworkSwitchStackRoutingStaticRoute(
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/staticRoutes"
body_params = [
@@ -1541,9 +1788,9 @@ def updateNetworkSwitchStackRoutingStaticRoute(self, networkId: str, switchStack
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
- staticRouteId = urllib.parse.quote(staticRouteId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ staticRouteId = urllib.parse.quote(str(staticRouteId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/staticRoutes/{staticRouteId}"
body_params = [
@@ -1573,9 +1820,9 @@ def deleteNetworkSwitchStackRoutingStaticRoute(self, networkId: str, switchStack
- staticRouteId (string): Static route ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- switchStackId = urllib.parse.quote(switchStackId, safe="")
- staticRouteId = urllib.parse.quote(staticRouteId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ staticRouteId = urllib.parse.quote(str(staticRouteId), safe="")
resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/routing/staticRoutes/{staticRouteId}"
action = {
@@ -1598,7 +1845,7 @@ def updateNetworkSwitchStormControl(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/stormControl"
body_params = [
@@ -1627,7 +1874,7 @@ def updateNetworkSwitchStp(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/stp"
body_params = [
@@ -1642,6 +1889,47 @@ def updateNetworkSwitchStp(self, networkId: str, **kwargs):
}
return action
+ def updateOrganizationConfigTemplateSwitchProfilePortsMirror(
+ self, organizationId: str, configTemplateId: str, profileId: str, source: dict, destination: dict, **kwargs
+ ):
+ """
+ **Update a port mirror**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-config-template-switch-profile-ports-mirror
+
+ - organizationId (string): Organization ID
+ - configTemplateId (string): Config template ID
+ - profileId (string): Profile ID
+ - source (object): Source ports mirror configuration
+ - destination (object): Destination port mirror configuration
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles/{profileId}/ports/mirror"
+ )
+
+ body_params = [
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "mirrors/update",
+ "body": payload,
+ }
+ return action
+
def updateOrganizationConfigTemplateSwitchProfilePort(
self, organizationId: str, configTemplateId: str, profileId: str, portId: str, **kwargs
):
@@ -1661,6 +1949,7 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
- vlan (integer): The VLAN of the switch template port. For a trunk port, this is the native VLAN. A null value will clear the value set for trunk ports.
- voiceVlan (integer): The voice VLAN of the switch template port. Only applicable to access ports.
- allowedVlans (string): The VLANs allowed on the switch template port. Only applicable to trunk ports.
+ - activeVlans (string): The VLANs that are active on the switch template port. Only applicable to trunk ports.
- isolationEnabled (boolean): The isolation status of the switch template port.
- rstpEnabled (boolean): The rapid spanning tree protocol status.
- stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard').
@@ -1702,10 +1991,10 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
f'''"accessPolicyType" cannot be "{kwargs["accessPolicyType"]}", & must be set to one of: {options}'''
)
- organizationId = urllib.parse.quote(organizationId, safe="")
- configTemplateId = urllib.parse.quote(configTemplateId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
- portId = urllib.parse.quote(portId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
+ portId = urllib.parse.quote(str(portId), safe="")
resource = (
f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles/{profileId}/ports/{portId}"
)
@@ -1719,6 +2008,7 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
"vlan",
"voiceVlan",
"allowedVlans",
+ "activeVlans",
"isolationEnabled",
"rstpEnabled",
"stpGuard",
@@ -1747,6 +2037,33 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
}
return action
+ def cloneOrganizationSwitchProfilesToTemplateNetwork(self, organizationId: str, **kwargs):
+ """
+ **Clone existing switch templates into a destination template network.**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-profiles-to-template-network
+
+ - organizationId (string): Organization ID
+ - profileIds (array): Switch profile IDs to clone
+ - templateNodeGroupId (string): Destination template network ID
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/cloneProfilesToTemplateNetwork"
+
+ body_params = [
+ "profileIds",
+ "templateNodeGroupId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "cloneProfilesToTemplateNetwork",
+ "body": payload,
+ }
+ return action
+
def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str, targetSerials: list, **kwargs):
"""
**Clone port-level and some switch-level configuration settings from a source switch to one or more target switches. Cloned settings include: Aggregation Groups, Power Settings, Multicast Settings, MTU Configuration, STP Bridge priority, Port Mirroring**
@@ -1759,7 +2076,7 @@ def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str,
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/switch/devices/clone"
body_params = [
@@ -1773,3 +2090,762 @@ def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str,
"body": payload,
}
return action
+
+ def createOrganizationSwitchPortsProfile(self, organizationId: str, **kwargs):
+ """
+ **Create a port profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - isOrganizationWide (boolean): The scope of the profile whether it is organization level or network level
+ - networks (object): The networks which are included/excluded in the profile
+ - networkId (string): The network identifier
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles"
+
+ body_params = [
+ "name",
+ "description",
+ "isOrganizationWide",
+ "networks",
+ "networkId",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "profiles/create",
+ "body": payload,
+ }
+ return action
+
+ def batchOrganizationSwitchPortsProfilesAssignmentsAssign(self, organizationId: str, items: list, **kwargs):
+ """
+ **Batch assign or unassign port profiles to switch ports**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-switch-ports-profiles-assignments-assign
+
+ - organizationId (string): Organization ID
+ - items (array): Array of assignment operations (max 100)
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/batchAssign"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "batch_assign",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, **kwargs):
+ """
+ **Create a port profile automation for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the port profile automation.
+ - description (string): Text describing the port profile automation.
+ - fallbackProfile (object): Configuration settings for port profile
+ - rules (array): Configuration settings for port profile automation rules
+ - assignedSwitchPorts (array): assigned switch ports
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations"
+
+ body_params = [
+ "name",
+ "description",
+ "fallbackProfile",
+ "rules",
+ "assignedSwitchPorts",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "automations/actions/update",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile automation in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the port profile automation.
+ - description (string): Text describing the port profile automation.
+ - fallbackProfile (object): Configuration settings for port profile
+ - rules (array): Configuration settings for port profile automation rules
+ - assignedSwitchPorts (array): assigned switch ports
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "fallbackProfile",
+ "rules",
+ "assignedSwitchPorts",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "automations/actions/update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, id: str):
+ """
+ **Delete an automation port profile from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "automations/actions/destroy",
+ }
+ return action
+
+ def createOrganizationSwitchPortsProfilesNetworksAssignment(
+ self, organizationId: str, type: str, profile: dict, network: dict, **kwargs
+ ):
+ """
+ **Create Network and Smart Ports Profile association for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-networks-assignment
+
+ - organizationId (string): Organization ID
+ - type (string): Type of association
+ - profile (object): Smart Port Profile object
+ - network (object): Network object
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments"
+
+ body_params = [
+ "type",
+ "profile",
+ "network",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "profiles/create",
+ "body": payload,
+ }
+ return action
+
+ def batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate(self, organizationId: str, items: list, **kwargs):
+ """
+ **Batch Create Network and Smart Ports Profile associations for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-switch-ports-profiles-networks-assignments-create
+
+ - organizationId (string): Organization ID
+ - items (array): Array of network and profile associations
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/batchCreate"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "batch_create",
+ "body": payload,
+ }
+ return action
+
+ def bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete(self, organizationId: str, items: list, **kwargs):
+ """
+ **Bulk delete Network and Smart Port Profile associations**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-switch-ports-profiles-networks-assignments-delete
+
+ - organizationId (string): Organization ID
+ - items (array): Array of assignments to delete
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/bulkDelete"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "bulk_destroy",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchPortsProfilesNetworksAssignment(self, organizationId: str, assignmentId: str):
+ """
+ **Delete Network and Smart Port profile association for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-networks-assignment
+
+ - organizationId (string): Organization ID
+ - assignmentId (string): Assignment ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ assignmentId = urllib.parse.quote(str(assignmentId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/{assignmentId}"
+
+ action = {
+ "resource": resource,
+ "operation": "profiles/destroy",
+ }
+ return action
+
+ def createOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, network: dict, **kwargs):
+ """
+ **Create a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - network (object): The network where the RADIUS name is assigned
+ - portProfile (object): The assigned port profile
+ - radius (object): The RADIUS options for this assignment
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments"
+
+ body_params = [
+ "network",
+ "portProfile",
+ "radius",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - network (object): The network where the RADIUS name is assigned
+ - portProfile (object): The assigned port profile
+ - radius (object): The RADIUS options for this assignment
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ body_params = [
+ "network",
+ "portProfile",
+ "radius",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str):
+ """
+ **Deletes a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateOrganizationSwitchPortsProfile(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - isOrganizationWide (boolean): The scope of the profile whether it is organization level or network level
+ - networks (object): The networks which are included/excluded in the profile
+ - networkId (string): The network identifier
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "isOrganizationWide",
+ "networks",
+ "networkId",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "profiles/update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchPortsProfile(self, organizationId: str, id: str):
+ """
+ **Delete a port profile from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "profiles/destroy",
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, number: int, **kwargs):
+ """
+ **Create an autonomous system. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - number (integer): The autonomous system number (CLI: 'router bgp ')
+ - description (string): A description for the autonomous system
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems"
+
+ body_params = [
+ "number",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "systems/create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, autonomousSystemId: str, **kwargs):
+ """
+ **Update an autonomous system. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - autonomousSystemId (string): Autonomous system ID
+ - number (integer): The autonomous system number (CLI: 'router bgp ')
+ - description (string): A description for the autonomous system
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ autonomousSystemId = urllib.parse.quote(str(autonomousSystemId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/{autonomousSystemId}"
+
+ body_params = [
+ "number",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "systems/update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, autonomousSystemId: str):
+ """
+ **Delete an autonomous system from an organization. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - autonomousSystemId (string): Autonomous system ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ autonomousSystemId = urllib.parse.quote(str(autonomousSystemId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/{autonomousSystemId}"
+
+ action = {
+ "resource": resource,
+ "operation": "systems/destroy",
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy(
+ self, organizationId: str, filterList: dict, network: dict, rules: list, **kwargs
+ ):
+ """
+ **Create or update a filter list, in addition to its associated rules. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-filters-filter-lists-deploy
+
+ - organizationId (string): Organization ID
+ - filterList (object): Information regarding the filter list
+ - network (object): Information regarding the network the filter list belongs to
+ - rules (array): Information regarding the filter list rules
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/deploy"
+
+ body_params = [
+ "filterList",
+ "network",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "deploy",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchRoutingBgpFiltersFilterList(self, organizationId: str, listId: str):
+ """
+ **Delete a filter list. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-filters-filter-list
+
+ - organizationId (string): Organization ID
+ - listId (string): List ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ listId = urllib.parse.quote(str(listId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/{listId}"
+
+ action = {
+ "resource": resource,
+ "operation": "lists/destroy",
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy(
+ self, organizationId: str, network: dict, prefixList: dict, rules: list, **kwargs
+ ):
+ """
+ **Create or update a prefix list, in addition to its associated rules. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-filters-prefix-lists-deploy
+
+ - organizationId (string): Organization ID
+ - network (object): Information regarding the network the prefix list belongs to
+ - prefixList (object): Information regarding the prefix list
+ - rules (array): Information regarding the prefix list rules
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/deploy"
+
+ body_params = [
+ "network",
+ "prefixList",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "deploy",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchRoutingBgpFiltersPrefixList(self, organizationId: str, listId: str):
+ """
+ **Delete a prefix list. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-filters-prefix-list
+
+ - organizationId (string): Organization ID
+ - listId (string): List ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ listId = urllib.parse.quote(str(listId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/{listId}"
+
+ action = {
+ "resource": resource,
+ "operation": "lists/destroy",
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpPeersGroupsDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ network: dict,
+ peerGroup: dict,
+ peerGroupAddressFamilyBindingProfile: dict,
+ peerGroupProfile: dict,
+ policies: list,
+ router: dict,
+ **kwargs,
+ ):
+ """
+ **Create or update a peer group, in addition to an associated peer group profile, peer group address family binding, peer group address family binding profile and routing policies associated with the peer group. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-peers-groups-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family the peer group address family binding belongs to
+ - network (object): Information regarding the network the peer group profile belongs to
+ - peerGroup (object): Information regarding the peer group
+ - peerGroupAddressFamilyBindingProfile (object): Information regarding the peer group address family binding profile
+ - peerGroupProfile (object): Information regarding the peer group profile
+ - policies (array): Information regarding the routing policies
+ - router (object): Information regarding the router this peer group belongs to
+ - peerGroupAddressFamilyBinding (object): Information regarding the peer group address family binding. Only required when updating.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/deploy"
+
+ body_params = [
+ "addressFamily",
+ "network",
+ "peerGroup",
+ "peerGroupAddressFamilyBinding",
+ "peerGroupAddressFamilyBindingProfile",
+ "peerGroupProfile",
+ "policies",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "deploy",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpPeersNeighborsDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ neighbor: dict,
+ neighborAddressFamilyBinding: dict,
+ peerGroup: dict,
+ policies: list,
+ router: dict,
+ **kwargs,
+ ):
+ """
+ **Create or update a neighor, in addition to an associated neighbor address family binding and routing policies associated with the neighbor. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-peers-neighbors-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family this binding is bound to
+ - neighbor (object): Information regarding the BPG neighbor
+ - neighborAddressFamilyBinding (object): Information regarding the neighbor address family binding
+ - peerGroup (object): Information regarding the peer group this neighbor belongs to
+ - policies (array): Information regarding the routing policies related to the neighbor
+ - router (object): Information regarding the router this neighbor peers with
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors/deploy"
+
+ body_params = [
+ "addressFamily",
+ "neighbor",
+ "neighborAddressFamilyBinding",
+ "peerGroup",
+ "policies",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "deploy",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpRoutersDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ addressFamilyPrefixes: list,
+ addressFamilyProfile: dict,
+ autonomousSystem: dict,
+ router: dict,
+ switch: dict,
+ **kwargs,
+ ):
+ """
+ **Create a BGP router, in addition to an associated address family, address family prefixes, and address family profile. This is helpful for the initial deployment of a BGP router.. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-routers-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family
+ - addressFamilyPrefixes (array): The list of network prefixes to which the address family applies
+ - addressFamilyProfile (object): Information regarding the profile applied to the address family
+ - autonomousSystem (object): Information regarding the router's autonomous system
+ - router (object): Information regarding the BPG router
+ - switch (object): The router's switch node. When the router is part of a switch stack, this is the switch stack's active node
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/deploy"
+
+ body_params = [
+ "addressFamily",
+ "addressFamilyPrefixes",
+ "addressFamilyProfile",
+ "autonomousSystem",
+ "router",
+ "switch",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "deploy",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationSwitchRoutingBgpRoutersPeersDeploy(
+ self, organizationId: str, addressFamily: dict, peerGroups: list, router: dict, **kwargs
+ ):
+ """
+ **Create and update listen ranges, update peers' enabled flag, and delete peer groups for a BGP router. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-routers-peers-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family
+ - peerGroups (array): Information regarding the peer group peers for a router's peer group
+ - router (object): Information regarding the BPG router
+ """
+
+ kwargs = locals()
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/peers/deploy"
+
+ body_params = [
+ "addressFamily",
+ "peerGroups",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "peers_deploy",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationSwitchRoutingBgpRouter(self, organizationId: str, routerId: str):
+ """
+ **Delete a router from an organization. Border Gateway Protocol requires IOS XE 17.18 or higher**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-router
+
+ - organizationId (string): Organization ID
+ - routerId (string): Router ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ routerId = urllib.parse.quote(str(routerId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/{routerId}"
+
+ action = {
+ "resource": resource,
+ "operation": "ms/actions/bgp/routers/destroy",
+ }
+ return action
diff --git a/meraki/api/batch/users.py b/meraki/api/batch/users.py
new file mode 100644
index 00000000..ef21c3eb
--- /dev/null
+++ b/meraki/api/batch/users.py
@@ -0,0 +1,359 @@
+import urllib
+
+
+class ActionBatchUsers(object):
+ def __init__(self):
+ super(ActionBatchUsers, self).__init__()
+
+ def createOrganizationIamUsersAuthorization(self, organizationId: str, authZone: dict, **kwargs):
+ """
+ **Authorize a Meraki end user for an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-authorization
+
+ - organizationId (string): Organization ID
+ - authZone (object): Auth zone
+ - email (string): Meraki end user's email
+ - idpUserId (string): Meraki end user's ID
+ - startsAt (string): Start time of the desired access for the authorization. Defaults to now.
+ - expiresAt (string): Expiration time of the desired access for the authorization
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ body_params = [
+ "email",
+ "idpUserId",
+ "authZone",
+ "startsAt",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationIamUsersAuthorizations(self, organizationId: str, **kwargs):
+ """
+ **Update a Meraki end user's access to an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-authorizations
+
+ - organizationId (string): Organization ID
+ - authorizationId (string): Authorization ID
+ - email (string): Meraki end user's email
+ - authZone (object): Auth zone
+ - startsAt (string): Start time of the desired access for the authorization
+ - expiresAt (string): Expiration time of the desired access for the authorization
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ body_params = [
+ "authorizationId",
+ "email",
+ "authZone",
+ "startsAt",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def revokeOrganizationIamUsersAuthorizationsAuthorization(self, organizationId: str, authZone: dict, **kwargs):
+ """
+ **Revoke a Meraki end user's access to an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-organization-iam-users-authorizations-authorization
+
+ - organizationId (string): Organization ID
+ - authZone (object): Auth zone
+ - email (string): Meraki end user's email
+ - authorizationId (string): Authorization ID
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/authorization/revoke"
+
+ body_params = [
+ "email",
+ "authorizationId",
+ "authZone",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "revoke",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationIamUsersAuthorization(self, organizationId: str, authorizationId: str):
+ """
+ **Delete an authorization for a Meraki end user.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-authorization
+
+ - organizationId (string): Organization ID
+ - authorizationId (string): Authorization ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ authorizationId = urllib.parse.quote(str(authorizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/{authorizationId}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationIamUsersIdp(self, organizationId: str, name: str, type: str, idpConfig: dict, **kwargs):
+ """
+ **Create an identity provider for an organization. Only Entra ID(Azure AD) is supported at this time.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the identity provider
+ - type (string): Type of the identity provider
+ - idpConfig (object): Identity provider configuration. Required for external identity providers.
+ - description (string): Optional. Description of the identity provider
+ - syncType (string): The synchronization method for the identity provider. Set to 'proactive' to sync all users and groups from your identity provider.
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["Azure AD"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+ if "syncType" in kwargs and kwargs["syncType"] is not None:
+ options = ["proactive"]
+ assert kwargs["syncType"] in options, (
+ f'''"syncType" cannot be "{kwargs["syncType"]}", & must be set to one of: {options}'''
+ )
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps"
+
+ body_params = [
+ "name",
+ "type",
+ "description",
+ "idpConfig",
+ "syncType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationIamUsersIdpsTestConnectivity(self, organizationId: str, **kwargs):
+ """
+ **Test connectivity to an Entra ID identity provider.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-test-connectivity
+
+ - organizationId (string): Organization ID
+ - idpId (string): Id of the identity provider
+ - idpConfig (object): Identity provider configuration. Required for external identity providers.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/testConnectivity"
+
+ body_params = [
+ "idpId",
+ "idpConfig",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "test_connectivity",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationIamUsersIdpsUser(self, organizationId: str, **kwargs):
+ """
+ **Create a Meraki user**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - displayName (string): A human-readable identifier for the created user.
+ - email (string): An email address identified with the user.
+ - password (string): The password for the user account.
+ - sendPassword (boolean): If true, sends an email with the password to the user.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users"
+
+ body_params = [
+ "displayName",
+ "email",
+ "password",
+ "sendPassword",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationIamUsersIdpsUser(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a Meraki user**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - displayName (string): A human-readable identifier for the created user.
+ - email (string): An email address identified with the user.
+ - password (string): The password for the user account.
+ - sendPassword (boolean): If true, sends an email with the password to the user.
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users/{id}"
+
+ body_params = [
+ "displayName",
+ "email",
+ "password",
+ "sendPassword",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationIamUsersIdpsUser(self, organizationId: str, id: str):
+ """
+ **Delete a Meraki end user**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def createOrganizationIamUsersIdpSync(self, organizationId: str, idpId: str, **kwargs):
+ """
+ **Trigger an IdP sync for an identity provider. Only Entra ID(Azure AD) is supported at this time.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idp-sync
+
+ - organizationId (string): Organization ID
+ - idpId (string): Idp ID
+ - emails (array): List of emails to sync
+ - force (boolean): Force a complete sync of all users and groups
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{idpId}/sync"
+
+ body_params = [
+ "emails",
+ "force",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def updateOrganizationIamUsersIdp(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update an identity provider. Only Entra ID(Azure AD) is supported at this time.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the identity provider
+ - description (string): Description of the identity provider
+ - idpConfig (object): Identity provider configuration. You can update individual attributes
+ - syncType (string): The synchronization method for the identity provider. Set to 'proactive' to sync all users and groups from your identity provider. Set to 'null' for on-demand user and group provisioning.
+ """
+
+ kwargs.update(locals())
+
+ if "syncType" in kwargs and kwargs["syncType"] is not None:
+ options = ["proactive"]
+ assert kwargs["syncType"] in options, (
+ f'''"syncType" cannot be "{kwargs["syncType"]}", & must be set to one of: {options}'''
+ )
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "idpConfig",
+ "syncType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationIamUsersIdp(self, organizationId: str, id: str):
+ """
+ **Delete a identity provider from an organization. Only Entra ID(Azure AD) is supported at this time.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
diff --git a/meraki/api/batch/wireless.py b/meraki/api/batch/wireless.py
index 21684c44..f9026a78 100644
--- a/meraki/api/batch/wireless.py
+++ b/meraki/api/batch/wireless.py
@@ -16,7 +16,7 @@ def updateDeviceWirelessAlternateManagementInterfaceIpv6(self, serial: str, **kw
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/wireless/alternateManagementInterface/ipv6"
body_params = [
@@ -42,17 +42,19 @@ def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs):
Dashboard's automatically generated value.
- minor (integer): Desired minor value of the beacon. If the value is set to null it will reset to
Dashboard's automatically generated value.
+ - transmit (object): Transmit settings including power, interval, and advertised power.
"""
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/wireless/bluetooth/settings"
body_params = [
"uuid",
"major",
"minor",
+ "transmit",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -74,7 +76,7 @@ def updateDeviceWirelessElectronicShelfLabel(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/wireless/electronicShelfLabel"
body_params = [
@@ -89,6 +91,60 @@ def updateDeviceWirelessElectronicShelfLabel(self, serial: str, **kwargs):
}
return action
+ def updateDeviceWirelessRadioAfcPosition(self, serial: str, **kwargs):
+ """
+ **Update the position attributes for this device**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-wireless-radio-afc-position
+
+ - serial (string): Serial
+ - height (object): Height attributes
+ - gps (object): GPS attributes
+ """
+
+ kwargs.update(locals())
+
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/position"
+
+ body_params = [
+ "height",
+ "gps",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateDeviceWirelessRadioOverrides(self, serial: str, **kwargs):
+ """
+ **Update 2.4 GHz, 5 GHz, and 6 GHz radio settings (channel, channel width, power, and enable/disable) that override RF profiles.**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-wireless-radio-overrides
+
+ - serial (string): Serial
+ - rfProfile (object): This device's RF profile
+ - radios (array): Radio overrides.
+ """
+
+ kwargs.update(locals())
+
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/overrides"
+
+ body_params = [
+ "rfProfile",
+ "radios",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def updateDeviceWirelessRadioSettings(self, serial: str, **kwargs):
"""
**Update 2.4 GHz and 5 GHz radio settings (channel, channel width, power) that override RF profiles. For 6 GHz support or radio enable/disable, use updateDeviceWirelessRadioOverrides instead.**
@@ -102,7 +158,7 @@ def updateDeviceWirelessRadioSettings(self, serial: str, **kwargs):
kwargs.update(locals())
- serial = urllib.parse.quote(serial, safe="")
+ serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/wireless/radio/settings"
body_params = [
@@ -134,7 +190,7 @@ def createNetworkWirelessAirMarshalRule(self, networkId: str, type: str, match:
options = ["alert", "allow", "block"]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/airMarshal/rules"
body_params = [
@@ -166,8 +222,8 @@ def updateNetworkWirelessAirMarshalRule(self, networkId: str, ruleId: str, **kwa
options = ["alert", "allow", "block"]
assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
- networkId = urllib.parse.quote(networkId, safe="")
- ruleId = urllib.parse.quote(ruleId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
resource = f"/networks/{networkId}/wireless/airMarshal/rules/{ruleId}"
body_params = [
@@ -191,8 +247,8 @@ def deleteNetworkWirelessAirMarshalRule(self, networkId: str, ruleId: str):
- ruleId (string): Rule ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- ruleId = urllib.parse.quote(ruleId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
resource = f"/networks/{networkId}/wireless/airMarshal/rules/{ruleId}"
action = {
@@ -218,7 +274,7 @@ def updateNetworkWirelessAirMarshalSettings(self, networkId: str, defaultPolicy:
f'''"defaultPolicy" cannot be "{kwargs["defaultPolicy"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/airMarshal/settings"
body_params = [
@@ -246,7 +302,7 @@ def updateNetworkWirelessAlternateManagementInterface(self, networkId: str, **kw
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/alternateManagementInterface"
body_params = [
@@ -275,7 +331,7 @@ def updateNetworkWirelessBilling(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/billing"
body_params = [
@@ -307,7 +363,7 @@ def updateNetworkWirelessElectronicShelfLabel(self, networkId: str, **kwargs):
options = ["Bluetooth", "high frequency"]
assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/electronicShelfLabel"
body_params = [
@@ -332,17 +388,19 @@ def createNetworkWirelessEthernetPortsProfile(self, networkId: str, name: str, p
- name (string): AP port profile name
- ports (array): AP ports configuration
- usbPorts (array): AP usb ports configuration
+ - security (object): AP port security configuration
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/ethernet/ports/profiles"
body_params = [
"name",
"ports",
"usbPorts",
+ "security",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -364,7 +422,7 @@ def assignNetworkWirelessEthernetPortsProfiles(self, networkId: str, serials: li
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/ethernet/ports/profiles/assign"
body_params = [
@@ -390,7 +448,7 @@ def setNetworkWirelessEthernetPortsProfilesDefault(self, networkId: str, profile
kwargs = locals()
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/ethernet/ports/profiles/setDefault"
body_params = [
@@ -414,18 +472,20 @@ def updateNetworkWirelessEthernetPortsProfile(self, networkId: str, profileId: s
- name (string): AP port profile name
- ports (array): AP ports configuration
- usbPorts (array): AP usb ports configuration
+ - security (object): AP port security configuration
"""
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/networks/{networkId}/wireless/ethernet/ports/profiles/{profileId}"
body_params = [
"name",
"ports",
"usbPorts",
+ "security",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -444,8 +504,8 @@ def deleteNetworkWirelessEthernetPortsProfile(self, networkId: str, profileId: s
- profileId (string): Profile ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- profileId = urllib.parse.quote(profileId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
resource = f"/networks/{networkId}/wireless/ethernet/ports/profiles/{profileId}"
action = {
@@ -466,7 +526,7 @@ def updateNetworkWirelessLocationScanning(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/location/scanning"
body_params = [
@@ -481,6 +541,89 @@ def updateNetworkWirelessLocationScanning(self, networkId: str, **kwargs):
}
return action
+ def updateNetworkWirelessLocationWayfinding(self, networkId: str, **kwargs):
+ """
+ **Change client wayfinding settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-location-wayfinding
+
+ - networkId (string): Network ID
+ - enabled (boolean): Whether to enable client wayfinding on that network (only supported on Wireless networks).
+ - maintenanceWindow (object): Maintenance window during which optimization might take place to improve location accuracy.
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/location/wayfinding"
+
+ body_params = [
+ "enabled",
+ "maintenanceWindow",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkWirelessOpportunisticPcap(self, networkId: str, **kwargs):
+ """
+ **Update the Opportunistic Pcap settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-opportunistic-pcap
+
+ - networkId (string): Network ID
+ - enablement (object): Enablement settings
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/opportunisticPcap"
+
+ body_params = [
+ "enablement",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "factory",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkWirelessRadioAutoRf(self, networkId: str, **kwargs):
+ """
+ **Update the AutoRF settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-auto-rf
+
+ - networkId (string): Network ID
+ - busyHour (object): Busy Hour settings
+ - channel (object): Channel settings
+ - fra (object): FRA settings
+ - aiRrm (object): AI-RRM settings
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/radio/autoRf"
+
+ body_params = [
+ "busyHour",
+ "channel",
+ "fra",
+ "aiRrm",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
"""
**Update the AutoRF settings for a wireless network**
@@ -495,7 +638,7 @@ def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/radio/rrm"
body_params = [
@@ -529,6 +672,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
- transmission (object): Settings related to radio transmission.
- perSsidSettings (object): Per-SSID radio settings by number.
- flexRadios (object): Flex radio settings.
+ - dot11be (object): 802.11be settings
"""
kwargs.update(locals())
@@ -544,7 +688,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
f'''"bandSelectionType" cannot be "{kwargs["bandSelectionType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/rfProfiles"
body_params = [
@@ -559,6 +703,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
"transmission",
"perSsidSettings",
"flexRadios",
+ "dot11be",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -588,6 +733,7 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
- transmission (object): Settings related to radio transmission.
- perSsidSettings (object): Per-SSID radio settings by number.
- flexRadios (object): Flex radio settings.
+ - dot11be (object): 802.11be settings
"""
kwargs.update(locals())
@@ -603,8 +749,8 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
f'''"bandSelectionType" cannot be "{kwargs["bandSelectionType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- rfProfileId = urllib.parse.quote(rfProfileId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ rfProfileId = urllib.parse.quote(str(rfProfileId), safe="")
resource = f"/networks/{networkId}/wireless/rfProfiles/{rfProfileId}"
body_params = [
@@ -621,6 +767,7 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
"transmission",
"perSsidSettings",
"flexRadios",
+ "dot11be",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
action = {
@@ -639,8 +786,8 @@ def deleteNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str):
- rfProfileId (string): Rf profile ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- rfProfileId = urllib.parse.quote(rfProfileId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ rfProfileId = urllib.parse.quote(str(rfProfileId), safe="")
resource = f"/networks/{networkId}/wireless/rfProfiles/{rfProfileId}"
action = {
@@ -673,7 +820,7 @@ def updateNetworkWirelessSettings(self, networkId: str, **kwargs):
f'''"upgradeStrategy" cannot be "{kwargs["upgradeStrategy"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/settings"
body_params = [
@@ -703,6 +850,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
- number (string): Number
- name (string): The name of the SSID
- enabled (boolean): Whether or not the SSID is enabled
+ - localAuth (boolean): Extended local auth flag for Enterprise NAC
- authMode (string): The association control method for the SSID ('open', 'open-enhanced', 'psk', 'open-with-radius', 'open-enhanced-with-radius', 'open-with-nac', '8021x-meraki', '8021x-nac', '8021x-radius', '8021x-google', '8021x-entra', '8021x-localradius', 'ipsk-with-radius', 'ipsk-without-radius', 'ipsk-with-nac' or 'ipsk-with-radius-easy-psk')
- enterpriseAdminAccess (string): Whether or not an SSID is accessible by 'enterprise' administrators ('access disabled' or 'access enabled')
- ssidAdminAccessible (boolean): SSID Administrator access status
@@ -734,6 +882,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
- radiusAccountingInterimInterval (integer): The interval (in seconds) in which accounting information is updated and sent to the RADIUS accounting server.
- radiusAttributeForGroupPolicies (string): Specify the RADIUS attribute used to look up group policies ('Filter-Id', 'Reply-Message', 'Airespace-ACL-Name' or 'Aruba-User-Role'). Access points must receive this attribute in the RADIUS Access-Accept message
- ipAssignmentMode (string): The client IP assignment mode ('NAT mode', 'Bridge mode', 'Layer 3 roaming', 'Ethernet over GRE', 'Layer 3 roaming with a concentrator', 'VPN' or 'Campus Gateway')
+ - campusGateway (object): Campus gateway settings
- useVlanTagging (boolean): Whether or not traffic should be directed to use specific VLANs. This param is only valid if the ipAssignmentMode is 'Bridge mode' or 'Layer 3 roaming'
- concentratorNetworkId (string): The concentrator to use when the ipAssignmentMode is 'Layer 3 roaming with a concentrator' or 'VPN'.
- secondaryConcentratorNetworkId (string): The secondary concentrator to use when the ipAssignmentMode is 'VPN'. If configured, the APs will switch to using this concentrator if the primary concentrator is unreachable. This param is optional. ('disabled' represents no secondary concentrator.)
@@ -844,13 +993,14 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
f'''"radiusAttributeForGroupPolicies" cannot be "{kwargs["radiusAttributeForGroupPolicies"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}"
body_params = [
"name",
"enabled",
+ "localAuth",
"authMode",
"enterpriseAdminAccess",
"ssidAdminAccessible",
@@ -882,6 +1032,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
"radiusAccountingInterimInterval",
"radiusAttributeForGroupPolicies",
"ipAssignmentMode",
+ "campusGateway",
"useVlanTagging",
"concentratorNetworkId",
"secondaryConcentratorNetworkId",
@@ -937,8 +1088,8 @@ def updateNetworkWirelessSsidBonjourForwarding(self, networkId: str, number: str
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/bonjourForwarding"
body_params = [
@@ -967,8 +1118,8 @@ def updateNetworkWirelessSsidDeviceTypeGroupPolicies(self, networkId: str, numbe
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/deviceTypeGroupPolicies"
body_params = [
@@ -998,8 +1149,8 @@ def updateNetworkWirelessSsidEapOverride(self, networkId: str, number: str, **kw
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/eapOverride"
body_params = [
@@ -1029,8 +1180,8 @@ def updateNetworkWirelessSsidFirewallL3FirewallRules(self, networkId: str, numbe
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/firewall/l3FirewallRules"
body_params = [
@@ -1057,8 +1208,8 @@ def updateNetworkWirelessSsidFirewallL7FirewallRules(self, networkId: str, numbe
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/firewall/l7FirewallRules"
body_params = [
@@ -1106,8 +1257,8 @@ def updateNetworkWirelessSsidHotspot20(self, networkId: str, number: str, **kwar
f'''"networkAccessType" cannot be "{kwargs["networkAccessType"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/hotspot20"
body_params = [
@@ -1143,8 +1294,8 @@ def createNetworkWirelessSsidIdentityPsk(self, networkId: str, number: str, name
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/identityPsks"
body_params = [
@@ -1177,9 +1328,9 @@ def updateNetworkWirelessSsidIdentityPsk(self, networkId: str, number: str, iden
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
- identityPskId = urllib.parse.quote(identityPskId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ identityPskId = urllib.parse.quote(str(identityPskId), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/identityPsks/{identityPskId}"
body_params = [
@@ -1206,9 +1357,9 @@ def deleteNetworkWirelessSsidIdentityPsk(self, networkId: str, number: str, iden
- identityPskId (string): Identity psk ID
"""
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
- identityPskId = urllib.parse.quote(identityPskId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ identityPskId = urllib.parse.quote(str(identityPskId), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/identityPsks/{identityPskId}"
action = {
@@ -1230,8 +1381,8 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/openRoaming"
body_params = [
@@ -1246,6 +1397,117 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw
}
return action
+ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, number: str, **kwargs):
+ """
+ **Update the client exclusion status configuration for a given SSID**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-ssid-policies-client-exclusion
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - static (object): Static client exclusion status
+ - dynamic (object): Dynamic client exclusion configuration
+ """
+
+ kwargs.update(locals())
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion"
+
+ body_params = [
+ "static",
+ "dynamic",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Replace the static client exclusion list for the given SSID (use PUT /exclusions)**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-ssid-policies-client-exclusion-static-exclusions
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to set as static exclusion list
+ """
+
+ kwargs = locals()
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Add MAC addresses to the existing static client exclusion list for the given SSID (use POST /bulkAdd)**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-wireless-ssid-policies-client-exclusion-static-exclusions-bulk-add
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to add to static exclusion
+ """
+
+ kwargs = locals()
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions/bulkAdd"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Remove MAC addresses from the existing static client exclusion list for the given SSID (use POST /bulkRemove)**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-wireless-ssid-policies-client-exclusion-static-exclusions-bulk-remove
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to remove from static exclusion
+ """
+
+ kwargs = locals()
+
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions/bulkRemove"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def updateNetworkWirelessSsidSchedules(self, networkId: str, number: str, **kwargs):
"""
**Update the outage schedule for the SSID**
@@ -1260,8 +1522,8 @@ def updateNetworkWirelessSsidSchedules(self, networkId: str, number: str, **kwar
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/schedules"
body_params = [
@@ -1290,6 +1552,7 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
- redirectUrl (string): The custom redirect URL where the users will go after the splash page.
- useRedirectUrl (boolean): The Boolean indicating whether the the user will be redirected to the custom redirect URL after the splash page. A custom redirect URL must be set if this is true.
- welcomeMessage (string): The welcome message for the users on the splash page.
+ - language (string): Language of splash page.
- userConsent (object): User consent settings
- themeId (string): The id of the selected splash theme.
- splashLogo (object): The logo used in the splash page.
@@ -1311,14 +1574,40 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
assert kwargs["splashTimeout"] in options, (
f'''"splashTimeout" cannot be "{kwargs["splashTimeout"]}", & must be set to one of: {options}'''
)
+ if "language" in kwargs:
+ options = [
+ "DA",
+ "DE",
+ "EL",
+ "EN",
+ "ES",
+ "FI",
+ "FR",
+ "GL",
+ "IT",
+ "JA",
+ "KO",
+ "NL",
+ "NO",
+ "PL",
+ "PT",
+ "RU",
+ "SK",
+ "SV",
+ "UK",
+ "ZH",
+ ]
+ assert kwargs["language"] in options, (
+ f'''"language" cannot be "{kwargs["language"]}", & must be set to one of: {options}'''
+ )
if "controllerDisconnectionBehavior" in kwargs:
options = ["default", "open", "restricted"]
assert kwargs["controllerDisconnectionBehavior"] in options, (
f'''"controllerDisconnectionBehavior" cannot be "{kwargs["controllerDisconnectionBehavior"]}", & must be set to one of: {options}'''
)
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/splash/settings"
body_params = [
@@ -1328,6 +1617,7 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
"redirectUrl",
"useRedirectUrl",
"welcomeMessage",
+ "language",
"userConsent",
"themeId",
"splashLogo",
@@ -1366,8 +1656,8 @@ def updateNetworkWirelessSsidTrafficShapingRules(self, networkId: str, number: s
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/trafficShaping/rules"
body_params = [
@@ -1397,8 +1687,8 @@ def updateNetworkWirelessSsidVpn(self, networkId: str, number: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
- number = urllib.parse.quote(number, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
resource = f"/networks/{networkId}/wireless/ssids/{number}/vpn"
body_params = [
@@ -1428,7 +1718,7 @@ def updateNetworkWirelessZigbee(self, networkId: str, **kwargs):
kwargs.update(locals())
- networkId = urllib.parse.quote(networkId, safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/wireless/zigbee"
body_params = [
@@ -1445,6 +1735,33 @@ def updateNetworkWirelessZigbee(self, networkId: str, **kwargs):
}
return action
+ def createOrganizationWirelessDevicesLiveToolsClientDisconnect(self, organizationId: str, clientId: str, **kwargs):
+ """
+ **Enqueue a job to disconnect a client from an AP. This endpoint has a sustained rate limit of one request every five seconds per device, with an allowed burst of five requests.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-live-tools-client-disconnect
+
+ - organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/liveTools/clients/{clientId}/disconnect"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "disconnect",
+ "body": payload,
+ }
+ return action
+
def createOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, items: list, **kwargs):
"""
**Create a zero touch deployment for a wireless access point**
@@ -1457,7 +1774,7 @@ def createOrganizationWirelessDevicesProvisioningDeployment(self, organizationId
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
body_params = [
@@ -1484,7 +1801,7 @@ def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationI
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
body_params = [
@@ -1508,8 +1825,8 @@ def deleteOrganizationWirelessDevicesProvisioningDeployment(self, organizationId
- deploymentId (string): Deployment ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- deploymentId = urllib.parse.quote(deploymentId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/{deploymentId}"
action = {
@@ -1535,7 +1852,7 @@ def createOrganizationWirelessLocationScanningReceiver(
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
body_params = [
@@ -1567,8 +1884,8 @@ def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- receiverId = urllib.parse.quote(receiverId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ receiverId = urllib.parse.quote(str(receiverId), safe="")
resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
body_params = [
@@ -1593,8 +1910,8 @@ def deleteOrganizationWirelessLocationScanningReceiver(self, organizationId: str
- receiverId (string): Receiver ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- receiverId = urllib.parse.quote(receiverId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ receiverId = urllib.parse.quote(str(receiverId), safe="")
resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
action = {
@@ -1617,7 +1934,7 @@ def updateOrganizationWirelessMqttSettings(self, organizationId: str, network: d
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
body_params = [
@@ -1645,7 +1962,7 @@ def recalculateOrganizationWirelessRadioAutoRfChannels(self, organizationId: str
kwargs = locals()
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/recalculate"
body_params = [
@@ -1675,7 +1992,7 @@ def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
body_params = [
@@ -1701,8 +2018,8 @@ def deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organiz
- entryId (string): Entry ID
"""
- organizationId = urllib.parse.quote(organizationId, safe="")
- entryId = urllib.parse.quote(entryId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ entryId = urllib.parse.quote(str(entryId), safe="")
resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
action = {
@@ -1724,8 +2041,8 @@ def updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organiz
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- entryId = urllib.parse.quote(entryId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ entryId = urllib.parse.quote(str(entryId), safe="")
resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
body_params = [
@@ -1740,6 +2057,133 @@ def updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organiz
}
return action
+ def createOrganizationWirelessSsidsProfile(self, organizationId: str, name: str, ssid: dict, **kwargs):
+ """
+ **Create a new SSID profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the SSID profile
+ - ssid (object): SSID configuration for the profile
+ - precedence (object): Precedence configuration for the SSID profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles"
+
+ body_params = [
+ "name",
+ "precedence",
+ "ssid",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def createOrganizationWirelessSsidsProfilesAssignment(self, organizationId: str, profile: dict, ssid: dict, **kwargs):
+ """
+ **Assigns an SSID profile to an SSID in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-profiles-assignment
+
+ - organizationId (string): Organization ID
+ - profile (object): SSID profile to assign
+ - ssid (object): SSID to assign the SSID profile to
+ - network (object): Network containing the SSID (required if SSID number is used)
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
+
+ body_params = [
+ "profile",
+ "ssid",
+ "network",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "create",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationWirelessSsidsProfilesAssignments(self, organizationId: str, ssid: dict, **kwargs):
+ """
+ **Unassigns the SSID profile assigned to an SSID**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-profiles-assignments
+
+ - organizationId (string): Organization ID
+ - ssid (object): SSID to delete the SSID profile assignment of
+ - network (object): Network containing the SSID (required if SSID number is used)
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
+ def updateOrganizationWirelessSsidsProfile(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update this SSID profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the SSID profile
+ - ssid (object): SSID configuration for the profile
+ """
+
+ kwargs.update(locals())
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/{id}"
+
+ body_params = [
+ "name",
+ "ssid",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ action = {
+ "resource": resource,
+ "operation": "update",
+ "body": payload,
+ }
+ return action
+
+ def deleteOrganizationWirelessSsidsProfile(self, organizationId: str, id: str):
+ """
+ **Delete an SSID profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/{id}"
+
+ action = {
+ "resource": resource,
+ "operation": "destroy",
+ }
+ return action
+
def updateOrganizationWirelessZigbeeDevice(self, organizationId: str, id: str, enrolled: bool, **kwargs):
"""
**Endpoint to update zigbee gateways**
@@ -1753,8 +2197,8 @@ def updateOrganizationWirelessZigbeeDevice(self, organizationId: str, id: str, e
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- id = urllib.parse.quote(id, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
resource = f"/organizations/{organizationId}/wireless/zigbee/devices/{id}"
body_params = [
@@ -1781,8 +2225,8 @@ def updateOrganizationWirelessZigbeeDoorLock(self, organizationId: str, doorLock
kwargs.update(locals())
- organizationId = urllib.parse.quote(organizationId, safe="")
- doorLockId = urllib.parse.quote(doorLockId, safe="")
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ doorLockId = urllib.parse.quote(str(doorLockId), safe="")
resource = f"/organizations/{organizationId}/wireless/zigbee/doorLocks/{doorLockId}"
body_params = [
diff --git a/meraki/api/camera.py b/meraki/api/camera.py
index 2f834255..7d983310 100644
--- a/meraki/api/camera.py
+++ b/meraki/api/camera.py
@@ -739,6 +739,97 @@ def getNetworkCameraSchedules(self, networkId: str):
return self._session.get(metadata, resource)
+ def createNetworkCameraVideoWall(self, networkId: str, name: str, tiles: list, **kwargs):
+ """
+ **Create a new video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - name (string): The name of the video wall.
+ - tiles (array): The tiles that should appear on the video wall.
+ - index (integer): The order that this wall should appear on the video wall list.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "createNetworkCameraVideoWall",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls"
+
+ body_params = [
+ "name",
+ "index",
+ "tiles",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkCameraVideoWall: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateNetworkCameraVideoWall(self, networkId: str, id: str, name: str, tiles: list, **kwargs):
+ """
+ **Update the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - id (string): ID
+ - name (string): The name of the video wall.
+ - tiles (array): The tiles that should appear on the video wall.
+ - index (integer): The order that this wall should appear on the video wall list.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "updateNetworkCameraVideoWall",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls/{id}"
+
+ body_params = [
+ "name",
+ "index",
+ "tiles",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkCameraVideoWall: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteNetworkCameraVideoWall(self, networkId: str, id: str):
+ """
+ **Delete the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-camera-video-wall
+
+ - networkId (string): Network ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "deleteNetworkCameraVideoWall",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/camera/videoWalls/{id}"
+
+ return self._session.delete(metadata, resource)
+
def createNetworkCameraWirelessProfile(self, networkId: str, name: str, ssid: dict, **kwargs):
"""
**Creates a new camera wireless profile for this network.**
@@ -1091,6 +1182,45 @@ def getOrganizationCameraDetectionsHistoryByBoundaryByInterval(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationCameraDevicesConfigurations(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Lists all the capabilities of cameras in this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-devices-configurations
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "devices", "configurations"],
+ "operation": "getOrganizationCameraDevicesConfigurations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/camera/devices/configurations"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCameraDevicesConfigurations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationCameraOnboardingStatuses(self, organizationId: str, **kwargs):
"""
**Fetch onboarding status of cameras**
@@ -1336,3 +1466,104 @@ def updateOrganizationCameraRole(self, organizationId: str, roleId: str, **kwarg
self._session._logger.warning(f"updateOrganizationCameraRole: ignoring unrecognized kwargs: {invalid}")
return self._session.put(metadata, resource, payload)
+
+ def getOrganizationCameraVideoWalls(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return a list of video walls.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-video-walls
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 10 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of network ids to filter video walls on
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "getOrganizationCameraVideoWalls",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/camera/videoWalls"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationCameraVideoWalls: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCameraVideoWall(self, organizationId: str, id: str):
+ """
+ **Return the specified video wall.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-video-wall
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls"],
+ "operation": "getOrganizationCameraVideoWall",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/camera/videoWalls/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationCameraVideoWallVideoLink(self, organizationId: str, id: str, **kwargs):
+ """
+ **Returns video wall link to the specified video wall id**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-camera-video-wall-video-link
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - timestamp (string): [optional] The video link will start at this time. The timestamp should be a string in ISO8601 format. If no timestamp is specified, we will assume current time.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["camera", "configure", "videoWalls", "videoLink"],
+ "operation": "getOrganizationCameraVideoWallVideoLink",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/camera/videoWalls/{id}/videoLink"
+
+ query_params = [
+ "timestamp",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCameraVideoWallVideoLink: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
diff --git a/meraki/api/campusGateway.py b/meraki/api/campusGateway.py
index c5636184..cc456d95 100644
--- a/meraki/api/campusGateway.py
+++ b/meraki/api/campusGateway.py
@@ -96,6 +96,150 @@ def updateNetworkCampusGatewayCluster(self, networkId: str, clusterId: str, **kw
return self._session.put(metadata, resource, payload)
+ def deleteNetworkCampusGatewayCluster(self, networkId: str, clusterId: str):
+ """
+ **Delete a cluster**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-campus-gateway-cluster
+
+ - networkId (string): Network ID
+ - clusterId (string): Cluster ID
+ """
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters"],
+ "operation": "deleteNetworkCampusGatewayCluster",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clusterId = urllib.parse.quote(str(clusterId), safe="")
+ resource = f"/networks/{networkId}/campusGateway/clusters/{clusterId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getNetworkCampusGatewaySsidMdns(self, networkId: str, number: str):
+ """
+ **List the currently configured mDNS settings for the SSID**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-campus-gateway-ssid-mdns
+
+ - networkId (string): Network ID
+ - number (string): Number
+ """
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "ssids", "mdns"],
+ "operation": "getNetworkCampusGatewaySsidMdns",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/campusGateway/ssids/{number}/mdns"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkCampusGatewaySsidMdns(self, networkId: str, number: str, **kwargs):
+ """
+ **Update the mDNS gateway settings and rules for a SSID and cluster**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-campus-gateway-ssid-mdns
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - enabled (boolean): If true, mDNS gateway is enabled for this SSID and cluster.
+ - rules (array): List of mDNS forwarding rules.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "ssids", "mdns"],
+ "operation": "updateNetworkCampusGatewaySsidMdns",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/campusGateway/ssids/{number}/mdns"
+
+ body_params = [
+ "enabled",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkCampusGatewaySsidMdns: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationCampusGatewayClientsUsageByNetworkByCluster(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns client usage details for campus gateway clusters within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clients-usage-by-network-by-cluster
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - networkIds (array): Filter results by a list of network IDs.
+ - networkGroupIds (array): Limit the results to clients that belong to one of the provided network groups.
+ - clusterIds (array): Filter results by a list of cluster IDs.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "monitor", "clients", "usage", "byNetwork", "byCluster"],
+ "operation": "getOrganizationCampusGatewayClientsUsageByNetworkByCluster",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clients/usage/byNetwork/byCluster"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "networkGroupIds",
+ "clusterIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "clusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClientsUsageByNetworkByCluster: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationCampusGatewayClusters(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Get the details of campus gateway clusters**
@@ -143,6 +287,556 @@ def getOrganizationCampusGatewayClusters(self, organizationId: str, total_pages=
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationCampusGatewayClustersFailoverTargets(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the details of a Failover Targets for a Campus Gateway cluster**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-failover-targets
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - clusterIds (array): Optional parameter to filter clusters. This filter uses multiple exact matches.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "failover", "targets"],
+ "operation": "getOrganizationCampusGatewayClustersFailoverTargets",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/failover/targets"
+
+ query_params = [
+ "networkIds",
+ "clusterIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "clusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersFailoverTargets: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayClustersFailoverTargetsByCluster(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get available backup cluster targets for campus gateway failover configuration**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-failover-targets-by-cluster
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Networks for which backup cluster targets should be gathered.
+ - clusterIds (array): Cluster IDs to filter backup cluster targets.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "failover", "targets", "byCluster"],
+ "operation": "getOrganizationCampusGatewayClustersFailoverTargetsByCluster",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/failover/targets/byCluster"
+
+ query_params = [
+ "networkIds",
+ "clusterIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "clusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersFailoverTargetsByCluster: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayClustersNetworksOverviews(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List networks tunneling through Campus Gateway clusters with their AP, ssids and client counts**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-networks-overviews
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - clusterIds (array): Optional parameter to filter by MCG cluster IDs. This filter uses multiple exact matches.
+ - siteIds (array): Optional parameter to filter by site IDs. This filter uses multiple exact matches.
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - tunnelingSources (array): Optional parameter to filter networks by tunneling source. 'configured' returns networks explicitly set up to tunnel through the campus gateway. 'roaming' returns networks tunneling due to AP roaming or disaster recovery. 'roaming' is only effective when 'clusterIds' is also provided; without 'clusterIds', the filter defaults to configured-only behavior. Defaults to 'configured' if omitted.
+ - search (string): Optional parameter to filter networks by wireless network name. This filter uses case-insensitive substring matching.
+ - sortBy (string): Optional parameter to sort results. Default is 'name'. Use 'siteName' to sort by site name.
+ - sortOrder (string): Optional parameter to specify sort direction. Default is 'asc'.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["clients", "clusterId", "connections", "name", "networkId", "siteName", "ssids"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "networks", "overviews"],
+ "operation": "getOrganizationCampusGatewayClustersNetworksOverviews",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/networks/overviews"
+
+ query_params = [
+ "clusterIds",
+ "siteIds",
+ "networkIds",
+ "tunnelingSources",
+ "search",
+ "sortBy",
+ "sortOrder",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clusterIds",
+ "siteIds",
+ "networkIds",
+ "tunnelingSources",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersNetworksOverviews: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def provisionOrganizationCampusGatewayClusters(
+ self,
+ organizationId: str,
+ clusterId: str,
+ network: dict,
+ name: str,
+ uplinks: list,
+ tunnels: list,
+ nameservers: dict,
+ portChannels: list,
+ **kwargs,
+ ):
+ """
+ **Provisions a cluster,adds campus gateways to it and associate/dissociate failover targets.**
+ https://developer.cisco.com/meraki/api-v1/#!provision-organization-campus-gateway-clusters
+
+ - organizationId (string): Organization ID
+ - clusterId (string): ID of the cluster to be provisioned
+ - network (object): Network to be provisioned
+ - name (string): Name of the new cluster
+ - uplinks (array): Uplink interface settings of the cluster
+ - tunnels (array): Tunnel interface settings of the cluster: Reuse uplink or specify tunnel interface
+ - nameservers (object): Nameservers of the cluster
+ - portChannels (array): Port channel settings of the cluster
+ - devices (array): Devices to be added to the cluster
+ - failover (object): Failover targets for the cluster
+ - notes (string): Notes about cluster with max size of 511 characters allowed
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters"],
+ "operation": "provisionOrganizationCampusGatewayClusters",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/provision"
+
+ body_params = [
+ "clusterId",
+ "network",
+ "name",
+ "uplinks",
+ "tunnels",
+ "nameservers",
+ "portChannels",
+ "devices",
+ "failover",
+ "notes",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"provisionOrganizationCampusGatewayClusters: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationCampusGatewayClustersSsids(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List SSIDs tunneling through Campus Gateway clusters**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-ssids
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - clusterIds (array): Optional parameter to filter by MCG cluster IDs. This filter uses multiple exact matches.
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - search (string): Optional parameter to filter SSIDs by name. This filter uses case-insensitive starts with string matching.
+ - sortBy (string): Optional parameter to sort results. Default is 'networkId'.
+ - sortOrder (string): Optional parameter to specify sort direction. Default is 'asc'.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["clusterId", "name", "networkId", "ssidId"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "ssids"],
+ "operation": "getOrganizationCampusGatewayClustersSsids",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/ssids"
+
+ query_params = [
+ "clusterIds",
+ "networkIds",
+ "search",
+ "sortBy",
+ "sortOrder",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clusterIds",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersSsids: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayClustersTunnelingByClusterByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all the MCG cluster-network tunnel settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-clusters-tunneling-by-cluster-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - clusterIds (array): Optional parameter to filter MCG clusters. This filter uses multiple exact matches
+ - dataEncryptionEnabled (boolean): Optional parameter to filter cluster-network tunnel settings by data encryption configuration
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "tunneling", "byCluster", "byNetwork"],
+ "operation": "getOrganizationCampusGatewayClustersTunnelingByClusterByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/tunneling/byCluster/byNetwork"
+
+ query_params = [
+ "clusterIds",
+ "dataEncryptionEnabled",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clusterIds",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayClustersTunnelingByClusterByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate(self, organizationId: str, **kwargs):
+ """
+ **Update MCG cluster-network tunnel settings for multiple networks**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-campus-gateway-clusters-tunneling-by-cluster-by-network-update
+
+ - organizationId (string): Organization ID
+ - items (array): MCG cluster-network tunnel settings
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "clusters", "tunneling", "byCluster", "byNetwork"],
+ "operation": "batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/clusters/tunneling/byCluster/byNetwork/batchUpdate"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchOrganizationCampusGatewayClustersTunnelingByClusterByNetworkUpdate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationCampusGatewayConnections(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the details of APs tunneling through the Campus Gateway clusters**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-connections
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter connections(APs) by its own serials. This filter uses multiple exact matches.
+ - campusGatewaySerials (array): Optional parameter to filter connections(APs) by MCG serials. This filter uses multiple exact matches.
+ - campusGatewayClusterIds (array): Optional parameter to filter connections(APs) by MCG cluster IDs. This filter uses multiple exact matches.
+ - campusGatewayTunnelStatuses (array): Optional parameter to filter connections(APs) by tunnel statuses. This filter uses multiple exact matches.
+ - search (string): Optional parameter to filter connections(APs) on AP name, serial, MAC address, network name, or interface IP address. This filter uses partial string matching (ILIKE).
+ - models (array): Optional parameter to filter connections(APs) by device model names. This filter uses multiple exact matches.
+ - dataEncryptionStatuses (array): Optional parameter to filter connections(APs) by data encryption status. This filter uses multiple exact matches.
+ - sortBy (string): Optional parameter to sort results. Available options: name, serial, status, interfaces, clients, dataEncryption, networkName. Default is 'serial'.
+ - sortOrder (string): Optional parameter to specify sort direction. Default is 'asc'.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["clients", "dataEncryption", "interfaces", "name", "networkName", "serial", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "connections"],
+ "operation": "getOrganizationCampusGatewayConnections",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/connections"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "search",
+ "models",
+ "dataEncryptionStatuses",
+ "sortBy",
+ "sortOrder",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "models",
+ "dataEncryptionStatuses",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayConnections: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationCampusGatewayConnectionsOverview(self, organizationId: str, **kwargs):
+ """
+ **List the count of connections(APs) with tunneling status up and down through the Campus Gateway clusters**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-campus-gateway-connections-overview
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter networks. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter connections(APs) by its own serials. This filter uses multiple exact matches.
+ - campusGatewaySerials (array): Optional parameter to filter connections(APs) by Campus Gateway serials. This filter uses multiple exact matches.
+ - campusGatewayClusterIds (array): Optional parameter to filter connections(APs) by Campus Gateway cluster IDs. This filter uses multiple exact matches.
+ - campusGatewayTunnelStatuses (array): Optional parameter to filter connections(APs) by tunnel statuses. This filter uses multiple exact matches.
+ - search (string): Optional setting that lets you filter access points (APs) by name, serial number, MAC address, network name, or interface IP address. The filter matches partial text, not just exact values (uses ILIKE matching).
+ - models (array): Optional parameter to filter connections(APs) by device model names. This filter uses multiple exact matches.
+ - dataEncryptionStatuses (array): Optional parameter to filter connections(APs) by data encryption status. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["campusGateway", "configure", "connections", "overview"],
+ "operation": "getOrganizationCampusGatewayConnectionsOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/campusGateway/connections/overview"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "search",
+ "models",
+ "dataEncryptionStatuses",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "campusGatewaySerials",
+ "campusGatewayClusterIds",
+ "campusGatewayTunnelStatuses",
+ "models",
+ "dataEncryptionStatuses",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCampusGatewayConnectionsOverview: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
def getOrganizationCampusGatewayDevicesUplinksLocalOverridesByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
diff --git a/meraki/api/devices.py b/meraki/api/devices.py
index 4babf70f..8a436051 100644
--- a/meraki/api/devices.py
+++ b/meraki/api/devices.py
@@ -232,6 +232,56 @@ def createDeviceCellularUplinksBandsMasksUpdate(self, serial: str, slot: str, ty
return self._session.post(metadata, resource, payload)
+ def revokeDeviceCertificate(self, serial: str, certificateSerial: str, **kwargs):
+ """
+ **Revoke a device certificate**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-device-certificate
+
+ - serial (string): Serial
+ - certificateSerial (string): Certificate serial
+ - reason (string): Revocation reason per RFC 5280; omit to use `unspecified`
+ """
+
+ kwargs.update(locals())
+
+ if "reason" in kwargs:
+ options = [
+ "aACompromise",
+ "affiliationChanged",
+ "cACompromise",
+ "certificateHold",
+ "cessationOfOperation",
+ "keyCompromise",
+ "privilegeWithdrawn",
+ "removeFromCRL",
+ "superseded",
+ "unspecified",
+ ]
+ assert kwargs["reason"] in options, (
+ f'''"reason" cannot be "{kwargs["reason"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["devices", "configure", "certificates"],
+ "operation": "revokeDeviceCertificate",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ certificateSerial = urllib.parse.quote(str(certificateSerial), safe="")
+ resource = f"/devices/{serial}/certificates/{certificateSerial}/revoke"
+
+ body_params = [
+ "reason",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"revokeDeviceCertificate: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
def getDeviceClients(self, serial: str, **kwargs):
"""
**List the clients of a device, up to a maximum of a month ago**
@@ -265,6 +315,56 @@ def getDeviceClients(self, serial: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def createDeviceLiveToolsAclHitCount(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform an ACL hit count for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-acl-hit-count
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "aclHitCount"],
+ "operation": "createDeviceLiveToolsAclHitCount",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/aclHitCount"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsAclHitCount: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsAclHitCount(self, serial: str, id: str):
+ """
+ **Return an ACL hit count live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-acl-hit-count
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "aclHitCount"],
+ "operation": "getDeviceLiveToolsAclHitCount",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/aclHitCount/{id}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsArpTable(self, serial: str, **kwargs):
"""
**Enqueue a job to perform a ARP table request for the device**
@@ -367,6 +467,75 @@ def getDeviceLiveToolsCableTest(self, serial: str, id: str):
return self._session.get(metadata, resource)
+ def getDeviceLiveToolsClientsDisconnect(self, serial: str, id: str):
+ """
+ **Return a client disconnect job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-clients-disconnect
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "clients", "disconnect"],
+ "operation": "getDeviceLiveToolsClientsDisconnect",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/clients/disconnect/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsDhcpLease(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a DHCP leases request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-dhcp-lease
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "dhcpLeases"],
+ "operation": "createDeviceLiveToolsDhcpLease",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/dhcpLeases"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsDhcpLease: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsDhcpLease(self, serial: str, dhcpLeasesId: str):
+ """
+ **Return a DHCP leases live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-dhcp-lease
+
+ - serial (string): Serial
+ - dhcpLeasesId (string): Dhcp leases ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "dhcpLeases"],
+ "operation": "getDeviceLiveToolsDhcpLease",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ dhcpLeasesId = urllib.parse.quote(str(dhcpLeasesId), safe="")
+ resource = f"/devices/{serial}/liveTools/dhcpLeases/{dhcpLeasesId}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsLedsBlink(self, serial: str, duration: int, **kwargs):
"""
**Enqueue a job to blink LEDs on a device**
@@ -425,6 +594,7 @@ def createDeviceLiveToolsMacTable(self, serial: str, **kwargs):
https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-mac-table
- serial (string): Serial
+ - mac (string): Optional parameter to filter MAC table entries by MAC address. Must be a colon-delimited six-octet MAC address, for example '00:11:22:a0:b1:c2'. Matching is case-insensitive.
- callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
"""
@@ -438,6 +608,7 @@ def createDeviceLiveToolsMacTable(self, serial: str, **kwargs):
resource = f"/devices/{serial}/liveTools/macTable"
body_params = [
+ "mac",
"callback",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -521,6 +692,56 @@ def getDeviceLiveToolsMulticastRouting(self, serial: str, multicastRoutingId: st
return self._session.get(metadata, resource)
+ def createDeviceLiveToolsOspfNeighbor(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a OSPF neighbors request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ospf-neighbor
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "ospfNeighbors"],
+ "operation": "createDeviceLiveToolsOspfNeighbor",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/ospfNeighbors"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsOspfNeighbor: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsOspfNeighbor(self, serial: str, ospfNeighborsId: str):
+ """
+ **Return an OSPF neighbors live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ospf-neighbor
+
+ - serial (string): Serial
+ - ospfNeighborsId (string): Ospf neighbors ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "ospfNeighbors"],
+ "operation": "getDeviceLiveToolsOspfNeighbor",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ ospfNeighborsId = urllib.parse.quote(str(ospfNeighborsId), safe="")
+ resource = f"/devices/{serial}/liveTools/ospfNeighbors/{ospfNeighborsId}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsPing(self, serial: str, target: str, **kwargs):
"""
**Enqueue a job to ping a target host from the device**
@@ -779,6 +1000,89 @@ def getDeviceLiveToolsPowerUsage(self, serial: str, jobId: str):
return self._session.get(metadata, resource)
+ def createDeviceLiveToolsReboot(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to reboot a device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-reboot
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "reboot"],
+ "operation": "createDeviceLiveToolsReboot",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/reboot"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsReboot: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsReboot(self, serial: str, rebootId: str):
+ """
+ **Return a reboot job**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-reboot
+
+ - serial (string): Serial
+ - rebootId (string): Reboot ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "reboot"],
+ "operation": "getDeviceLiveToolsReboot",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ rebootId = urllib.parse.quote(str(rebootId), safe="")
+ resource = f"/devices/{serial}/liveTools/reboot/{rebootId}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsRoutingTable(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a routing table request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table
+
+ - serial (string): Serial
+ - destination (object): Optional destination filter used to return routes containing the supplied destination.
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "routingTable"],
+ "operation": "createDeviceLiveToolsRoutingTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/routingTable"
+
+ body_params = [
+ "destination",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsRoutingTable: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs):
"""
**Enqueue a job to perform a routing table lookup request for a device**
@@ -911,6 +1215,81 @@ def getDeviceLiveToolsRoutingTableSummary(self, serial: str, id: str):
return self._session.get(metadata, resource)
+ def getDeviceLiveToolsRoutingTable(self, serial: str, id: str):
+ """
+ **Return an routing table live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-routing-table
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "routingTable"],
+ "operation": "getDeviceLiveToolsRoutingTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/routingTable/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsSpeedTest(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to execute a speed test from a device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-speed-test
+
+ - serial (string): Serial
+ - interface (string): Optional filter for a specific WAN interface. Valid interfaces are wan1, wan2, wan3, wan4. Default will return wan1.
+ """
+
+ kwargs.update(locals())
+
+ if "interface" in kwargs:
+ options = ["wan1", "wan2", "wan3", "wan4"]
+ assert kwargs["interface"] in options, (
+ f'''"interface" cannot be "{kwargs["interface"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["devices", "liveTools", "speedTest"],
+ "operation": "createDeviceLiveToolsSpeedTest",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/speedTest"
+
+ body_params = [
+ "interface",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsSpeedTest: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsSpeedTest(self, serial: str, id: str):
+ """
+ **Returns a speed test result in megabits per second**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-speed-test
+
+ - serial (string): Serial
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "speedTest"],
+ "operation": "getDeviceLiveToolsSpeedTest",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/devices/{serial}/liveTools/speedTest/{id}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsThroughputTest(self, serial: str, **kwargs):
"""
**Enqueue a job to test a device throughput, the test will run for 10 secs to test throughput**
@@ -961,6 +1340,110 @@ def getDeviceLiveToolsThroughputTest(self, serial: str, throughputTestId: str):
return self._session.get(metadata, resource)
+ def createDeviceLiveToolsTraceRoute(self, serial: str, target: str, sourceInterface: str, **kwargs):
+ """
+ **Enqueue a job to run trace route in the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-trace-route
+
+ - serial (string): Serial
+ - target (string): Destination Host name or address
+ - sourceInterface (string): Source Interface IP address
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "traceRoute"],
+ "operation": "createDeviceLiveToolsTraceRoute",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/traceRoute"
+
+ body_params = [
+ "target",
+ "sourceInterface",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsTraceRoute: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsTraceRoute(self, serial: str, traceRouteId: str):
+ """
+ **Return a trace route job**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-trace-route
+
+ - serial (string): Serial
+ - traceRouteId (string): Trace route ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "traceRoute"],
+ "operation": "getDeviceLiveToolsTraceRoute",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ traceRouteId = urllib.parse.quote(str(traceRouteId), safe="")
+ resource = f"/devices/{serial}/liveTools/traceRoute/{traceRouteId}"
+
+ return self._session.get(metadata, resource)
+
+ def createDeviceLiveToolsVrrpTable(self, serial: str, **kwargs):
+ """
+ **Enqueue a job to perform a VRRP table request for the device**
+ https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-vrrp-table
+
+ - serial (string): Serial
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["devices", "liveTools", "vrrpTable"],
+ "operation": "createDeviceLiveToolsVrrpTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/liveTools/vrrpTable"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createDeviceLiveToolsVrrpTable: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getDeviceLiveToolsVrrpTable(self, serial: str, vrrpTableId: str):
+ """
+ **Return an VRRP table live tool job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-vrrp-table
+
+ - serial (string): Serial
+ - vrrpTableId (string): Vrrp table ID
+ """
+
+ metadata = {
+ "tags": ["devices", "liveTools", "vrrpTable"],
+ "operation": "getDeviceLiveToolsVrrpTable",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ vrrpTableId = urllib.parse.quote(str(vrrpTableId), safe="")
+ resource = f"/devices/{serial}/liveTools/vrrpTable/{vrrpTableId}"
+
+ return self._session.get(metadata, resource)
+
def createDeviceLiveToolsWakeOnLan(self, serial: str, vlanId: int, mac: str, **kwargs):
"""
**Enqueue a job to send a Wake-on-LAN packet from the device**
diff --git a/meraki/api/insight.py b/meraki/api/insight.py
index 79b02839..08b7cb4b 100644
--- a/meraki/api/insight.py
+++ b/meraki/api/insight.py
@@ -64,6 +64,95 @@ def getOrganizationInsightApplications(self, organizationId: str):
return self._session.get(metadata, resource)
+ def createOrganizationInsightApplication(self, organizationId: str, counterSetRuleId: int, **kwargs):
+ """
+ **Add an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - counterSetRuleId (integer): The id of the counter set rule
+ - enableSmartThresholds (boolean): Enable Smart Thresholds
+ - thresholds (object): Thresholds defined by a user for each application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "applications"],
+ "operation": "createOrganizationInsightApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications"
+
+ body_params = [
+ "counterSetRuleId",
+ "enableSmartThresholds",
+ "thresholds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationInsightApplication: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationInsightApplication(self, organizationId: str, applicationId: str, **kwargs):
+ """
+ **Update an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - applicationId (string): Application ID
+ - enableSmartThresholds (boolean): Enable Smart Thresholds
+ - thresholds (object): Thresholds defined by a user for each application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "applications"],
+ "operation": "updateOrganizationInsightApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ applicationId = urllib.parse.quote(str(applicationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications/{applicationId}"
+
+ body_params = [
+ "enableSmartThresholds",
+ "thresholds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationInsightApplication: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationInsightApplication(self, organizationId: str, applicationId: str):
+ """
+ **Delete an Insight tracked application**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-insight-application
+
+ - organizationId (string): Organization ID
+ - applicationId (string): Application ID
+ """
+
+ metadata = {
+ "tags": ["insight", "configure", "applications"],
+ "operation": "deleteOrganizationInsightApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ applicationId = urllib.parse.quote(str(applicationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/applications/{applicationId}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationInsightMonitoredMediaServers(self, organizationId: str):
"""
**List the monitored media servers for this organization**
@@ -194,3 +283,154 @@ def deleteOrganizationInsightMonitoredMediaServer(self, organizationId: str, mon
resource = f"/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}"
return self._session.delete(metadata, resource)
+
+ def getOrganizationInsightSpeedTestResults(self, organizationId: str, serials: list, **kwargs):
+ """
+ **List the speed tests for the given devices under this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-insight-speed-test-results
+
+ - organizationId (string): Organization ID
+ - serials (array): A list of serial numbers. The returned results will be filtered to only include these serials.
+ - timespan (integer): Amount of seconds ago to query for results. Only include timespan OR both t0 & t1.
+ - t0 (integer): Start time to query for results in epoch seconds. Only include timespan OR both t0 & t1.
+ - t1 (integer): End time to query for results in epoch seconds. Only include timespan OR both t0 & t1.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "speedTestResults"],
+ "operation": "getOrganizationInsightSpeedTestResults",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/speedTestResults"
+
+ query_params = [
+ "serials",
+ "timespan",
+ "t0",
+ "t1",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationInsightSpeedTestResults: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationInsightWebApps(self, organizationId: str):
+ """
+ **Lists all default web applications rules with counter set rule ids**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-insight-web-apps
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "getOrganizationInsightWebApps",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationInsightWebApp(self, organizationId: str, name: str, hostname: str, **kwargs):
+ """
+ **Add a custom web application for Insight to be able to track**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the Web Application
+ - hostname (string): The hostname of Web Application
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "createOrganizationInsightWebApp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps"
+
+ body_params = [
+ "name",
+ "hostname",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationInsightWebApp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationInsightWebApp(self, organizationId: str, customCounterSetRuleId: str, **kwargs):
+ """
+ **Update a custom web application for Insight to be able to track**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - customCounterSetRuleId (string): Custom counter set rule ID
+ - name (string): The name of the Web Application
+ - hostname (string): The hostname of Web Application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "updateOrganizationInsightWebApp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ customCounterSetRuleId = urllib.parse.quote(str(customCounterSetRuleId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps/{customCounterSetRuleId}"
+
+ body_params = [
+ "name",
+ "hostname",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationInsightWebApp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationInsightWebApp(self, organizationId: str, customCounterSetRuleId: str):
+ """
+ **Delete a custom web application by counter set rule id.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-insight-web-app
+
+ - organizationId (string): Organization ID
+ - customCounterSetRuleId (string): Custom counter set rule ID
+ """
+
+ metadata = {
+ "tags": ["insight", "configure", "webApps"],
+ "operation": "deleteOrganizationInsightWebApp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ customCounterSetRuleId = urllib.parse.quote(str(customCounterSetRuleId), safe="")
+ resource = f"/organizations/{organizationId}/insight/webApps/{customCounterSetRuleId}"
+
+ return self._session.delete(metadata, resource)
diff --git a/meraki/api/licensing.py b/meraki/api/licensing.py
index df89824b..5911aa63 100644
--- a/meraki/api/licensing.py
+++ b/meraki/api/licensing.py
@@ -45,6 +45,39 @@ def getAdministeredLicensingSubscriptionEntitlements(self, **kwargs):
return self._session.get(metadata, resource, params)
+ def batchAdministeredLicensingSubscriptionNetworksFeatureTiersUpdate(self, **kwargs):
+ """
+ **Batch change networks to their desired feature tier for specified product types**
+ https://developer.cisco.com/meraki/api-v1/#!batch-administered-licensing-subscription-networks-feature-tiers-update
+
+ - items (array): List of networks and corresponding product types to update. Maximum 500 networks
+ - isAtomic (boolean): Flag to determine if the operation should act atomically
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["licensing", "configure", "subscription", "featureTiers"],
+ "operation": "batchAdministeredLicensingSubscriptionNetworksFeatureTiersUpdate",
+ }
+ resource = "/administered/licensing/subscription/networks/featureTiers/batchUpdate"
+
+ body_params = [
+ "items",
+ "isAtomic",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchAdministeredLicensingSubscriptionNetworksFeatureTiersUpdate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getAdministeredLicensingSubscriptionSubscriptions(
self, organizationIds: list, total_pages=1, direction="next", **kwargs
):
diff --git a/meraki/api/nac.py b/meraki/api/nac.py
new file mode 100644
index 00000000..067cc48e
--- /dev/null
+++ b/meraki/api/nac.py
@@ -0,0 +1,1151 @@
+import urllib
+
+
+class Nac(object):
+ def __init__(self, session):
+ super(Nac, self).__init__()
+ self._session = session
+
+ def getOrganizationNacAuthorizationPolicies(self, organizationId: str, **kwargs):
+ """
+ **Get all nac authorization policies for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-authorization-policies
+
+ - organizationId (string): Organization ID
+ - policyIds (array): List of ids for specific authorization policies retrieval
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies"],
+ "operation": "getOrganizationNacAuthorizationPolicies",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies"
+
+ query_params = [
+ "policyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "policyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacAuthorizationPolicies: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def createOrganizationNacAuthorizationPolicyRule(
+ self, organizationId: str, policyId: str, name: str, rank: int, authorizationProfile: dict, **kwargs
+ ):
+ """
+ **Create a rule in an authorization policy set of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-authorization-policy-rule
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - name (string): Name of Authorization rule
+ - rank (integer): Rank of Authorization rule
+ - authorizationProfile (object): Authorization profile associated with the rule
+ - enabled (boolean): Enabled status of authorization rule. Default is False.
+ - sourcePolicyVersion (string): Source policy version of the policy set containing this rule
+ - condition (object): Condition of Authorization rule.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies", "rules"],
+ "operation": "createOrganizationNacAuthorizationPolicyRule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies/{policyId}/rules"
+
+ body_params = [
+ "name",
+ "rank",
+ "enabled",
+ "sourcePolicyVersion",
+ "authorizationProfile",
+ "condition",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacAuthorizationPolicyRule: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationNacAuthorizationPolicyRule(
+ self, organizationId: str, policyId: str, ruleId: str, name: str, rank: int, authorizationProfile: dict, **kwargs
+ ):
+ """
+ **Update an existing rule of an authorization policy set within an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-authorization-policy-rule
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - name (string): Name of Authorization rule
+ - rank (integer): Rank of Authorization rule
+ - authorizationProfile (object): Authorization profile associated with the rule
+ - enabled (boolean): Enabled status of authorization rule. Default is False.
+ - sourcePolicyVersion (string): Source policy version of the policy set containing this rule
+ - condition (object): Condition of Authorization rule.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies", "rules"],
+ "operation": "updateOrganizationNacAuthorizationPolicyRule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies/{policyId}/rules/{ruleId}"
+
+ body_params = [
+ "name",
+ "rank",
+ "enabled",
+ "sourcePolicyVersion",
+ "authorizationProfile",
+ "condition",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationNacAuthorizationPolicyRule: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationNacAuthorizationPolicyRule(self, organizationId: str, policyId: str, ruleId: str, **kwargs):
+ """
+ **Delete a rule in an authorization policy set of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-authorization-policy-rule
+
+ - organizationId (string): Organization ID
+ - policyId (string): Policy ID
+ - ruleId (string): Rule ID
+ - sourcePolicyVersion (string): Source policy version of the policy set containing this rule
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "authorization", "policies", "rules"],
+ "operation": "deleteOrganizationNacAuthorizationPolicyRule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ policyId = urllib.parse.quote(str(policyId), safe="")
+ ruleId = urllib.parse.quote(str(ruleId), safe="")
+ resource = f"/organizations/{organizationId}/nac/authorization/policies/{policyId}/rules/{ruleId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationNacCertificates(self, organizationId: str, **kwargs):
+ """
+ **Gets all certificates for an organization and can filter by certificate status, expiry date and last used date**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates
+
+ - organizationId (string): Organization ID
+ - status (string): Status Parameter for GetAll request
+ - expiry (boolean): Boolean indicating whether to filter by expiry in one month
+ - lastUsed (boolean): Boolean indicating whether to filter by last used in over one month
+ """
+
+ kwargs.update(locals())
+
+ if "status" in kwargs:
+ options = ["Disabled", "Enabled"]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates"],
+ "operation": "getOrganizationNacCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates"
+
+ query_params = [
+ "status",
+ "expiry",
+ "lastUsed",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacCertificatesAuthoritiesCrls(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get all the organization's CRL.It's possible to filter results by CRL issuers (CA) or CRL's ID - see caIds and crlIds query parameters.This endpoint could be used for 'show' action when you specify a single CRL ID in crlIds parameter**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates-authorities-crls
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 5.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortBy (string): Optional parameter to specify the field used to sort results. (default: caId)
+ - sortOrder (string): Optional parameter to specify the sort order. (default: asc)
+ - crlIds (array): A list of CRL ids. The returned CRLs will be filtered to only include these ids
+ - caIds (array): When ca Ids are provided, only CRLs associated to the given CA will be returned. Otherwise, all the CRLs created for an organization will be returned.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["caId", "createdAt", "lastUpdatedAt"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls"],
+ "operation": "getOrganizationNacCertificatesAuthoritiesCrls",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortBy",
+ "sortOrder",
+ "crlIds",
+ "caIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "crlIds",
+ "caIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacCertificatesAuthoritiesCrls: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNacCertificatesAuthoritiesCrl(
+ self, organizationId: str, caId: str, content: str, isDelta: bool, **kwargs
+ ):
+ """
+ **Create a new CRL (either base or delta) for an existing CA**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-certificates-authorities-crl
+
+ - organizationId (string): Organization ID
+ - caId (string): ID of the CRL issuer
+ - content (string): CRL content in PEM format
+ - isDelta (boolean): Whether it's a delta CRL or not
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls"],
+ "operation": "createOrganizationNacCertificatesAuthoritiesCrl",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls"
+
+ body_params = [
+ "caId",
+ "content",
+ "isDelta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacCertificatesAuthoritiesCrl: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNacCertificatesAuthoritiesCrlsDescriptors(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get all the organization's CRL descriptors (metadata only - revocation list data is excluded)**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates-authorities-crls-descriptors
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortBy (string): Optional parameter to specify the field used to sort results. (default: caId)
+ - sortOrder (string): Optional parameter to specify the sort order. (default: asc)
+ - caIds (array): When ca Ids are provided, only CRLs associated to the given CA will be returned. Otherwise, all the CRLs created for an organization will be returned.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["caId", "createdAt", "lastUpdatedAt"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls", "descriptors"],
+ "operation": "getOrganizationNacCertificatesAuthoritiesCrlsDescriptors",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls/descriptors"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortBy",
+ "sortOrder",
+ "caIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "caIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacCertificatesAuthoritiesCrlsDescriptors: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationNacCertificatesAuthoritiesCrl(self, organizationId: str, crlId: str):
+ """
+ **Deletes a whole CRL, including all its deltas (in case of base CRL removal)**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-certificates-authorities-crl
+
+ - organizationId (string): Organization ID
+ - crlId (string): Crl ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "authorities", "crls"],
+ "operation": "deleteOrganizationNacCertificatesAuthoritiesCrl",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ crlId = urllib.parse.quote(str(crlId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/authorities/crls/{crlId}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationNacCertificatesImport(self, organizationId: str, contents: str, **kwargs):
+ """
+ **Import certificate for this organization or validate without persisting**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-certificates-import
+
+ - organizationId (string): Organization ID
+ - contents (string): Certificate content in valid PEM format
+ - dryRun (boolean): If true, validates the certificate without persisting it
+ - profile (object): Profile object containing certificate config fields
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "import"],
+ "operation": "createOrganizationNacCertificatesImport",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/import"
+
+ body_params = [
+ "contents",
+ "dryRun",
+ "profile",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacCertificatesImport: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNacCertificatesOverview(self, organizationId: str):
+ """
+ **Get counts of Enabled, Disabled, Expired and Last Used certificates for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-certificates-overview
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates", "overview"],
+ "operation": "getOrganizationNacCertificatesOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/overview"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationNacCertificate(self, organizationId: str, certificateId: str, profile: dict, **kwargs):
+ """
+ **Update certificate configuration by certificateId for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-certificate
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ - profile (object): Profile object containing certificate config fields
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "certificates"],
+ "operation": "updateOrganizationNacCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/nac/certificates/{certificateId}"
+
+ body_params = [
+ "profile",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNacCertificate: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationNacClients(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get all known clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-clients
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - sortOrder (string): Query parameter for specifying the direction of sorting to use for the given sortKey.
+ - sortKey (string): Query parameter to sort the clients by the value of the specified key.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): Optional parameter to fuzzy search on clients.
+ - clientIds (array): List of ids for specific client retrieval
+ - groupIds (array): List of group ids for client retrieval by group
+ - lastNetworkName (array): List of network names for client retrieval by last login network name
+ - ssid (array): List of SSID's to filter
+ - classification (object): Classification filters for client retrieval
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ASC", "DESC"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = ["mac"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "getOrganizationNacClients",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients"
+
+ query_params = [
+ "sortOrder",
+ "sortKey",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "clientIds",
+ "groupIds",
+ "lastNetworkName",
+ "ssid",
+ "classification",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clientIds",
+ "groupIds",
+ "lastNetworkName",
+ "ssid",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacClients: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNacClient(self, organizationId: str, mac: str, **kwargs):
+ """
+ **Create a client for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-client
+
+ - organizationId (string): Organization ID
+ - mac (string): The MAC address of the client
+ - type (string): Type describes if the network client belongs to an individual user or corporate
+ - owner (string): The username of the owner of the client
+ - description (string): User provided description for the client
+ - uuid (string): Universally unique identifier of the client
+ - userDetails (array): List of users of this network client
+ - oui (object): Organizationally unique identifier assigned to a vendor of the client
+ - groups (array): List of group members associated with the client
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["BYOD", "corporate"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "createOrganizationNacClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients"
+
+ body_params = [
+ "type",
+ "owner",
+ "mac",
+ "description",
+ "uuid",
+ "userDetails",
+ "oui",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNacClient: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def bulkOrganizationNacClientsDelete(self, organizationId: str, clientIds: list, **kwargs):
+ """
+ **Delete existing client(s) for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-nac-clients-delete
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of ids for specific client retrieval
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "bulkOrganizationNacClientsDelete",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkDelete"
+
+ body_params = [
+ "clientIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"bulkOrganizationNacClientsDelete: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationNacClientsBulkEdit(self, organizationId: str, clientIds: list, **kwargs):
+ """
+ **Bulk Update of existing clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-bulk-edit
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of clients ids to apply the bulk edit operation on.
+ - description (string): User provided description to be applied on the list of clients provided
+ - groups (object): Client group information to be applied on the list of clients provided
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "bulkEdit"],
+ "operation": "createOrganizationNacClientsBulkEdit",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkEdit"
+
+ body_params = [
+ "clientIds",
+ "description",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNacClientsBulkEdit: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationNacClientsBulkUpload(
+ self, organizationId: str, contents: str, updateClients: bool, createClientGroups: bool, **kwargs
+ ):
+ """
+ **Bulk upload of clients, client groups and their associations for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-bulk-upload
+
+ - organizationId (string): Organization ID
+ - contents (string): CSV file content in Base64 encoded string format
+ - updateClients (boolean): The updateClients indicates whether existing clients must be updated with new data from the CSV
+ - createClientGroups (boolean): The createClientGroups indicates whether new client groups must be created or not
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "bulkUpload"],
+ "operation": "createOrganizationNacClientsBulkUpload",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/bulkUpload"
+
+ body_params = [
+ "contents",
+ "updateClients",
+ "createClientGroups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationNacClientsBulkUpload: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNacClientsGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get all known client groups for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-clients-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - sortOrder (string): Query parameter for specifying the direction of sorting to use for the given sortKey.
+ - sortKey (string): Query parameter to sort the client groups by the value of the specified key.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): Optional parameter to fuzzy search on client groups.
+ - groupIds (array): List of ids for specific group retrieval
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ASC", "DESC"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = ["name"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "getOrganizationNacClientsGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups"
+
+ query_params = [
+ "sortOrder",
+ "sortKey",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "groupIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "groupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacClientsGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNacClientsGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a client group for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the group for access control model
+ - description (string): User provided description of the group
+ - members (array): List of client members associated with the group
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "createOrganizationNacClientsGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups"
+
+ body_params = [
+ "name",
+ "description",
+ "members",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNacClientsGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationNacClientsGroup(self, organizationId: str, groupId: str, **kwargs):
+ """
+ **Update an existing client group for the organization with bulk member operations**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - name (string): The name of the group for access control model
+ - description (string): User provided description of the group
+ - members (object): Bulk member operations with addList/removeList arrays
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "updateOrganizationNacClientsGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups/{groupId}"
+
+ body_params = [
+ "name",
+ "description",
+ "members",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNacClientsGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationNacClientsGroup(self, organizationId: str, groupId: str):
+ """
+ **Delete an existing client group for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-nac-clients-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "groups"],
+ "operation": "deleteOrganizationNacClientsGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/groups/{groupId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationNacClientsOverview(self, organizationId: str):
+ """
+ **Get overview data for all known clients for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-clients-overview
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "clients", "overview"],
+ "operation": "getOrganizationNacClientsOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/overview"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationNacClient(self, organizationId: str, clientId: str, mac: str, **kwargs):
+ """
+ **Update an existing client for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-nac-client
+
+ - organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - mac (string): The MAC address of the client
+ - type (string): Type describes if the network client belongs to an individual user or corporate
+ - owner (string): The username of the owner of the client
+ - description (string): User provided description for the client
+ - uuid (string): Universally unique identifier of the client
+ - userDetails (array): List of users of this network client
+ - oui (object): Organizationally unique identifier assigned to a vendor of the client
+ - groups (object): Client group membership changes
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["BYOD", "corporate"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["nac", "configure", "clients"],
+ "operation": "updateOrganizationNacClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/organizations/{organizationId}/nac/clients/{clientId}"
+
+ body_params = [
+ "type",
+ "owner",
+ "mac",
+ "description",
+ "uuid",
+ "userDetails",
+ "oui",
+ "groups",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNacClient: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationNacDictionaries(self, organizationId: str):
+ """
+ **Get all NAC dictionaries**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-dictionaries
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "dictionaries"],
+ "operation": "getOrganizationNacDictionaries",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/dictionaries"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationNacDictionaryAttributes(self, organizationId: str, dictionaryId: str, **kwargs):
+ """
+ **Get all attributes by dictionary ID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-dictionary-attributes
+
+ - organizationId (string): Organization ID
+ - dictionaryId (string): Dictionary ID
+ - networkIds (array): An optional list of network IDs to filter the 'enum' field. Only enum values applicable to the specified networks will be returned.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "dictionaries", "attributes"],
+ "operation": "getOrganizationNacDictionaryAttributes",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ dictionaryId = urllib.parse.quote(str(dictionaryId), safe="")
+ resource = f"/organizations/{organizationId}/nac/dictionaries/{dictionaryId}/attributes"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacDictionaryAttributes: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacDictionaryAttributeValues(
+ self, organizationId: str, dictionaryId: str, attributeName: str, **kwargs
+ ):
+ """
+ **Search allowed values for a dictionary attribute**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-dictionary-attribute-values
+
+ - organizationId (string): Organization ID
+ - dictionaryId (string): Dictionary ID
+ - attributeName (string): Attribute name
+ - search (string): Optional search string for contains-match filtering of allowed values
+ - networkIds (array): An optional list of network IDs to filter the allowed values.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "dictionaries", "attributes", "values"],
+ "operation": "getOrganizationNacDictionaryAttributeValues",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ dictionaryId = urllib.parse.quote(str(dictionaryId), safe="")
+ attributeName = urllib.parse.quote(str(attributeName), safe="")
+ resource = f"/organizations/{organizationId}/nac/dictionaries/{dictionaryId}/attributes/{attributeName}/values"
+
+ query_params = [
+ "search",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNacDictionaryAttributeValues: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacLicenseUsage(self, organizationId: str, startDate: str, **kwargs):
+ """
+ **Returns license usage data for a specific organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-license-usage
+
+ - organizationId (string): Organization ID
+ - startDate (string): Start date for the usage data in UTC timezone
+ - endDate (string): End date for the usage data in UTC timezone
+ - networkIds (array): List of locale and node group ids
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "license", "usage"],
+ "operation": "getOrganizationNacLicenseUsage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/license/usage"
+
+ query_params = [
+ "startDate",
+ "endDate",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacLicenseUsage: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationNacSessionsHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the NAC Sessions for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-sessions-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 hour.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["nac", "configure", "sessions", "history"],
+ "operation": "getOrganizationNacSessionsHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/nac/sessions/history"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNacSessionsHistory: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationNacSessionDetails(self, organizationId: str, sessionId: str):
+ """
+ **Return the details of selected NAC Sessions**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-nac-session-details
+
+ - organizationId (string): Organization ID
+ - sessionId (string): Session ID
+ """
+
+ metadata = {
+ "tags": ["nac", "configure", "sessions", "details"],
+ "operation": "getOrganizationNacSessionDetails",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ sessionId = urllib.parse.quote(str(sessionId), safe="")
+ resource = f"/organizations/{organizationId}/nac/sessions/{sessionId}/details"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/api/networks.py b/meraki/api/networks.py
index c1858a71..73107503 100644
--- a/meraki/api/networks.py
+++ b/meraki/api/networks.py
@@ -855,6 +855,23 @@ def vmxNetworkDevicesClaim(self, networkId: str, size: str, **kwargs):
return self._session.post(metadata, resource, payload)
+ def getNetworkDevicesJson(self, networkId: str):
+ """
+ **Extraction of the legacy nodes JSON endpoint for a network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-devices-json
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "devices", "json"],
+ "operation": "getNetworkDevicesJson",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/devices/json"
+
+ return self._session.get(metadata, resource)
+
def removeNetworkDevices(self, networkId: str, serial: str, **kwargs):
"""
**Remove a single device**
@@ -1486,6 +1503,7 @@ def createNetworkFloorPlan(self, networkId: str, name: str, imageContents: str,
- topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan.
- topRightCorner (object): The longitude and latitude of the top right corner of your floor plan.
- floorNumber (number): The floor number of the floors within the building
+ - buildingId (string): The ID of the building that this floor belongs to.
"""
kwargs.update(locals())
@@ -1505,6 +1523,7 @@ def createNetworkFloorPlan(self, networkId: str, name: str, imageContents: str,
"topLeftCorner",
"topRightCorner",
"floorNumber",
+ "buildingId",
"imageContents",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1701,6 +1720,7 @@ def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
- topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan.
- topRightCorner (object): The longitude and latitude of the top right corner of your floor plan.
- floorNumber (number): The floor number of the floors within the building
+ - buildingId (string): The ID of the building that this floor belongs to.
- imageContents (string): The file contents (a base 64 encoded string) of your new image. Supported formats are PNG, GIF, and JPG. Note that all images are saved as PNG files, regardless of the format they are uploaded in. If you upload a new image, and you do NOT specify any new geolocation fields ('center, 'topLeftCorner', etc), the floor plan will be recentered with no rotation in order to maintain the aspect ratio of your new image.
"""
@@ -1722,6 +1742,7 @@ def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
"topLeftCorner",
"topRightCorner",
"floorNumber",
+ "buildingId",
"imageContents",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1949,6 +1970,106 @@ def getNetworkHealthAlerts(self, networkId: str):
return self._session.get(metadata, resource)
+ def getNetworkLocationScanning(self, networkId: str):
+ """
+ **Return scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-location-scanning
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning"],
+ "operation": "getNetworkLocationScanning",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkLocationScanning(self, networkId: str, **kwargs):
+ """
+ **Change scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-location-scanning
+
+ - networkId (string): Network ID
+ - analyticsEnabled (boolean): Collect location and scanning analytics
+ - scanningApiEnabled (boolean): Enable push API for scanning events, analytics must be enabled
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning"],
+ "operation": "updateNetworkLocationScanning",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning"
+
+ body_params = [
+ "analyticsEnabled",
+ "scanningApiEnabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkLocationScanning: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getNetworkLocationScanningHttpServers(self, networkId: str):
+ """
+ **Return list of scanning API receivers**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-location-scanning-http-servers
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning", "httpServers"],
+ "operation": "getNetworkLocationScanningHttpServers",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning/httpServers"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkLocationScanningHttpServers(self, networkId: str, endpoints: list, **kwargs):
+ """
+ **Set the list of scanning API receivers**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-location-scanning-http-servers
+
+ - networkId (string): Network ID
+ - endpoints (array): A set of http server configurations
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["networks", "configure", "locationScanning", "httpServers"],
+ "operation": "updateNetworkLocationScanningHttpServers",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/locationScanning/httpServers"
+
+ body_params = [
+ "endpoints",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkLocationScanningHttpServers: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkMerakiAuthUsers(self, networkId: str):
"""
**List the authorized users configured under Meraki Authentication for a network (splash guest or RADIUS users for a wireless network, or client VPN users for a MX network)**
@@ -2106,14 +2227,17 @@ def updateNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **k
return self._session.put(metadata, resource, payload)
- def getNetworkMqttBrokers(self, networkId: str):
+ def getNetworkMqttBrokers(self, networkId: str, **kwargs):
"""
**List the MQTT brokers for this network**
https://developer.cisco.com/meraki/api-v1/#!get-network-mqtt-brokers
- networkId (string): Network ID
+ - productTypes (array): Optional parameter to filter MQTT brokers by product type. If multiple types are provided, the query will return brokers that match any of the provided types.
"""
+ kwargs.update(locals())
+
metadata = {
"tags": ["networks", "configure", "mqttBrokers"],
"operation": "getNetworkMqttBrokers",
@@ -2121,7 +2245,26 @@ def getNetworkMqttBrokers(self, networkId: str):
networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/mqttBrokers"
- return self._session.get(metadata, resource)
+ query_params = [
+ "productTypes",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getNetworkMqttBrokers: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: int, **kwargs):
"""
@@ -2134,10 +2277,17 @@ def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: in
- port (integer): Host port though which the MQTT broker can be reached.
- security (object): Security settings of the MQTT broker.
- authentication (object): Authentication settings of the MQTT broker
+ - productType (string): The product type for which the MQTT broker is being created.
"""
kwargs.update(locals())
+ if "productType" in kwargs:
+ options = ["camera", "wireless"]
+ assert kwargs["productType"] in options, (
+ f'''"productType" cannot be "{kwargs["productType"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
"tags": ["networks", "configure", "mqttBrokers"],
"operation": "createNetworkMqttBroker",
@@ -2151,6 +2301,7 @@ def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: in
"port",
"security",
"authentication",
+ "productType",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2637,6 +2788,7 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
- remoteStatusPageEnabled (boolean): Enables / disables access to the device status page (http://[device's LAN IP]). Optional. Can only be set if localStatusPageEnabled is set to true
- localStatusPage (object): A hash of Local Status page(s)' authentication options applied to the Network.
- securePort (object): A hash of SecureConnect options applied to the Network.
+ - fips (object): A hash of FIPS options applied to the Network
- namedVlans (object): A hash of Named VLANs options applied to the Network.
"""
@@ -2654,6 +2806,7 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
"remoteStatusPageEnabled",
"localStatusPage",
"securePort",
+ "fips",
"namedVlans",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2666,6 +2819,93 @@ def updateNetworkSettings(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def createNetworkSitesBuilding(self, networkId: str, name: str, **kwargs):
+ """
+ **Create a new building**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sites-building
+
+ - networkId (string): Network ID
+ - name (string): The name of the building
+ - floors (array): The floors of the building
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["networks", "configure", "sites", "buildings"],
+ "operation": "createNetworkSitesBuilding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings"
+
+ body_params = [
+ "name",
+ "floors",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSitesBuilding: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteNetworkSitesBuilding(self, networkId: str, buildingId: str):
+ """
+ **Delete a building**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-sites-building
+
+ - networkId (string): Network ID
+ - buildingId (string): Building ID
+ """
+
+ metadata = {
+ "tags": ["networks", "configure", "sites", "buildings"],
+ "operation": "deleteNetworkSitesBuilding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ buildingId = urllib.parse.quote(str(buildingId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings/{buildingId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateNetworkSitesBuilding(self, networkId: str, buildingId: str, **kwargs):
+ """
+ **Update a building**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-sites-building
+
+ - networkId (string): Network ID
+ - buildingId (string): Building ID
+ - name (string): The name of the building
+ - floors (array): The floors of the building
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["networks", "configure", "sites", "buildings"],
+ "operation": "updateNetworkSitesBuilding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ buildingId = urllib.parse.quote(str(buildingId), safe="")
+ resource = f"/networks/{networkId}/sites/buildings/{buildingId}"
+
+ body_params = [
+ "name",
+ "floors",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSitesBuilding: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSnmp(self, networkId: str):
"""
**Return the SNMP settings for a network**
@@ -2728,6 +2968,47 @@ def updateNetworkSnmp(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkSnmpTraps(self, networkId: str, **kwargs):
+ """
+ **Update the SNMP trap configuration for the specified network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-snmp-traps
+
+ - networkId (string): Network ID
+ - mode (string): SNMP trap protocol version
+ - receiver (object): Stores the port and address
+ - v2 (object): V2 mode
+ - v3 (object): V3 mode
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["disabled", "v1/v2c", "v3"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["networks", "configure", "snmp", "traps"],
+ "operation": "updateNetworkSnmpTraps",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/snmp/traps"
+
+ body_params = [
+ "mode",
+ "receiver",
+ "v2",
+ "v3",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSnmpTraps: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSplashLoginAttempts(self, networkId: str, **kwargs):
"""
**List the splash login attempts for a network**
@@ -3040,9 +3321,10 @@ def createNetworkVlanProfile(self, networkId: str, name: str, vlanNames: list, v
- vlanNames (array): An array of named VLANs
- vlanGroups (array): An array of VLAN groups
- iname (string): IName of the profile
+ - allowedVlans (string): The VLANs allowed on the VLAN profile. Only applicable to trunk ports. The given range must be inclusive of all named VLANs.
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
"tags": ["networks", "configure", "vlanProfiles"],
@@ -3053,6 +3335,7 @@ def createNetworkVlanProfile(self, networkId: str, name: str, vlanNames: list, v
body_params = [
"name",
+ "allowedVlans",
"vlanNames",
"vlanGroups",
"iname",
@@ -3188,9 +3471,10 @@ def updateNetworkVlanProfile(self, networkId: str, iname: str, name: str, vlanNa
- name (string): Name of the profile, string length must be from 1 to 255 characters
- vlanNames (array): An array of named VLANs
- vlanGroups (array): An array of VLAN groups
+ - allowedVlans (string): The VLANs allowed on the VLAN profile. Only applicable to trunk ports. The given range must be inclusive of all named VLANs.
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
"tags": ["networks", "configure", "vlanProfiles"],
@@ -3202,6 +3486,7 @@ def updateNetworkVlanProfile(self, networkId: str, iname: str, name: str, vlanNa
body_params = [
"name",
+ "allowedVlans",
"vlanNames",
"vlanGroups",
]
diff --git a/meraki/api/organizations.py b/meraki/api/organizations.py
index 4331a1ce..31229248 100644
--- a/meraki/api/organizations.py
+++ b/meraki/api/organizations.py
@@ -1083,6 +1083,329 @@ def deleteOrganizationAlertsProfile(self, organizationId: str, alertConfigId: st
return self._session.delete(metadata, resource)
+ def getOrganizationApiPushProfiles(self, organizationId: str, **kwargs):
+ """
+ **List the push profiles in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-push-profiles
+
+ - organizationId (string): Organization ID
+ - inames (array): Optional parameter to filter the result set by the included set of push profile inames
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "getOrganizationApiPushProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles"
+
+ query_params = [
+ "inames",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "inames",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationApiPushProfiles: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def createOrganizationApiPushProfile(self, organizationId: str, iname: str, topic: dict, receiver: dict, **kwargs):
+ """
+ **Create a new push profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Immutable name of the resource. Must be unique within resources of this type.
+ - topic (object): Push topic
+ - receiver (object): Push receiver profile
+ - name (string): Name of push profile
+ - description (string): Description of push profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "createOrganizationApiPushProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles"
+
+ body_params = [
+ "iname",
+ "name",
+ "description",
+ "topic",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationApiPushProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationApiPushProfile(self, organizationId: str, iname: str, **kwargs):
+ """
+ **Update a push profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ - name (string): Name of push profile
+ - description (string): Description of push profile
+ - topic (object): Push topic
+ - receiver (object): Push receiver profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "updateOrganizationApiPushProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles/{iname}"
+
+ body_params = [
+ "name",
+ "description",
+ "topic",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationApiPushProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationApiPushProfile(self, organizationId: str, iname: str):
+ """
+ **Delete a push profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-api-push-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "profiles"],
+ "operation": "deleteOrganizationApiPushProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/profiles/{iname}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationApiPushReceiversProfiles(self, organizationId: str):
+ """
+ **List the push receiver profiles in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-push-receivers-profiles
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "getOrganizationApiPushReceiversProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str, receiver: dict, **kwargs):
+ """
+ **Create a new push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Immutable name of the resource. Must be unique within resources of this type.
+ - receiver (object): Webhook receiver
+ - name (string): Name of receiver profile
+ - description (string): Description of receiver profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "createOrganizationApiPushReceiversProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles"
+
+ body_params = [
+ "iname",
+ "name",
+ "description",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationApiPushReceiversProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str):
+ """
+ **Delete a push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "deleteOrganizationApiPushReceiversProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles/{iname}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationApiPushReceiversProfile(self, organizationId: str, iname: str, **kwargs):
+ """
+ **Update a push receiver profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-api-push-receivers-profile
+
+ - organizationId (string): Organization ID
+ - iname (string): Iname
+ - name (string): Name of the receiver profile
+ - description (string): Description of the receiver profile
+ - receiver (object): API Push Receiver details
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "receivers", "profiles"],
+ "operation": "updateOrganizationApiPushReceiversProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ iname = urllib.parse.quote(str(iname), safe="")
+ resource = f"/organizations/{organizationId}/api/push/receivers/profiles/{iname}"
+
+ body_params = [
+ "name",
+ "description",
+ "receiver",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationApiPushReceiversProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationApiPushTopics(self, organizationId: str):
+ """
+ **List of push topics**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-push-topics
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "push", "topics"],
+ "operation": "getOrganizationApiPushTopics",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/push/topics"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationApiRestProvisioningPipelines(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List pipelines with operation and status metadata, sorted by pipeline ID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-rest-provisioning-pipelines
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'descending'.
+ - status (string): If provided, filters pipelines by status. If omitted, pipelines of all statuses are returned. `pending` pipelines have not started, `active` pipelines have started but not finished, `success` pipelines completed successfully, and `error` pipelines failed.
+ - timespan (integer): Created-at lookback for matching pipelines, in seconds. Defaults to 7200 seconds. The maximum is 30 days.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "status" in kwargs:
+ options = ["active", "error", "pending", "success"]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "api", "rest", "provisioning", "pipelines"],
+ "operation": "getOrganizationApiRestProvisioningPipelines",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/api/rest/provisioning/pipelines"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ "status",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRestProvisioningPipelines: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationApiRestProvisioningPipelinesJobs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List pipeline jobs, with optional status filtering**
@@ -1369,47 +1692,195 @@ def getOrganizationApiRequestsOverviewResponseCodesByInterval(self, organization
return self._session.get(metadata, resource, params)
- def getOrganizationAssuranceAlerts(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationApiRequestsResponseCodesHistoryByAdmin(self, organizationId: str, **kwargs):
"""
- **Return all health alerts for an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-alerts
+ **Lists API request response codes and their counts aggregated by admin**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-admin
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 4 - 300. Default is 30.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
- - networkId (string): Optional parameter to filter alerts by network ids.
- - severity (string): Optional parameter to filter by severity type.
- - types (array): Optional parameter to filter by alert type.
- - tsStart (string): Optional parameter to filter by starting timestamp
- - tsEnd (string): Optional parameter to filter by end timestamp
- - category (string): Optional parameter to filter by category.
- - sortBy (string): Optional parameter to set column to sort by.
- - serials (array): Optional parameter to filter by primary device serial
- - deviceTypes (array): Optional parameter to filter by device types
- - deviceTags (array): Optional parameter to filter by device tags
- - active (boolean): Optional parameter to filter by active alerts defaults to true
- - dismissed (boolean): Optional parameter to filter by dismissed alerts defaults to false
- - resolved (boolean): Optional parameter to filter by resolved alerts defaults to false
- - suppressAlertsForOfflineNodes (boolean): When set to true the api will only return connectivity alerts for a given device if that device is in an offline state. This only applies to devices. This is ignored when resolved is true. Example: If a Switch has a VLan Mismatch and is Unreachable. only the Unreachable alert will be returned. Defaults to false.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
"""
kwargs.update(locals())
- if "sortOrder" in kwargs:
- options = ["ascending", "descending"]
- assert kwargs["sortOrder"] in options, (
- f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
- )
- if "category" in kwargs:
- options = ["configuration", "connectivity", "device_health", "experience_metrics", "insights"]
- assert kwargs["category"] in options, (
- f'''"category" cannot be "{kwargs["category"]}", & must be set to one of: {options}'''
- )
- if "sortBy" in kwargs:
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "byAdmin"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryByAdmin",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/byAdmin"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryByAdmin: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApiRequestsResponseCodesHistoryByApplication(self, organizationId: str, **kwargs):
+ """
+ **Lists API request response codes and their counts aggregated by application**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-application
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "byApplication"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryByApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/byApplication"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryByApplication: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApiRequestsResponseCodesHistoryByOperation(self, organizationId: str, **kwargs):
+ """
+ **Aggregates API usage data by operationId**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-operation
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "byOperation"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryByOperation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/byOperation"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryByOperation: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationApiRequestsResponseCodesHistoryBySourceIp(self, organizationId: str, **kwargs):
+ """
+ **Aggregates API usage by source ip**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-api-requests-response-codes-history-by-source-ip
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "apiRequests", "responseCodes", "history", "bySourceIp"],
+ "operation": "getOrganizationApiRequestsResponseCodesHistoryBySourceIp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/apiRequests/responseCodes/history/bySourceIp"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationApiRequestsResponseCodesHistoryBySourceIp: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceAlerts(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return all health alerts for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-alerts
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 4 - 300. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
+ - networkId (string): Optional parameter to filter alerts by network ids.
+ - severity (string): Optional parameter to filter by severity type.
+ - types (array): Optional parameter to filter by alert type.
+ - tsStart (string): Optional parameter to filter by starting timestamp
+ - tsEnd (string): Optional parameter to filter by end timestamp
+ - category (string): Optional parameter to filter by category.
+ - sortBy (string): Optional parameter to set column to sort by.
+ - serials (array): Optional parameter to filter by primary device serial
+ - deviceTypes (array): Optional parameter to filter by device types
+ - deviceTags (array): Optional parameter to filter by device tags
+ - active (boolean): Optional parameter to filter by active alerts defaults to true
+ - dismissed (boolean): Optional parameter to filter by dismissed alerts defaults to false
+ - resolved (boolean): Optional parameter to filter by resolved alerts defaults to false
+ - suppressAlertsForOfflineNodes (boolean): When set to true the api will only return connectivity alerts for a given device if that device is in an offline state. This only applies to devices. This is ignored when resolved is true. Example: If a Switch has a VLan Mismatch and is Unreachable. only the Unreachable alert will be returned. Defaults to false.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "category" in kwargs:
+ options = ["configuration", "connectivity", "device_health", "experience_metrics", "insights"]
+ assert kwargs["category"] in options, (
+ f'''"category" cannot be "{kwargs["category"]}", & must be set to one of: {options}'''
+ )
+ if "sortBy" in kwargs:
options = ["category", "dismissedAt", "resolvedAt", "severity", "startedAt"]
assert kwargs["sortBy"] in options, (
f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
@@ -1908,170 +2379,2218 @@ def getOrganizationAssuranceAlert(self, organizationId: str, id: str):
return self._session.get(metadata, resource)
- def getOrganizationBrandingPolicies(self, organizationId: str):
+ def getOrganizationAssuranceClientsConnectedCountHistory(self, organizationId: str, networkId: str, **kwargs):
"""
- **List the branding policies of an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies
+ **Return combined wireless and wired connected client counts over time for a network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-connected-count-history
- organizationId (string): Organization ID
+ - networkId (string): Network ID to query.
+ - serials (array): A list of serials of wireless AP or wired switch devices
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssidNumbers (array): Filter results by SSID number
+ - deviceType (string): Filter connected client counts by device type.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 8 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600. The default is 600. Interval is calculated if time params are provided.
"""
+ kwargs.update(locals())
+
+ if "deviceType" in kwargs:
+ options = ["access_point", "switch"]
+ assert kwargs["deviceType"] in options, (
+ f'''"deviceType" cannot be "{kwargs["deviceType"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "getOrganizationBrandingPolicies",
+ "tags": ["organizations", "monitor", "clients", "connectedCountHistory"],
+ "operation": "getOrganizationAssuranceClientsConnectedCountHistory",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies"
+ resource = f"/organizations/{organizationId}/assurance/clients/connectedCountHistory"
- return self._session.get(metadata, resource)
+ query_params = [
+ "networkId",
+ "serials",
+ "bands",
+ "ssidNumbers",
+ "deviceType",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def createOrganizationBrandingPolicy(self, organizationId: str, name: str, **kwargs):
+ array_params = [
+ "serials",
+ "bands",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsConnectedCountHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceClientsEvents(self, organizationId: str, clientId: str, networkId: str, **kwargs):
"""
- **Add a new branding policy to an organization**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-branding-policy
+ **Given a client, get all alerts and events for a given timespan**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-events
- - organizationId (string): Organization ID
- - name (string): Name of the Dashboard branding policy.
- - enabled (boolean): Boolean indicating whether this policy is enabled.
- - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
- - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
- 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
- the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
- Dashboard; see the documentation for each property to see the allowed values.
- Each property defaults to 'default or inherit' when not provided.
- - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ - organizationId (string): Organization ID
+ - clientId (string): ID of client to query
+ - networkId (string): Network ID where client is connected
+ - filter (array): Optional parameter to filter by issue
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "createOrganizationBrandingPolicy",
+ "tags": ["organizations", "configure", "clients", "events"],
+ "operation": "getOrganizationAssuranceClientsEvents",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies"
+ resource = f"/organizations/{organizationId}/assurance/clients/events"
- body_params = [
- "name",
- "enabled",
- "adminSettings",
- "helpSettings",
- "customLogo",
+ query_params = [
+ "filter",
+ "clientId",
+ "networkId",
+ "t0",
+ "t1",
+ "timespan",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "filter",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"createOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsEvents: ignoring unrecognized kwargs: {invalid}"
+ )
- return self._session.post(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def getOrganizationBrandingPoliciesPriorities(self, organizationId: str):
+ def getOrganizationAssuranceClientsEventsCorrelated(
+ self, organizationId: str, clientId: str, category: str, networkId: str, timestamp: str, **kwargs
+ ):
"""
- **Return the branding policy IDs of an organization in priority order**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies-priorities
+ **Given a client, category, and timespan, return events that have a close connection to each other.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-events-correlated
- organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - category (string): Category of events
+ - networkId (string): Network used by the client
+ - timestamp (string): Timestamp for the event
+ - lookback (integer): Amount of time in minutes to look back
+ - lookforward (integer): Amount of time in minutes to look forwards
"""
+ kwargs.update(locals())
+
+ if "category" in kwargs:
+ options = ["application", "association", "authentication", "dhcp", "dns"]
+ assert kwargs["category"] in options, (
+ f'''"category" cannot be "{kwargs["category"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
- "operation": "getOrganizationBrandingPoliciesPriorities",
+ "tags": ["organizations", "configure", "clients", "events", "correlated"],
+ "operation": "getOrganizationAssuranceClientsEventsCorrelated",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+ resource = f"/organizations/{organizationId}/assurance/clients/events/correlated"
- return self._session.get(metadata, resource)
+ query_params = [
+ "clientId",
+ "category",
+ "networkId",
+ "timestamp",
+ "lookback",
+ "lookforward",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def updateOrganizationBrandingPoliciesPriorities(self, organizationId: str, **kwargs):
- """
- **Update the priority ordering of an organization's branding policies.**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policies-priorities
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsEventsCorrelated: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceClientsTopologyCurrent(self, organizationId: str, clientId: str, networkId: str, **kwargs):
+ """
+ **Given a client, return current topology**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-topology-current
+
+ - organizationId (string): Organization ID
+ - clientId (string): ID of client to query
+ - networkId (string): Network ID where client is connected
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "clients", "topology", "current"],
+ "operation": "getOrganizationAssuranceClientsTopologyCurrent",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/clients/topology/current"
+
+ query_params = [
+ "clientId",
+ "networkId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsTopologyCurrent: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceClientsTopologyNew(self, organizationId: str, clientIds: list, networkId: str, **kwargs):
+ """
+ **Given a client, return current topology**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-clients-topology-new
+
+ - organizationId (string): Organization ID
+ - clientIds (array): List of IDs for client retrieval for a given network. Limited to 1 client for now
+ - networkId (string): Network ID where client is connected
+ - timestamp (string): Timestamp for client topology path
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "clients", "topology", "new"],
+ "operation": "getOrganizationAssuranceClientsTopologyNew",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/clients/topology/new"
+
+ query_params = [
+ "clientIds",
+ "networkId",
+ "timestamp",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "clientIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceClientsTopologyNew: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceDevicesStatusesOverview(self, organizationId: str, **kwargs):
+ """
+ **Returns counts of online, offline, and recovered devices by product type, along with offline intervals for impacted devices in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-devices-statuses-overview
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "statuses", "overview"],
+ "operation": "getOrganizationAssuranceDevicesStatusesOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/devices/statuses/overview"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceDevicesStatusesOverview: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceFetchTableQuery(self, organizationId: str, tableName: str, **kwargs):
+ """
+ **Returns the table data for a given timespan**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-fetch-table-query
+
+ - organizationId (string): Organization ID
+ - tableName (string): The table from which we want to get data
+ - t0 (string): The beginning of the timespan for the data.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 365 days, 5 hours, 49 minutes, and 12 seconds. The default is 30 days, 10 hours, 29 minutes, and 6 seconds.
+ - userEmail (string): The user email for whom we want to calculate lookback
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "fetchTableQuery"],
+ "operation": "getOrganizationAssuranceFetchTableQuery",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/fetchTableQuery"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "tableName",
+ "userEmail",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceFetchTableQuery: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServer(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServer"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServer"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServerByInterval(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server and by interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server-by-interval
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServer", "byInterval"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServerByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServer/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServerByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServerType(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server-type
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServerType"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServerType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServerType"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServerType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceNetworkServicesServerHealthByServerTypeByInterval(self, organizationId: str, **kwargs):
+ """
+ **Returns network server health in organization by server type and by interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-network-services-server-health-by-server-type-by-interval
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results for these networks.
+ - serverTypes (array): Filter results for these server types.
+ - serverIps (array): Filter results for these server IP addresses.
+ - ssidNumbers (array): Filter results for these SSID Numbers.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networkServices", "serverHealth", "byServerType", "byInterval"],
+ "operation": "getOrganizationAssuranceNetworkServicesServerHealthByServerTypeByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/networkServices/serverHealth/byServerType/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serverTypes",
+ "serverIps",
+ "ssidNumbers",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceNetworkServicesServerHealthByServerTypeByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def checkupOrganizationAssuranceOptimization(self, organizationId: str, **kwargs):
+ """
+ **Returns an array of checkup results for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!checkup-organization-assurance-optimization
+
+ - organizationId (string): Organization ID
+ - forceRefresh (boolean): Optional parameter to reassess best practices
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "optimization"],
+ "operation": "checkupOrganizationAssuranceOptimization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/optimization/checkup"
+
+ query_params = [
+ "forceRefresh",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"checkupOrganizationAssuranceOptimization: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceOptimizationCheckupByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns an array of checkup results for the networks**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-optimization-checkup-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 7.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter checkups by Network Id
+ - forceRefresh (boolean): Optional parameter to reassess best practices
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "optimization", "checkup", "byNetwork"],
+ "operation": "getOrganizationAssuranceOptimizationCheckupByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/optimization/checkup/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "forceRefresh",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceOptimizationCheckupByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceProductAnnouncements(self, organizationId: str, **kwargs):
+ """
+ **Gets relevant product announcements for a user**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-product-announcements
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 365 days, 5 hours, 49 minutes, and 12 seconds. The default is 91 days, 7 hours, 27 minutes, and 18 seconds.
+ - onlyRelevant (boolean): Limits product announcements that are considered relevant to this user when true
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "productAnnouncements"],
+ "operation": "getOrganizationAssuranceProductAnnouncements",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/productAnnouncements"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "onlyRelevant",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceProductAnnouncements: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceScores(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get network health scores for a list of networks.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-scores
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 2 hours and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "scores"],
+ "operation": "getOrganizationAssuranceScores",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/scores"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAssuranceScores: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceThousandEyesApplications(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Get a list of Thousand Eyes applications with their alerts.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-thousand-eyes-applications
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - clientId (string): Filter results by client.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "thousandEyes", "applications"],
+ "operation": "getOrganizationAssuranceThousandEyesApplications",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/thousandEyes/applications"
+
+ query_params = [
+ "networkIds",
+ "clientId",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceThousandEyesApplications: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wired connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarizes wired connection successes and failures by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientOs(self, organizationId: str, **kwargs):
+ """
+ **Summarizes wired connection successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wired connection successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": [
+ "organizations",
+ "configure",
+ "wired",
+ "experience",
+ "successfulConnections",
+ "byNetwork",
+ "byClientType",
+ ],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wired connection successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByInterval(self, organizationId: str, **kwargs):
+ """
+ **Time-series of wired connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "wired", "experience", "successfulConnections", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByServer(self, organizationId: str, **kwargs):
+ """
+ **Summarizes wired connection successes and failures by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wired-experience-successful-connections-by-network-by-server
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "wired", "experience", "successfulConnections", "byNetwork", "byServer"],
+ "operation": "getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wired/experience/successfulConnections/byNetwork/byServer"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWiredExperienceSuccessfulConnectionsByNetworkByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWorkflows(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return workflows filtered by organization ID, network ID, type, and category**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-workflows
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
+ - networkIds (array): Optional parameter to filter by network ID
+ - types (array): Optional parameter to filter workflows by types
+ - categories (array): Optional parameter to filter workflows by categories
+ - scopeTypes (array): Optional parameter to filter workflows by scope types
+ - networkTags (array): Optional parameter to filter workflows by network tags
+ - clientTags (array): Optional parameter to filter workflows by client tags
+ - nodeTags (array): Optional parameter to filter workflows by node tags
+ - state (string): Optional parameter to filter workflows by state
+ - tsStart (string): Start time to filter workflows
+ - tsEnd (string): End time to filter workflows
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "workflows"],
+ "operation": "getOrganizationAssuranceWorkflows",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/workflows"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ "networkIds",
+ "types",
+ "categories",
+ "scopeTypes",
+ "networkTags",
+ "clientTags",
+ "nodeTags",
+ "state",
+ "tsStart",
+ "tsEnd",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "types",
+ "categories",
+ "scopeTypes",
+ "networkTags",
+ "clientTags",
+ "nodeTags",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAssuranceWorkflows: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAuthRadiusServers(self, organizationId: str):
+ """
+ **List the organization-wide RADIUS servers in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-auth-radius-servers
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "getOrganizationAuthRadiusServers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationAuthRadiusServer(self, organizationId: str, address: str, secret: str, **kwargs):
+ """
+ **Add an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - address (string): The IP address or FQDN of the RADIUS server
+ - secret (string): Shared secret of the RADIUS server
+ - name (string): The name of the RADIUS server
+ - modes (array): Available server modes
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "createOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers"
+
+ body_params = [
+ "name",
+ "address",
+ "modes",
+ "secret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationAuthRadiusServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationAuthRadiusServersAssignments(self, organizationId: str):
+ """
+ **Return list of network and policies that organization-wide RADIUS servers are bing used**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-auth-radius-servers-assignments
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers", "assignments"],
+ "operation": "getOrganizationAuthRadiusServersAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/assignments"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationAuthRadiusServer(self, organizationId: str, serverId: str):
+ """
+ **Return an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "getOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationAuthRadiusServer(self, organizationId: str, serverId: str, **kwargs):
+ """
+ **Update an organization-wide RADIUS server**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ - name (string): The name of the RADIUS server
+ - address (string): The IP address or FQDN of the RADIUS server
+ - modes (array): Available server modes
+ - secret (string): Shared secret of the RADIUS server
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "updateOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ body_params = [
+ "name",
+ "address",
+ "modes",
+ "secret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationAuthRadiusServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationAuthRadiusServer(self, organizationId: str, serverId: str):
+ """
+ **Delete an organization-wide RADIUS server from a organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-auth-radius-server
+
+ - organizationId (string): Organization ID
+ - serverId (string): Server ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "auth", "radius", "servers"],
+ "operation": "deleteOrganizationAuthRadiusServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ serverId = urllib.parse.quote(str(serverId), safe="")
+ resource = f"/organizations/{organizationId}/auth/radius/servers/{serverId}"
+
+ return self._session.delete(metadata, resource)
+
+ def codeOrganizationAutomateIdentity(self, organizationId: str):
+ """
+ **Generate a single use short lived code that can be used to retrieve the identity of the current user in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!code-organization-automate-identity
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "automate", "identity"],
+ "operation": "codeOrganizationAutomateIdentity",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/automate/identity/code"
+
+ return self._session.post(metadata, resource)
+
+ def getOrganizationBrandingPolicies(self, organizationId: str):
+ """
+ **List the branding policies of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "getOrganizationBrandingPolicies",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationBrandingPolicy(self, organizationId: str, name: str, **kwargs):
+ """
+ **Add a new branding policy to an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the Dashboard branding policy.
+ - enabled (boolean): Boolean indicating whether this policy is enabled.
+ - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
+ - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
+ 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
+ the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
+ Dashboard; see the documentation for each property to see the allowed values.
+ Each property defaults to 'default or inherit' when not provided.
+ - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "createOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies"
+
+ body_params = [
+ "name",
+ "enabled",
+ "adminSettings",
+ "helpSettings",
+ "customLogo",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationBrandingPoliciesPriorities(self, organizationId: str):
+ """
+ **Return the branding policy IDs of an organization in priority order**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policies-priorities
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
+ "operation": "getOrganizationBrandingPoliciesPriorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationBrandingPoliciesPriorities(self, organizationId: str, **kwargs):
+ """
+ **Update the priority ordering of an organization's branding policies.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policies-priorities
+
+ - organizationId (string): Organization ID
+ - brandingPolicyIds (array): An ordered list of branding policy IDs that determines the priority order of how to apply the policies
+
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
+ "operation": "updateOrganizationBrandingPoliciesPriorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+
+ body_params = [
+ "brandingPolicyIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationBrandingPoliciesPriorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ """
+ **Return a branding policy**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - brandingPolicyId (string): Branding policy ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "getOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str, name: str, **kwargs):
+ """
+ **Update a branding policy**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - brandingPolicyId (string): Branding policy ID
+ - name (string): Name of the Dashboard branding policy.
+ - enabled (boolean): Boolean indicating whether this policy is enabled.
+ - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
+ - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
+ 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
+ the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
+ Dashboard; see the documentation for each property to see the allowed values.
+
+ - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "updateOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+
+ body_params = [
+ "name",
+ "enabled",
+ "adminSettings",
+ "helpSettings",
+ "customLogo",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ """
+ **Delete a branding policy**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-branding-policy
+
+ - organizationId (string): Organization ID
+ - brandingPolicyId (string): Branding policy ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "brandingPolicies"],
+ "operation": "deleteOrganizationBrandingPolicy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
+ resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationCertificates(self, organizationId: str, **kwargs):
+ """
+ **Gets all or specific certificates for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates
+
+ - organizationId (string): Organization ID
+ - certificateIds (array): List of ids for specific certificate retrieval
+ - certManagedBy (array): List of cert managed by types
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "getOrganizationCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates"
+
+ query_params = [
+ "certificateIds",
+ "certManagedBy",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateIds",
+ "certManagedBy",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationCertificatesAuthorities(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List certificate authorities for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - authorityIds (array): Feature certificate authority IDs to filter by (exact match on each id; duplicates are ignored)
+ - sortBy (string): Field to sort by (default: authorityId)
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["authorityId", "featureType", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "getOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ query_params = [
+ "authorityIds",
+ "sortBy",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "authorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationCertificatesAuthority(self, organizationId: str, featureType: str, **kwargs):
+ """
+ **Create a certificate authority for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-certificates-authority
+
+ - organizationId (string): Organization ID
+ - featureType (string): Feature this CA serves (e.g., radsec, openroaming, zigbee)
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "createOrganizationCertificatesAuthority",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ body_params = [
+ "featureType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationCertificatesAuthority: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, **kwargs):
+ """
+ **Trust a newly created certificate authority (transition from untrusted to trusted).**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the certificate authority to trust. The CA must currently be untrusted.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "updateOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ body_params = [
+ "authorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, name: str):
+ """
+ **Delete a certificate authority**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the certificate authority to delete
+ - name (string): Certificate authority name
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "deleteOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationCertificatesAuthoritiesJob(self, organizationId: str, jobId: str):
+ """
+ **Return the status and result of a certificate authority job.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-authorities-job
+
+ - organizationId (string): Organization ID
+ - jobId (string): Job ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities", "jobs"],
+ "operation": "getOrganizationCertificatesAuthoritiesJob",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ jobId = urllib.parse.quote(str(jobId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities/jobs/{jobId}"
+
+ return self._session.get(metadata, resource)
+
+ def revokeOrganizationCertificatesAuthorities(self, organizationId: str, authorityId: str, **kwargs):
+ """
+ **Revoke a trusted feature certificate authority.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-organization-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - authorityId (string): ID of the feature certificate authority to revoke
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "authorities"],
+ "operation": "revokeOrganizationCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/authorities/revoke"
+
+ body_params = [
+ "authorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"revokeOrganizationCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def importOrganizationCertificates(self, organizationId: str, managedBy: str, contents: str, description: str, **kwargs):
+ """
+ **Import certificate for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!import-organization-certificates
+
+ - organizationId (string): Organization ID
+ - managedBy (string): Certificate managed by type [system_manager, mr, encrypted_syslog, grpc_dial_out]
+ - contents (string): Certificate content in valid PEM format
+ - description (string): Certificate description
+ """
+
+ kwargs = locals()
+
+ if "managedBy" in kwargs:
+ options = ["encrypted_syslog", "grpc_dial_out", "mr", "system_manager"]
+ assert kwargs["managedBy"] in options, (
+ f'''"managedBy" cannot be "{kwargs["managedBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "importOrganizationCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/import"
+
+ body_params = [
+ "managedBy",
+ "contents",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"importOrganizationCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationCertificatesMerakiAuthContents(self, organizationId: str):
+ """
+ **Download the public RADIUS certificate.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-meraki-auth-contents
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "monitor", "certificates", "merakiAuth", "contents"],
+ "operation": "getOrganizationCertificatesMerakiAuthContents",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/merakiAuth/contents"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationCertificatesRevocationLists(self, organizationId: str, **kwargs):
+ """
+ **Return full certificate revocation lists (CRLs) for the organization's certificate authorities**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificates-revocation-lists
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Optional filter: feature certificate authority IDs (base-10 integers). Every value must exist for this organization; otherwise the request fails. Omit to return CRLs for all feature CAs in the organization.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates", "revocationLists"],
+ "operation": "getOrganizationCertificatesRevocationLists",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/revocationLists"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationCertificatesRevocationLists: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def deleteOrganizationCertificate(self, organizationId: str, certificateId: str):
+ """
+ **Delete a certificate for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-certificate
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "deleteOrganizationCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/{certificateId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationCertificate(self, organizationId: str, certificateId: str, **kwargs):
+ """
+ **Update a certificate's description for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-certificate
- organizationId (string): Organization ID
- - brandingPolicyIds (array): An ordered list of branding policy IDs that determines the priority order of how to apply the policies
+ - certificateId (string): Certificate ID
+ - description (string): Description of a certificate that already exist in your org
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "certificates"],
+ "operation": "updateOrganizationCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/{certificateId}"
+
+ body_params = [
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationCertificate: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+ def getOrganizationCertificateContents(self, organizationId: str, certificateId: str, **kwargs):
+ """
+ **Download the trusted certificate by certificate id.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-certificate-contents
+
+ - organizationId (string): Organization ID
+ - certificateId (string): Certificate ID
+ - chainId (string): chainId that represent which certificate chain is being requested
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies", "priorities"],
- "operation": "updateOrganizationBrandingPoliciesPriorities",
+ "tags": ["organizations", "configure", "certificates", "contents"],
+ "operation": "getOrganizationCertificateContents",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/priorities"
+ certificateId = urllib.parse.quote(str(certificateId), safe="")
+ resource = f"/organizations/{organizationId}/certificates/{certificateId}/contents"
+
+ query_params = [
+ "chainId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationCertificateContents: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def claimIntoOrganization(self, organizationId: str, **kwargs):
+ """
+ **Claim a list of devices, licenses, and/or orders into an organization inventory**
+ https://developer.cisco.com/meraki/api-v1/#!claim-into-organization
+
+ - organizationId (string): Organization ID
+ - orders (array): The numbers of the orders that should be claimed
+ - serials (array): The serials of the devices that should be claimed
+ - licenses (array): The licenses that should be claimed
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure"],
+ "operation": "claimIntoOrganization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/claim"
body_params = [
- "brandingPolicyIds",
+ "orders",
+ "serials",
+ "licenses",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
if self._session._validate_kwargs:
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"claimIntoOrganization: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationClientsBandwidthUsageHistory(self, organizationId: str, **kwargs):
+ """
+ **Return data usage (in megabits per second) over time for all clients in the given organization within a given time range.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-bandwidth-usage-history
+
+ - organizationId (string): Organization ID
+ - networkTag (string): Match result to an exact network tag
+ - deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
+ - ssidName (string): Filter results by ssid name
+ - usageUplink (string): Filter results by usage uplink
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 186 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "clients", "bandwidthUsageHistory"],
+ "operation": "getOrganizationClientsBandwidthUsageHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/clients/bandwidthUsageHistory"
+
+ query_params = [
+ "networkTag",
+ "deviceTag",
+ "networkId",
+ "ssidName",
+ "usageUplink",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationBrandingPoliciesPriorities: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationClientsBandwidthUsageHistory: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def getOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ def getOrganizationClientsOverview(self, organizationId: str, **kwargs):
"""
- **Return a branding policy**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-branding-policy
+ **Return summary information around client data usage (in kb) across the given organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-overview
- organizationId (string): Organization ID
- - brandingPolicyId (string): Branding policy ID
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
"""
+ kwargs.update(locals())
+
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "getOrganizationBrandingPolicy",
+ "tags": ["organizations", "monitor", "clients", "overview"],
+ "operation": "getOrganizationClientsOverview",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+ resource = f"/organizations/{organizationId}/clients/overview"
- return self._session.get(metadata, resource)
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str, name: str, **kwargs):
- """
- **Update a branding policy**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-branding-policy
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationClientsOverview: ignoring unrecognized kwargs: {invalid}")
- - organizationId (string): Organization ID
- - brandingPolicyId (string): Branding policy ID
- - name (string): Name of the Dashboard branding policy.
- - enabled (boolean): Boolean indicating whether this policy is enabled.
- - adminSettings (object): Settings for describing which kinds of admins this policy applies to.
- - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of
- 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show
- the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on
- Dashboard; see the documentation for each property to see the allowed values.
+ return self._session.get(metadata, resource, params)
- - customLogo (object): Properties describing the custom logo attached to the branding policy.
+ def getOrganizationClientsSearch(self, organizationId: str, mac: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return the client details in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-search
+
+ - organizationId (string): Organization ID
+ - mac (string): The MAC address of the client. Required.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5. Default is 5.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "updateOrganizationBrandingPolicy",
+ "tags": ["organizations", "configure", "clients", "search"],
+ "operation": "getOrganizationClientsSearch",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+ resource = f"/organizations/{organizationId}/clients/search"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "mac",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationClientsSearch: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def cloneOrganization(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a new organization by cloning the addressed organization**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the new organization
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure"],
+ "operation": "cloneOrganization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/clone"
body_params = [
"name",
- "enabled",
- "adminSettings",
- "helpSettings",
- "customLogo",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2079,53 +4598,109 @@ def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"updateOrganizationBrandingPolicy: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"cloneOrganization: ignoring unrecognized kwargs: {invalid}")
- return self._session.put(metadata, resource, payload)
+ return self._session.post(metadata, resource, payload)
- def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str):
+ def getOrganizationCloudConnectivityRequirements(self, organizationId: str):
"""
- **Delete a branding policy**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-branding-policy
+ **List of source/destination traffic rules**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-cloud-connectivity-requirements
- organizationId (string): Organization ID
- - brandingPolicyId (string): Branding policy ID
"""
- metadata = {
- "tags": ["organizations", "configure", "brandingPolicies"],
- "operation": "deleteOrganizationBrandingPolicy",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- brandingPolicyId = urllib.parse.quote(str(brandingPolicyId), safe="")
- resource = f"/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}"
+ metadata = {
+ "tags": ["organizations", "monitor", "cloud", "connectivity", "requirements"],
+ "operation": "getOrganizationCloudConnectivityRequirements",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/cloud/connectivity/requirements"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationComputeApplicationDeployments(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the Application Deployment agent configurations for all hosts under this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-compute-application-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - developerNames (array): Filters deployments by application developer name
+ - applicationNames (array): Filters deployments by application name
+ - enabled (boolean): Filters deployments by their enabled status
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "compute", "application", "deployments"],
+ "operation": "getOrganizationComputeApplicationDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "developerNames",
+ "applicationNames",
+ "enabled",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "developerNames",
+ "applicationNames",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationComputeApplicationDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
- return self._session.delete(metadata, resource)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def claimIntoOrganization(self, organizationId: str, **kwargs):
+ def createOrganizationComputeApplicationDeploymentsBulkCreate(
+ self, organizationId: str, hosts: list, application: dict, enabled: bool, **kwargs
+ ):
"""
- **Claim a list of devices, licenses, and/or orders into an organization inventory**
- https://developer.cisco.com/meraki/api-v1/#!claim-into-organization
+ **Add Application Deployment agents for a list of hosts**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-compute-application-deployments-bulk-create
- organizationId (string): Organization ID
- - orders (array): The numbers of the orders that should be claimed
- - serials (array): The serials of the devices that should be claimed
- - licenses (array): The licenses that should be claimed
+ - hosts (array): List of hosts to deploy applications on
+ - application (object): Application information
+ - enabled (boolean): Whether the deployment should be enabled
+ - applicationConfiguration (object): Optional: Generic object for application-specific configuration
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure"],
- "operation": "claimIntoOrganization",
+ "tags": ["organizations", "configure", "compute", "application", "deployments", "bulkCreate"],
+ "operation": "createOrganizationComputeApplicationDeploymentsBulkCreate",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/claim"
+ resource = f"/organizations/{organizationId}/compute/application/deployments/bulkCreate"
body_params = [
- "orders",
- "serials",
- "licenses",
+ "hosts",
+ "application",
+ "enabled",
+ "applicationConfiguration",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2133,159 +4708,118 @@ def claimIntoOrganization(self, organizationId: str, **kwargs):
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"claimIntoOrganization: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"createOrganizationComputeApplicationDeploymentsBulkCreate: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.post(metadata, resource, payload)
- def getOrganizationClientsBandwidthUsageHistory(self, organizationId: str, **kwargs):
+ def updateOrganizationComputeApplicationDeployment(self, organizationId: str, deploymentId: str, enabled: bool, **kwargs):
"""
- **Return data usage (in megabits per second) over time for all clients in the given organization within a given time range.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-bandwidth-usage-history
+ **Update a Deployment agent configuration**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-compute-application-deployment
- organizationId (string): Organization ID
- - networkTag (string): Match result to an exact network tag
- - deviceTag (string): Match result to an exact device tag
- - ssidName (string): Filter results by ssid name
- - usageUplink (string): Filter results by usage uplink
- - t0 (string): The beginning of the timespan for the data.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 186 days. The default is 1 day.
+ - deploymentId (string): Deployment ID
+ - enabled (boolean): Whether or not the Application Deployment agent is enabled for the host.
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
- "tags": ["organizations", "monitor", "clients", "bandwidthUsageHistory"],
- "operation": "getOrganizationClientsBandwidthUsageHistory",
+ "tags": ["organizations", "configure", "compute", "application", "deployments"],
+ "operation": "updateOrganizationComputeApplicationDeployment",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clients/bandwidthUsageHistory"
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/{deploymentId}"
- query_params = [
- "networkTag",
- "deviceTag",
- "ssidName",
- "usageUplink",
- "t0",
- "t1",
- "timespan",
+ body_params = [
+ "enabled",
]
- params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
if self._session._validate_kwargs:
- all_params = query_params
+ all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationClientsBandwidthUsageHistory: ignoring unrecognized kwargs: {invalid}"
+ f"updateOrganizationComputeApplicationDeployment: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get(metadata, resource, params)
+ return self._session.put(metadata, resource, payload)
- def getOrganizationClientsOverview(self, organizationId: str, **kwargs):
+ def deleteOrganizationComputeApplicationDeployment(self, organizationId: str, deploymentId: str):
"""
- **Return summary information around client data usage (in kb) across the given organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-overview
+ **Delete a Application Deployment agent from the host**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-compute-application-deployment
- organizationId (string): Organization ID
- - t0 (string): The beginning of the timespan for the data.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - deploymentId (string): Deployment ID
"""
- kwargs.update(locals())
-
metadata = {
- "tags": ["organizations", "monitor", "clients", "overview"],
- "operation": "getOrganizationClientsOverview",
+ "tags": ["organizations", "configure", "compute", "application", "deployments"],
+ "operation": "deleteOrganizationComputeApplicationDeployment",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clients/overview"
-
- query_params = [
- "t0",
- "t1",
- "timespan",
- ]
- params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/compute/application/deployments/{deploymentId}"
- if self._session._validate_kwargs:
- all_params = query_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationClientsOverview: ignoring unrecognized kwargs: {invalid}")
-
- return self._session.get(metadata, resource, params)
+ return self._session.delete(metadata, resource)
- def getOrganizationClientsSearch(self, organizationId: str, mac: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationComputeHosts(
+ self, organizationId: str, developerName: str, applicationName: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Return the client details in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-clients-search
+ **Retrieves a list of compute hosts eligible for application deployment within a given organization, filtered by the specified application developer and application name, with optional network ID filtering.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-compute-hosts
- organizationId (string): Organization ID
- - mac (string): The MAC address of the client. Required.
+ - developerName (string): Filters hosts by application developer name
+ - applicationName (string): Filters hosts by application name
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5. Default is 5.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Filters hosts by the network ID they belong to
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "clients", "search"],
- "operation": "getOrganizationClientsSearch",
+ "tags": ["organizations", "configure", "compute", "hosts"],
+ "operation": "getOrganizationComputeHosts",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clients/search"
+ resource = f"/organizations/{organizationId}/compute/hosts"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
- "mac",
+ "developerName",
+ "applicationName",
+ "networkIds",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- if self._session._validate_kwargs:
- all_params = query_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationClientsSearch: ignoring unrecognized kwargs: {invalid}")
-
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
-
- def cloneOrganization(self, organizationId: str, name: str, **kwargs):
- """
- **Create a new organization by cloning the addressed organization**
- https://developer.cisco.com/meraki/api-v1/#!clone-organization
-
- - organizationId (string): Organization ID
- - name (string): The name of the new organization
- """
-
- kwargs = locals()
-
- metadata = {
- "tags": ["organizations", "configure"],
- "operation": "cloneOrganization",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/clone"
-
- body_params = [
- "name",
+ array_params = [
+ "networkIds",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"cloneOrganization: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"getOrganizationComputeHosts: ignoring unrecognized kwargs: {invalid}")
- return self._session.post(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
def getOrganizationConfigTemplates(self, organizationId: str):
"""
@@ -2632,36 +5166,176 @@ def getOrganizationDevicesAvailabilitiesChangeHistory(
- productTypes (array): Optional parameter to filter device availabilities history by device product types
- networkIds (array): Optional parameter to filter device availabilities history by network IDs
- statuses (array): Optional parameter to filter device availabilities history by device statuses
+ - categories (array): Optional parameter to filter device availabilities history by categories of status, reboot, or upgrade
+ - networkTags (array): Optional parameter to filter device availabilities history by network tags. The filtering is case-sensitive. If tags are included, 'networkTagsFilterType' should also be included (see below).
+ - networkTagsFilterType (string): An optional parameter of value 'withAnyTags' or 'withAllTags' to indicate whether to return networks which contain ANY or ALL of the included tags. If no type is included, 'withAnyTags' will be selected.
+ - deviceTags (array): Optional parameter to filter device availabilities history by device tags. The filtering is case-sensitive. If tags are included, 'deviceTagsFilterType' should also be included (see below).
+ - deviceTagsFilterType (string): An optional parameter of value 'withAnyTags' or 'withAllTags' to indicate whether to return devices which contain ANY or ALL of the included tags. If no type is included, 'withAnyTags' will be selected.
+ """
+
+ kwargs.update(locals())
+
+ if "networkTagsFilterType" in kwargs:
+ options = ["withAllTags", "withAnyTags"]
+ assert kwargs["networkTagsFilterType"] in options, (
+ f'''"networkTagsFilterType" cannot be "{kwargs["networkTagsFilterType"]}", & must be set to one of: {options}'''
+ )
+ if "deviceTagsFilterType" in kwargs:
+ options = ["withAllTags", "withAnyTags"]
+ assert kwargs["deviceTagsFilterType"] in options, (
+ f'''"deviceTagsFilterType" cannot be "{kwargs["deviceTagsFilterType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "availabilities", "changeHistory"],
+ "operation": "getOrganizationDevicesAvailabilitiesChangeHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/availabilities/changeHistory"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "serials",
+ "productTypes",
+ "networkIds",
+ "statuses",
+ "categories",
+ "networkTags",
+ "networkTagsFilterType",
+ "deviceTags",
+ "deviceTagsFilterType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ "productTypes",
+ "networkIds",
+ "statuses",
+ "categories",
+ "networkTags",
+ "deviceTags",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesAvailabilitiesChangeHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesBootsHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns the history of device boots in reverse chronological order (most recent first)**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-boots-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 730 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 730 days.
+ - serials (array): Optional parameter to filter device by device serial numbers. This filter uses multiple exact matches.
+ - productTypes (array): Optional parameter to filter devices by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
+ - mostRecentPerDevice (boolean): If true, only the most recent boot for each device is returned.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'descending'.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "boots", "history"],
+ "operation": "getOrganizationDevicesBootsHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/boots/history"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "serials",
+ "productTypes",
+ "mostRecentPerDevice",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationDevicesBootsHistory: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesBootsOverviewByDevice(self, organizationId: str, **kwargs):
+ """
+ **Summarizes device reboots across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-boots-overview-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - productTypes (array): An optional parameter to filter device statuses by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["organizations", "monitor", "devices", "availabilities", "changeHistory"],
- "operation": "getOrganizationDevicesAvailabilitiesChangeHistory",
+ "tags": ["organizations", "monitor", "devices", "boots", "overview", "byDevice"],
+ "operation": "getOrganizationDevicesBootsOverviewByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/devices/availabilities/changeHistory"
+ resource = f"/organizations/{organizationId}/devices/boots/overview/byDevice"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
+ "networkIds",
+ "productTypes",
"t0",
"t1",
"timespan",
- "serials",
- "productTypes",
- "networkIds",
- "statuses",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "serials",
- "productTypes",
"networkIds",
- "statuses",
+ "productTypes",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -2673,10 +5347,10 @@ def getOrganizationDevicesAvailabilitiesChangeHistory(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationDevicesAvailabilitiesChangeHistory: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationDevicesBootsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
def getOrganizationDevicesCellularDataDevices(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
@@ -3276,6 +5950,64 @@ def getOrganizationDevicesCellularUplinksTowersByDevice(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationDevicesCertificates(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List device certificates for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-certificates
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - serials (array): Device serial numbers to filter by (exact match; duplicates are ignored)
+ - featureTypes (array): Feature types these device certificates serve (exact match; e.g., radsec, openroaming, zigbee)
+ - sortBy (string): Field to sort by (default: authorityId)
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["authorityId", "featureType", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "certificates"],
+ "operation": "getOrganizationDevicesCertificates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/certificates"
+
+ query_params = [
+ "serials",
+ "featureTypes",
+ "sortBy",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ "featureTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationDevicesCertificates: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def createOrganizationDevicesControllerMigration(self, organizationId: str, serials: list, target: str, **kwargs):
"""
**Migrate devices to another controller or management mode**
@@ -3410,6 +6142,56 @@ def bulkUpdateOrganizationDevicesDetails(self, organizationId: str, serials: lis
return self._session.post(metadata, resource, payload)
+ def getOrganizationDevicesMemoryByDevice(self, organizationId: str, networkIds: list, productTypes: list, **kwargs):
+ """
+ **Summarizes memory status across devices of a given network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-memory-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - productTypes (array): Parameter to filter device availabilities by device product types. This filter uses multiple exact matches.
+ - usageThreshold (number): Threshold of device memory utilization expressed as a percent. Filters out all devices below this value.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "memory", "byDevice"],
+ "operation": "getOrganizationDevicesMemoryByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/memory/byDevice"
+
+ query_params = [
+ "networkIds",
+ "productTypes",
+ "usageThreshold",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationDevicesMemoryByDevice: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
def getOrganizationDevicesOverviewByModel(self, organizationId: str, **kwargs):
"""
**Lists the count for each device model**
@@ -3744,6 +6526,65 @@ def stopOrganizationDevicesPacketCaptureCapture(self, organizationId: str, captu
return self._session.post(metadata, resource, payload)
+ def getOrganizationDevicesPacketCaptureOpportunisticByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the Opportunistic Pcap settings of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-packet-capture-opportunistic-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter results by network.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'descending'.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCapture", "opportunistic", "byNetwork"],
+ "operation": "getOrganizationDevicesPacketCaptureOpportunisticByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/opportunistic/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesPacketCaptureOpportunisticByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationDevicesPacketCaptureSchedules(self, organizationId: str, **kwargs):
"""
**List the Packet Capture Schedules**
@@ -3836,6 +6677,39 @@ def createOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, de
return self._session.post(metadata, resource, payload)
+ def bulkOrganizationDevicesPacketCaptureSchedulesDelete(self, organizationId: str, scheduleIds: list, **kwargs):
+ """
+ **Delete packet capture schedules**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-devices-packet-capture-schedules-delete
+
+ - organizationId (string): Organization ID
+ - scheduleIds (array): Delete the packet capture schedules of the specified schedule ids
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCapture", "schedules"],
+ "operation": "bulkOrganizationDevicesPacketCaptureSchedulesDelete",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/bulkDelete"
+
+ body_params = [
+ "scheduleIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"bulkOrganizationDevicesPacketCaptureSchedulesDelete: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def reorderOrganizationDevicesPacketCaptureSchedules(self, organizationId: str, order: list, **kwargs):
"""
**Bulk update priorities of pcap schedules**
@@ -3911,31 +6785,144 @@ def updateOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, sc
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationDevicesPacketCaptureSchedule: ignoring unrecognized kwargs: {invalid}"
+ f"updateOrganizationDevicesPacketCaptureSchedule: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, scheduleId: str):
+ """
+ **Delete schedule from cloud**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-devices-packet-capture-schedule
+
+ - organizationId (string): Organization ID
+ - scheduleId (string): Delete the capture schedules of the specified capture schedule id
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCapture", "schedules"],
+ "operation": "deleteOrganizationDevicesPacketCaptureSchedule",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ scheduleId = urllib.parse.quote(str(scheduleId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
+
+ return self._session.delete(metadata, resource)
+
+ def tasksOrganizationDevicesPacketCapture(self, organizationId: str, packetId: str, task: str, **kwargs):
+ """
+ **Enqueues a task for a specific packet capture**
+ https://developer.cisco.com/meraki/api-v1/#!tasks-organization-devices-packet-capture
+
+ - organizationId (string): Organization ID
+ - packetId (string): Packet ID
+ - task (string): Type of task to enqueue. It can be one of: ["analysis", "reasoning", "summary", "highlights", "title", "flow"]
+ - networkId (string): Parameter to validate authorization by network access
+ """
+
+ kwargs.update(locals())
+
+ if "task" in kwargs:
+ options = ["analysis", "flow", "highlights", "reasoning", "summary", "title"]
+ assert kwargs["task"] in options, f'''"task" cannot be "{kwargs["task"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCaptures"],
+ "operation": "tasksOrganizationDevicesPacketCapture",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ packetId = urllib.parse.quote(str(packetId), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCaptures/{packetId}/tasks"
+
+ body_params = [
+ "networkId",
+ "task",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"tasksOrganizationDevicesPacketCapture: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationDevicesPacketCaptureTask(self, organizationId: str, packetId: str, id: str, **kwargs):
+ """
+ **Retrieves packet capture analysis result for a specific packet capture task.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-packet-capture-task
+
+ - organizationId (string): Organization ID
+ - packetId (string): Packet ID
+ - id (string): ID
+ - networkId (string): Optional parameter to validate authorization by network access
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "packetCaptures", "tasks"],
+ "operation": "getOrganizationDevicesPacketCaptureTask",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ packetId = urllib.parse.quote(str(packetId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/devices/packetCaptures/{packetId}/tasks/{id}"
+
+ query_params = [
+ "networkId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesPacketCaptureTask: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def deleteOrganizationDevicesPacketCaptureSchedule(self, organizationId: str, scheduleId: str):
+ def bulkOrganizationDevicesPlacementPositionsUpdate(self, organizationId: str, serials: list, **kwargs):
"""
- **Delete schedule from cloud**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-devices-packet-capture-schedule
+ **Bulk update the attributes related to positions for provided devices**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-devices-placement-positions-update
- organizationId (string): Organization ID
- - scheduleId (string): Delete the capture schedules of the specified capture schedule id
+ - serials (array): List of device serials on a floor plan to update
+ - height (object): Height of the devices on the floor plan
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
- "tags": ["organizations", "configure", "devices", "packetCapture", "schedules"],
- "operation": "deleteOrganizationDevicesPacketCaptureSchedule",
+ "tags": ["organizations", "configure", "devices", "placement", "positions"],
+ "operation": "bulkOrganizationDevicesPlacementPositionsUpdate",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- scheduleId = urllib.parse.quote(str(scheduleId), safe="")
- resource = f"/organizations/{organizationId}/devices/packetCapture/schedules/{scheduleId}"
+ resource = f"/organizations/{organizationId}/devices/placement/positions/bulkUpdate"
- return self._session.delete(metadata, resource)
+ body_params = [
+ "serials",
+ "height",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"bulkOrganizationDevicesPlacementPositionsUpdate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
def getOrganizationDevicesPowerModulesStatusesByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
@@ -4078,6 +7065,216 @@ def getOrganizationDevicesProvisioningStatuses(self, organizationId: str, total_
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationDevicesSoftwareUpdatesOverviewsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns details about software updates for networks within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-software-updates-overviews-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - sortOrder (string): Sorted order of entries. Order options are 'ascending' and 'descending'. Default is 'ascending'.
+ - sortKey (string): Specify key to order the list of networks.
+ - configSource (string): Limit the list of networks to those that contain devices with the specified config source
+ - networkIds (array): Limit the list of networks to those that match the provided network IDs
+ - networkGroupIds (array): Limit the list of networks to those that belong to one of the provided network group IDs.
+ - productTypes (array): Limit the list of product types included for each network
+ - networkName (string): Limit the list of networks to those whose name contains the given search string.
+ - versionIds (array): Limit the list of networks to those that are currently on one of the provided version IDs.
+ - firmwareStatus (string): Limit the list of networks to those whose current firmware version has the specified end-of-support status.
+ - firmwareType (string): Limit the list of networks to those whose current firmware version has the specified release type.
+ - upgradeDependencyIds (array): Limit the list of networks to those that belong to one of the provided upgrade dependencies.
+ - upgradeAvailable (boolean): Limit the list of networks by upgrade availability.
+ - templateRole (string): Limit the list of networks by config template role: non-template only, templates only, or templates and bound networks.
+ """
+
+ kwargs.update(locals())
+
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = [
+ "availability",
+ "currentVersion",
+ "firmwareStatus",
+ "firmwareType",
+ "lastUpgrade",
+ "networkGroup",
+ "networkName",
+ "networkType",
+ "scheduledTime",
+ "scheduledUpgradeVersion",
+ "upgradeDependency",
+ ]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+ if "configSource" in kwargs:
+ options = ["cloud", "local"]
+ assert kwargs["configSource"] in options, (
+ f'''"configSource" cannot be "{kwargs["configSource"]}", & must be set to one of: {options}'''
+ )
+ if "firmwareStatus" in kwargs:
+ options = ["critical", "good", "warning"]
+ assert kwargs["firmwareStatus"] in options, (
+ f'''"firmwareStatus" cannot be "{kwargs["firmwareStatus"]}", & must be set to one of: {options}'''
+ )
+ if "firmwareType" in kwargs:
+ options = ["beta", "candidate", "stable"]
+ assert kwargs["firmwareType"] in options, (
+ f'''"firmwareType" cannot be "{kwargs["firmwareType"]}", & must be set to one of: {options}'''
+ )
+ if "templateRole" in kwargs:
+ options = ["bound-templates", "non-template", "templates"]
+ assert kwargs["templateRole"] in options, (
+ f'''"templateRole" cannot be "{kwargs["templateRole"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "software", "updates", "overviews", "byNetwork"],
+ "operation": "getOrganizationDevicesSoftwareUpdatesOverviewsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/software/updates/overviews/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortOrder",
+ "sortKey",
+ "configSource",
+ "networkIds",
+ "networkGroupIds",
+ "productTypes",
+ "networkName",
+ "versionIds",
+ "firmwareStatus",
+ "firmwareType",
+ "upgradeDependencyIds",
+ "upgradeAvailable",
+ "templateRole",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "productTypes",
+ "versionIds",
+ "upgradeDependencyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSoftwareUpdatesOverviewsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesSoftwareVersions(self, organizationId: str, releaseType: str, **kwargs):
+ """
+ **List the available software upgrade versions for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-software-versions
+
+ - organizationId (string): Organization ID
+ - releaseType (string): Filter by release type
+ """
+
+ kwargs = locals()
+
+ if "releaseType" in kwargs:
+ options = ["beta", "generallyAvailable", "recommended"]
+ assert kwargs["releaseType"] in options, (
+ f'''"releaseType" cannot be "{kwargs["releaseType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "software", "versions"],
+ "operation": "getOrganizationDevicesSoftwareVersions",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/software/versions"
+
+ query_params = [
+ "releaseType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSoftwareVersions: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationDevicesSoftwareVersionsChangelogs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provide changelogs for specified versions or, if unspecified, for all versions in the organization, including reference to the last and next versions.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-software-versions-changelogs
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - versionIds (array): Array of version IDs for filtering
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 30.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "devices", "software", "versions", "changelogs"],
+ "operation": "getOrganizationDevicesSoftwareVersionsChangelogs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/software/versions/changelogs"
+
+ query_params = [
+ "versionIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "versionIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSoftwareVersionsChangelogs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationDevicesStatuses(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List the status of every Meraki device in the organization**
@@ -4096,6 +7293,7 @@ def getOrganizationDevicesStatuses(self, organizationId: str, total_pages=1, dir
- models (array): Optional parameter to filter devices by models.
- tags (array): An optional parameter to filter devices by tags. The filtering is case-sensitive. If tags are included, 'tagsFilterType' should also be included (see below).
- tagsFilterType (string): An optional parameter of value 'withAnyTags' or 'withAllTags' to indicate whether to return devices which contain ANY or ALL of the included tags. If no type is included, 'withAnyTags' will be selected.
+ - configurationUpdatedAfter (string): Optional parameter to filter results by whether or not the device's configuration has been updated after the given timestamp
"""
kwargs.update(locals())
@@ -4124,6 +7322,7 @@ def getOrganizationDevicesStatuses(self, organizationId: str, total_pages=1, dir
"models",
"tags",
"tagsFilterType",
+ "configurationUpdatedAfter",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -4348,11 +7547,141 @@ def getOrganizationDevicesSystemMemoryUsageHistoryByInterval(
params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = query_params + array_params
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesSystemMemoryUsageHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesTopologyInterfaces(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List topology interfaces in an organization, including layer 2 and layer 3 metadata when available.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-topology-interfaces
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter interfaces by network ID. This filter uses multiple exact matches. Query array syntax follows the standard bracket form, for example: networkIds[]=L_1234&networkIds[]=L_5678.
+ - serials (array): Optional parameter to filter interfaces by device serial. This filter uses multiple exact matches. Query array syntax follows the standard bracket form, for example: serials[]=Q234-ABCD-5678&serials[]=Q234-ABCD-9012.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "topology", "interfaces"],
+ "operation": "getOrganizationDevicesTopologyInterfaces",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/topology/interfaces"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesTopologyInterfaces: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesTopologyL2Links(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List layer 2 topology links originating from devices in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-topology-l-2-links
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "topology", "l2", "links"],
+ "operation": "getOrganizationDevicesTopologyL2Links",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/topology/l2/links"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationDevicesTopologyL2Links: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationDevicesTopologyNodesDiscovered(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List topology nodes discovered by LLDP/CDP from devices in an organization, including reported metadata when available.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-devices-topology-nodes-discovered
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "devices", "topology", "nodes", "discovered"],
+ "operation": "getOrganizationDevicesTopologyNodesDiscovered",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/devices/topology/nodes/discovered"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationDevicesSystemMemoryUsageHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationDevicesTopologyNodesDiscovered: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
@@ -4612,6 +7941,248 @@ def deleteOrganizationEarlyAccessFeaturesOptIn(self, organizationId: str, optInI
return self._session.delete(metadata, resource)
+ def updateOrganizationExtensionsSdwanmanagerInterconnect(
+ self, organizationId: str, interconnectId: str, name: str, status: str, **kwargs
+ ):
+ """
+ **Update name and status of an Interconnect**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-extensions-sdwanmanager-interconnect
+
+ - organizationId (string): Organization ID
+ - interconnectId (string): Interconnect ID
+ - name (string): Interconnect name
+ - status (string): Interconnect status
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "sdwanmanager", "interconnects"],
+ "operation": "updateOrganizationExtensionsSdwanmanagerInterconnect",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ interconnectId = urllib.parse.quote(str(interconnectId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/sdwanmanager/interconnects/{interconnectId}"
+
+ body_params = [
+ "name",
+ "status",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationExtensionsSdwanmanagerInterconnect: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationExtensionsThousandEyesNetworks(self, organizationId: str):
+ """
+ **List the ThousandEyes agent configurations under this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-extensions-thousand-eyes-networks
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "getOrganizationExtensionsThousandEyesNetworks",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, enabled: bool, networkId: str, **kwargs):
+ """
+ **Add a ThousandEyes agent for this network**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - enabled (boolean): Whether or not the ThousandEyes agent is enabled for the network.
+ - networkId (string): Network that will have the ThousandEyes agent installed on.
+ - tests (array): An array of tests to be created
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "createOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks"
+
+ body_params = [
+ "enabled",
+ "networkId",
+ "tests",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationExtensionsThousandEyesNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationExtensionsThousandEyesNetworksSupported(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all the networks eligible for ThousandEyes agent activation under this organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-extensions-thousand-eyes-networks-supported
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - agentInstalled (boolean): Set to true to get only networks with installed ThousandEyes agent; set to false to get networks without agents.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks", "supported"],
+ "operation": "getOrganizationExtensionsThousandEyesNetworksSupported",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/supported"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "agentInstalled",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationExtensionsThousandEyesNetworksSupported: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str):
+ """
+ **List the ThousandEyes agent configuration under this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "getOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str, enabled: bool, **kwargs):
+ """
+ **Update a ThousandEyes agent from this network**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ - enabled (boolean): Whether or not the ThousandEyes agent is enabled for the network.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "updateOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ body_params = [
+ "enabled",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationExtensionsThousandEyesNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationExtensionsThousandEyesNetwork(self, organizationId: str, networkId: str):
+ """
+ **Delete a ThousandEyes agent from this network**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-extensions-thousand-eyes-network
+
+ - organizationId (string): Organization ID
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "networks"],
+ "operation": "deleteOrganizationExtensionsThousandEyesNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/networks/{networkId}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationExtensionsThousandEyesTest(self, organizationId: str, **kwargs):
+ """
+ **Create a ThousandEyes test based on a provided test template**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-extensions-thousand-eyes-test
+
+ - organizationId (string): Organization ID
+ - tests (array): An array of tests to be created
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "extensions", "thousandEyes", "tests"],
+ "operation": "createOrganizationExtensionsThousandEyesTest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/extensions/thousandEyes/tests"
+
+ body_params = [
+ "tests",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationExtensionsThousandEyesTest: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getOrganizationFirmwareUpgrades(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Get firmware upgrade information for an organization**
@@ -4807,29 +8378,117 @@ def getOrganizationFloorPlansAutoLocateStatuses(self, organizationId: str, total
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "floorPlanIds",
- ]
- params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
-
- array_params = [
- "networkIds",
- "floorPlanIds",
+ "networkIds",
+ "floorPlanIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "floorPlanIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationFloorPlansAutoLocateStatuses: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAccessGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List effective Catalyst Center access groups for the requested Catalyst Center administrators in the specified organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-access-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of access groups to return per page. Range: 1-50. Defaults to 50 when omitted.
+ - startingAfter (string): Cursor token to retrieve access groups after the specified access group identifier.
+ - endingBefore (string): Cursor token to retrieve access groups before the specified access group identifier.
+ - assignedAdminEmails (array): Catalyst Center administrator email addresses used by federation to filter access groups for the requested administrators.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "iam", "admins", "accessGroups"],
+ "operation": "getOrganizationAccessGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/admins/accessGroups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "assignedAdminEmails",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "assignedAdminEmails",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationAccessGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def resolveOrganizationIamAdminsAdministratorsMePermissions(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the authenticated caller admin's permissions for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!resolve-organization-iam-admins-administrators-me-permissions
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "iam", "admins", "administrators", "me", "permissions"],
+ "operation": "resolveOrganizationIamAdminsAdministratorsMePermissions",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/admins/administrators/me/permissions/resolve"
+
+ body_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
- for k, v in kwargs.items():
- if k.strip() in array_params:
- params[f"{k.strip()}[]"] = kwargs[f"{k}"]
- params.pop(k.strip())
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
if self._session._validate_kwargs:
- all_params = query_params + array_params
+ all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationFloorPlansAutoLocateStatuses: ignoring unrecognized kwargs: {invalid}"
+ f"resolveOrganizationIamAdminsAdministratorsMePermissions: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.post(metadata, resource, payload)
def getOrganizationIntegrationsDeployable(self, organizationId: str):
"""
@@ -5100,6 +8759,61 @@ def getOrganizationInventoryDevices(self, organizationId: str, total_pages=1, di
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationInventoryDevicesDetails(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return inventory devices with additional site, geolocation, software, licensing, lifecycle, and Catalyst Center-specific fields**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-inventory-devices-details
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter devices by network IDs. Matches devices in any of the provided network IDs. When multiple filter parameters are provided, a device must match each provided filter. Query array syntax follows the standard bracket form, for example: networkIds[]=L_1234&networkIds[]=L_5678. Maximum 100 network IDs.
+ - serials (array): Optional parameter to filter devices by serials. Matches devices with any of the provided serials. When multiple filter parameters are provided, a device must match each provided filter. Query array syntax follows the standard bracket form, for example: serials[]=Q234-ABCD-5678&serials[]=Q234-ABCD-9012. Maximum 100 serials.
+ - productTypes (array): Optional parameter to filter devices by product type. Matches devices with any of the provided product types. When multiple filter parameters are provided, a device must match each provided filter. Query array syntax follows the standard bracket form, for example: productTypes[]=switch&productTypes[]=wireless. Maximum 100 product types.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "inventory", "devices", "details"],
+ "operation": "getOrganizationInventoryDevicesDetails",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/inventory/devices/details"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "productTypes",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "productTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationInventoryDevicesDetails: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationInventoryDevicesEoxOverview(self, organizationId: str):
"""
**Fetch the EOX summary for an organization, including counts of devices that are end-of-sale, end-of-support, and end-of-support-soon.**
@@ -5687,6 +9401,7 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
- timeZone (string): The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
- copyFromNetworkId (string): The ID of the network to copy configuration from. Other provided parameters will override the copied configuration, except type which must match this network's type exactly.
- notes (string): Add any notes or additional information about this network here.
+ - details (array): An array of details
"""
kwargs.update(locals())
@@ -5705,6 +9420,252 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
"timeZone",
"copyFromNetworkId",
"notes",
+ "details",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNetwork: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds: list, **kwargs):
+ """
+ **Combine multiple networks into a single network**
+ https://developer.cisco.com/meraki/api-v1/#!combine-organization-networks
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the combined network
+ - networkIds (array): A list of the network IDs that will be combined. If an ID of a combined network is included in this list, the other networks in the list will be grouped into that network
+ - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break. All networks that are part of this combined network will have their enrollment string appended by '-network_type'. If left empty, all exisitng enrollment strings will be deleted.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks"],
+ "operation": "combineOrganizationNetworks",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/combine"
+
+ body_params = [
+ "name",
+ "networkIds",
+ "enrollmentString",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"combineOrganizationNetworks: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNetworksGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the network groups in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-networks-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - groupIds (array): Optional parameter to filter network groups by ID
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "getOrganizationNetworksGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups"
+
+ query_params = [
+ "groupIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "groupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationNetworksGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationNetworksGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a network group**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the network group
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "createOrganizationNetworksGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups"
+
+ body_params = [
+ "name",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationNetworksGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationNetworksGroupsOverviewByGroup(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the client and status overview information for the network groups in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-networks-groups-overview-by-group
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - sortBy (string): Field by which to sort the results
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["organizations", "monitor", "networks", "groups", "overview", "byGroup"],
+ "operation": "getOrganizationNetworksGroupsOverviewByGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/overview/byGroup"
+
+ query_params = [
+ "sortBy",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationNetworksGroupsOverviewByGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationNetworksGroup(self, organizationId: str, groupId: str, name: str, **kwargs):
+ """
+ **Update a network group**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - name (string): The new name of the network group
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "updateOrganizationNetworksGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}"
+
+ body_params = [
+ "name",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationNetworksGroup: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationNetworksGroup(self, organizationId: str, groupId: str):
+ """
+ **Delete a network group**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-networks-group
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "deleteOrganizationNetworksGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}"
+
+ return self._session.delete(metadata, resource)
+
+ def bulkOrganizationNetworksGroupAssign(self, organizationId: str, groupId: str, networkIds: list, **kwargs):
+ """
+ **Add networks to a network group**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-networks-group-assign
+
+ - organizationId (string): Organization ID
+ - groupId (string): Group ID
+ - networkIds (array): A list of network IDs to add to the network group
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "bulkOrganizationNetworksGroupAssign",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}/bulkAssign"
+
+ body_params = [
+ "networkIds",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -5712,34 +9673,32 @@ def createOrganizationNetwork(self, organizationId: str, name: str, productTypes
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"createOrganizationNetwork: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"bulkOrganizationNetworksGroupAssign: ignoring unrecognized kwargs: {invalid}")
return self._session.post(metadata, resource, payload)
- def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds: list, **kwargs):
+ def bulkOrganizationNetworksGroupUnassign(self, organizationId: str, groupId: str, networkIds: list, **kwargs):
"""
- **Combine multiple networks into a single network**
- https://developer.cisco.com/meraki/api-v1/#!combine-organization-networks
+ **Remove networks from a network group**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-networks-group-unassign
- organizationId (string): Organization ID
- - name (string): The name of the combined network
- - networkIds (array): A list of the network IDs that will be combined. If an ID of a combined network is included in this list, the other networks in the list will be grouped into that network
- - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break. All networks that are part of this combined network will have their enrollment string appended by '-network_type'. If left empty, all exisitng enrollment strings will be deleted.
+ - groupId (string): Group ID
+ - networkIds (array): A list of network IDs to remove from the network group
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
- "tags": ["organizations", "configure", "networks"],
- "operation": "combineOrganizationNetworks",
+ "tags": ["organizations", "configure", "networks", "groups"],
+ "operation": "bulkOrganizationNetworksGroupUnassign",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/networks/combine"
+ groupId = urllib.parse.quote(str(groupId), safe="")
+ resource = f"/organizations/{organizationId}/networks/groups/{groupId}/bulkUnassign"
body_params = [
- "name",
"networkIds",
- "enrollmentString",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -5747,7 +9706,9 @@ def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"combineOrganizationNetworks: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"bulkOrganizationNetworksGroupUnassign: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.post(metadata, resource, payload)
@@ -5833,6 +9794,25 @@ def getNetworkMoves(self, organizationId: str, total_pages=1, direction="next",
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def deleteOrganizationOpenRoamingCertificate(self, organizationId: str, id: str):
+ """
+ **Delete an open roaming certificate.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-open-roaming-certificate
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "openRoaming", "certificates"],
+ "operation": "deleteOrganizationOpenRoamingCertificate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/openRoaming/certificates/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationOpenapiSpec(self, organizationId: str, **kwargs):
"""
**Return the OpenAPI Specification of the organization's API documentation in JSON**
@@ -5954,6 +9934,7 @@ def getOrganizationPoliciesGlobalFirewallRulesets(self, organizationId: str, tot
- direction (string): direction to paginate, either "next" (default) or "prev" page
- rulesetIds (array): Filter rulesets by IDs
- name (string): Filter rulesets by name (partial match, case-insensitive). If multiple instances are provided, only the last one is used.
+ - excludedPolicyIds (array): Filter out rulesets that are associated with the specified policy IDs
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
@@ -5971,6 +9952,7 @@ def getOrganizationPoliciesGlobalFirewallRulesets(self, organizationId: str, tot
query_params = [
"rulesetIds",
"name",
+ "excludedPolicyIds",
"perPage",
"startingAfter",
"endingBefore",
@@ -5979,6 +9961,7 @@ def getOrganizationPoliciesGlobalFirewallRulesets(self, organizationId: str, tot
array_params = [
"rulesetIds",
+ "excludedPolicyIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -6499,6 +10482,7 @@ def getOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
- rulesetIds (array): Filter assignments by ruleset IDs
- policyIds (array): Filter assignments by policy IDs
- assignmentIds (array): Filter assignments by assignment IDs
+ - staged (boolean): Filter assignments by whether or not they are staged
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
@@ -6517,6 +10501,7 @@ def getOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
"rulesetIds",
"policyIds",
"assignmentIds",
+ "staged",
"perPage",
"startingAfter",
"endingBefore",
@@ -6554,6 +10539,7 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
- rulesetId (string): ID of the ruleset to assign
- policyId (string): ID of the policy to assign the ruleset to
- priority (integer): Priority of the ruleset assignment (lower numbers = higher priority)
+ - staged (boolean): Stage an assignment without applying it immediately to the policy
"""
kwargs.update(locals())
@@ -6569,6 +10555,7 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
"rulesetId",
"policyId",
"priority",
+ "staged",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -6582,6 +10569,41 @@ def createOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
return self._session.post(metadata, resource, payload)
+ def commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments(
+ self, organizationId: str, policy: dict, **kwargs
+ ):
+ """
+ **Commit staged Organization-Wide Policy Ruleset Assignments**
+ https://developer.cisco.com/meraki/api-v1/#!commit-organization-policies-global-group-policies-firewall-rulesets-assignments
+
+ - organizationId (string): Organization ID
+ - policy (object): Policy in which all staged rulesets will be committed
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["organizations", "configure", "policies", "global", "group", "firewall", "rulesets", "assignments"],
+ "operation": "commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/policies/global/group/policies/firewall/rulesets/assignments/commit"
+
+ body_params = [
+ "policy",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"commitOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def updateOrganizationPoliciesGlobalGroupPoliciesFirewallRulesetsAssignment(
self, organizationId: str, assignmentId: str, **kwargs
):
@@ -7014,6 +11036,185 @@ def deleteOrganizationPolicyObject(self, organizationId: str, policyObjectId: st
return self._session.delete(metadata, resource)
+ def getOrganizationRoutingVrfs(self, organizationId: str, **kwargs):
+ """
+ **List existing organization-wide VRFs (Virtual Routing and Forwarding).**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-routing-vrfs
+
+ - organizationId (string): Organization ID
+ - vrfIds (array): IDs of the desired VRFs.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "getOrganizationRoutingVrfs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs"
+
+ query_params = [
+ "vrfIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "vrfIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationRoutingVrfs: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def createOrganizationRoutingVrf(self, organizationId: str, name: str, **kwargs):
+ """
+ **Add an organization-wide VRF (Virtual Routing and Forwarding)**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the VRF (Virtual Routing and Forwarding)
+ - description (string): Description of the VRF (Virtual Routing and Forwarding)
+ - routeDistinguisher (string): RD (Route Distinguisher) for the VRF (Virtual Routing and Forwarding)
+ - routeTarget (string): Route target are used to control the import and export of routes between VRFs
+ - appliance (object): This parameter is used to enable or disable the VRF on the WAN appliance
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "createOrganizationRoutingVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs"
+
+ body_params = [
+ "name",
+ "description",
+ "routeDistinguisher",
+ "routeTarget",
+ "appliance",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationRoutingVrf: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationRoutingVrfsOverviewByVrf(self, organizationId: str, **kwargs):
+ """
+ **List existing organization-wide VRFs (Virtual Routing and Forwarding) overviews.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-routing-vrfs-overview-by-vrf
+
+ - organizationId (string): Organization ID
+ - vrfIds (array): IDs of the desired VRFs.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "routing", "vrfs", "overview", "byVrf"],
+ "operation": "getOrganizationRoutingVrfsOverviewByVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/overview/byVrf"
+
+ query_params = [
+ "vrfIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "vrfIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationRoutingVrfsOverviewByVrf: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def updateOrganizationRoutingVrf(self, organizationId: str, vrfId: str, **kwargs):
+ """
+ **Update an organization-wide VRF (Virtual Routing and Forwarding)**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - vrfId (string): Vrf ID
+ - name (string): The name of the VRF (Virtual Routing and Forwarding)
+ - description (string): Description of the VRF (Virtual Routing and Forwarding)
+ - routeDistinguisher (string): RD (Route Distinguisher) for the VRF (Virtual Routing and Forwarding)
+ - routeTarget (string): Route target are used to control the import and export of routes between VRFs
+ - appliance (object): This parameter is used to enable or disable the VRF on the WAN appliance
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "updateOrganizationRoutingVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ vrfId = urllib.parse.quote(str(vrfId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/{vrfId}"
+
+ body_params = [
+ "name",
+ "description",
+ "routeDistinguisher",
+ "routeTarget",
+ "appliance",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationRoutingVrf: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationRoutingVrf(self, organizationId: str, vrfId: str):
+ """
+ **Delete a VRF (Virtual Routing and Forwarding) from a organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-routing-vrf
+
+ - organizationId (string): Organization ID
+ - vrfId (string): Vrf ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "routing", "vrfs"],
+ "operation": "deleteOrganizationRoutingVrf",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ vrfId = urllib.parse.quote(str(vrfId), safe="")
+ resource = f"/organizations/{organizationId}/routing/vrfs/{vrfId}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationSaml(self, organizationId: str):
"""
**Returns the SAML SSO enabled settings for an organization.**
@@ -7546,7 +11747,7 @@ def getOrganizationSaseSites(self, organizationId: str, total_pages=1, direction
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def attachOrganizationSaseSites(self, organizationId: str, **kwargs):
+ def attachOrganizationSaseSites(self, organizationId: str, items: list, **kwargs):
"""
**Attach sites in this organization to Secure Access**
https://developer.cisco.com/meraki/api-v1/#!attach-organization-sase-sites
@@ -7555,7 +11756,7 @@ def attachOrganizationSaseSites(self, organizationId: str, **kwargs):
- items (array): List of Meraki SD-WAN sites with the associated regions to be attached.
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
"tags": ["organizations", "configure", "sase", "sites"],
@@ -7687,9 +11888,114 @@ def updateOrganizationSaseSite(self, organizationId: str, siteId: str, **kwargs)
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"updateOrganizationSaseSite: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(f"updateOrganizationSaseSite: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationSites(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Lists unified site resources for an organization across Meraki networks and Catalyst Center sites**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sites
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 500. Default is 500.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - ids (array): Optional parameter to filter resources by unified resource ID. This filter uses multiple exact matches.
+ - resourceTypes (array): Optional parameter to filter resources by returned resource type.
+ - resourceTags (array): Optional parameter to filter resources by tag. By default all provided tags must match.
+ - resourceName (string): Optional parameter to filter resources by case-insensitive partial name match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "monitor", "sites"],
+ "operation": "getOrganizationSites",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sites"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "ids",
+ "resourceTypes",
+ "resourceTags",
+ "resourceName",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ids",
+ "resourceTypes",
+ "resourceTags",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSites: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSitesBuildings(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the buildings belonging to the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sites-buildings
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter buildings by one or more network IDs
+ - buildingIds (array): Optional parameter to filter buildings by one or more building IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "sites", "buildings"],
+ "operation": "getOrganizationSitesBuildings",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sites/buildings"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "buildingIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "buildingIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSitesBuildings: ignoring unrecognized kwargs: {invalid}")
- return self._session.put(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
def getOrganizationSnmp(self, organizationId: str):
"""
@@ -7762,6 +12068,45 @@ def updateOrganizationSnmp(self, organizationId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getOrganizationSnmpTrapsByNetwork(self, organizationId: str, **kwargs):
+ """
+ **Retrieve the SNMP trap configuration for the networks in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-snmp-traps-by-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): An optional parameter to filter SNMP trap configs by network IDs
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "snmp", "traps", "byNetwork"],
+ "operation": "getOrganizationSnmpTrapsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/snmp/traps/byNetwork"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSnmpTrapsByNetwork: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
def getOrganizationSplashAsset(self, organizationId: str, id: str):
"""
**Get a Splash Theme Asset**
@@ -7912,6 +12257,7 @@ def getOrganizationSummaryTopAppliancesByUtilization(self, organizationId: str,
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -7932,6 +12278,7 @@ def getOrganizationSummaryTopAppliancesByUtilization(self, organizationId: str,
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8057,6 +12404,7 @@ def getOrganizationSummaryTopClientsByUsage(self, organizationId: str, **kwargs)
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8077,6 +12425,7 @@ def getOrganizationSummaryTopClientsByUsage(self, organizationId: str, **kwargs)
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8104,6 +12453,7 @@ def getOrganizationSummaryTopClientsManufacturersByUsage(self, organizationId: s
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8124,6 +12474,7 @@ def getOrganizationSummaryTopClientsManufacturersByUsage(self, organizationId: s
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8151,6 +12502,7 @@ def getOrganizationSummaryTopDevicesByUsage(self, organizationId: str, **kwargs)
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8171,6 +12523,7 @@ def getOrganizationSummaryTopDevicesByUsage(self, organizationId: str, **kwargs)
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8198,6 +12551,7 @@ def getOrganizationSummaryTopDevicesModelsByUsage(self, organizationId: str, **k
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8218,6 +12572,7 @@ def getOrganizationSummaryTopDevicesModelsByUsage(self, organizationId: str, **k
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8247,6 +12602,7 @@ def getOrganizationSummaryTopNetworksByStatus(self, organizationId: str, total_p
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8267,6 +12623,7 @@ def getOrganizationSummaryTopNetworksByStatus(self, organizationId: str, total_p
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8294,6 +12651,7 @@ def getOrganizationSummaryTopSsidsByUsage(self, organizationId: str, **kwargs):
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8314,6 +12672,7 @@ def getOrganizationSummaryTopSsidsByUsage(self, organizationId: str, **kwargs):
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8341,6 +12700,7 @@ def getOrganizationSummaryTopSwitchesByEnergyUsage(self, organizationId: str, **
- organizationId (string): Organization ID
- networkTag (string): Match result to an exact network tag
- deviceTag (string): Match result to an exact device tag
+ - networkId (string): Match result to an exact network id
- quantity (integer): Set number of desired results to return. Default is 10. Maximum is 50
- ssidName (string): Filter results by ssid name
- usageUplink (string): Filter results by usage uplink
@@ -8361,6 +12721,7 @@ def getOrganizationSummaryTopSwitchesByEnergyUsage(self, organizationId: str, **
query_params = [
"networkTag",
"deviceTag",
+ "networkId",
"quantity",
"ssidName",
"usageUplink",
@@ -8489,6 +12850,137 @@ def getOrganizationWebhooksCallbacksStatus(self, organizationId: str, callbackId
return self._session.get(metadata, resource)
+ def getOrganizationWebhooksHttpServers(self, organizationId: str):
+ """
+ **List the HTTP servers for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-http-servers
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "getOrganizationWebhooksHttpServers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationWebhooksHttpServer(self, organizationId: str, name: str, url: str, **kwargs):
+ """
+ **Add an HTTP server to an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - name (string): A name for easy reference to the HTTP server
+ - url (string): The URL of the HTTP server
+ - sharedSecret (string): A shared secret that will be included in POSTs sent to the HTTP server. This secret can be used to verify that the request was sent by Meraki.
+ - payloadTemplate (object): The payload template to use when posting data to the HTTP server.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "createOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers"
+
+ body_params = [
+ "name",
+ "url",
+ "sharedSecret",
+ "payloadTemplate",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationWebhooksHttpServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWebhooksHttpServer(self, organizationId: str, id: str):
+ """
+ **Return an HTTP server for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "getOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationWebhooksHttpServer(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update an HTTP server for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): A name for easy reference to the HTTP server
+ - url (string): The URL of the HTTP server
+ - sharedSecret (string): A shared secret that will be included in POSTs sent to the HTTP server. This secret can be used to verify that the request was sent by Meraki.
+ - payloadTemplate (object): The payload template to use when posting data to the HTTP server.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "updateOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers/{id}"
+
+ body_params = [
+ "name",
+ "url",
+ "sharedSecret",
+ "payloadTemplate",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationWebhooksHttpServer: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationWebhooksHttpServer(self, organizationId: str, id: str):
+ """
+ **Delete an HTTP server from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-webhooks-http-server
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "httpServers"],
+ "operation": "deleteOrganizationWebhooksHttpServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/httpServers/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationWebhooksLogs(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Return the log of webhook POSTs sent**
@@ -8533,3 +13025,206 @@ def getOrganizationWebhooksLogs(self, organizationId: str, total_pages=1, direct
self._session._logger.warning(f"getOrganizationWebhooksLogs: ignoring unrecognized kwargs: {invalid}")
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWebhooksPayloadTemplates(self, organizationId: str):
+ """
+ **List the webhook payload templates for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-payload-templates
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "getOrganizationWebhooksPayloadTemplates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationWebhooksPayloadTemplate(self, organizationId: str, name: str, **kwargs):
+ """
+ **Create a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the new template
+ - body (string): The liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
+ - headers (array): The liquid template used with the webhook headers.
+ - bodyFile (string): A file containing liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
+ - headersFile (string): A file containing the liquid template used with the webhook headers.
+ - sharing (object): Information on which entities have access to the template
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "createOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates"
+
+ body_params = [
+ "name",
+ "body",
+ "headers",
+ "bodyFile",
+ "headersFile",
+ "sharing",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWebhooksPayloadTemplate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str):
+ """
+ **Get the webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "getOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ return self._session.get(metadata, resource)
+
+ def deleteOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str):
+ """
+ **Destroy a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "deleteOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationWebhooksPayloadTemplate(self, organizationId: str, payloadTemplateId: str, **kwargs):
+ """
+ **Update a webhook payload template for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-webhooks-payload-template
+
+ - organizationId (string): Organization ID
+ - payloadTemplateId (string): Payload template ID
+ - name (string): The name of the template
+ - body (string): The liquid template used for the body of the webhook message.
+ - headers (array): The liquid template used with the webhook headers.
+ - bodyFile (string): A file containing liquid template used for the body of the webhook message.
+ - headersFile (string): A file containing the liquid template used with the webhook headers.
+ - sharing (object): Information on which entities have access to the template
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "payloadTemplates"],
+ "operation": "updateOrganizationWebhooksPayloadTemplate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ payloadTemplateId = urllib.parse.quote(str(payloadTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/payloadTemplates/{payloadTemplateId}"
+
+ body_params = [
+ "name",
+ "body",
+ "headers",
+ "bodyFile",
+ "headersFile",
+ "sharing",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWebhooksPayloadTemplate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def createOrganizationWebhooksWebhookTest(self, organizationId: str, url: str, **kwargs):
+ """
+ **Send a test webhook for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-webhooks-webhook-test
+
+ - organizationId (string): Organization ID
+ - url (string): The URL where the test webhook will be sent
+ - sharedSecret (string): The shared secret the test webhook will send. Optional. Defaults to HTTP server's shared secret. Otherwise, defaults to an empty string.
+ - payloadTemplateId (string): The ID of the payload template of the test webhook. Defaults to the HTTP server's template ID if one exists for the given URL, or Generic template ID otherwise
+ - payloadTemplateName (string): The name of the payload template.
+ - alertTypeId (string): The type of alert which the test webhook will send. Optional. Defaults to insight_app_outage_start.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "webhookTests"],
+ "operation": "createOrganizationWebhooksWebhookTest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/webhookTests"
+
+ body_params = [
+ "url",
+ "sharedSecret",
+ "payloadTemplateId",
+ "payloadTemplateName",
+ "alertTypeId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWebhooksWebhookTest: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWebhooksWebhookTest(self, organizationId: str, webhookTestId: str):
+ """
+ **Return the status of a webhook test for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-webhooks-webhook-test
+
+ - organizationId (string): Organization ID
+ - webhookTestId (string): Webhook test ID
+ """
+
+ metadata = {
+ "tags": ["organizations", "configure", "webhooks", "webhookTests"],
+ "operation": "getOrganizationWebhooksWebhookTest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ webhookTestId = urllib.parse.quote(str(webhookTestId), safe="")
+ resource = f"/organizations/{organizationId}/webhooks/webhookTests/{webhookTestId}"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/api/secureConnect.py b/meraki/api/secureConnect.py
new file mode 100644
index 00000000..75a773ac
--- /dev/null
+++ b/meraki/api/secureConnect.py
@@ -0,0 +1,1084 @@
+import urllib
+
+
+class SecureConnect(object):
+ def __init__(self, session):
+ super(SecureConnect, self).__init__()
+ self._session = session
+
+ def getOrganizationSecureConnectPrivateApplicationGroups(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides a list of private application groups for an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-application-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - nameIncludes (string): Optional parameter to search the application group list by group name, case is ignored
+ - applicationGroupIds (array): List of application group ids attached to fetch
+ - sortBy (string): Optional parameter to specify the field used to sort objects.
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is asc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["applicationGroupId", "modifiedAt", "name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "getOrganizationSecureConnectPrivateApplicationGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "nameIncludes",
+ "applicationGroupIds",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "applicationGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPrivateApplicationGroups: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Creates a group of private applications to apply to policy**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - name (string): Application Group Name. This is required and cannot have any special characters other than spaces and hyphens
+ - description (string): Optional short description for application group
+ - applicationIds (array): List of application ids attached to this Private Application Group
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "createOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups"
+
+ body_params = [
+ "name",
+ "description",
+ "applicationIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateApplicationGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, id: str, name: str, **kwargs):
+ """
+ **Update an application group in an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Application Group Name. This is required and cannot have any special characters other than spaces and hyphens
+ - description (string): Optional short description for application group
+ - applicationIds (array): List of application ids attached to this Private Application Group
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "updateOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "applicationIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateApplicationGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, id: str, **kwargs):
+ """
+ **Deletes private application group from an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - force (boolean): Boolean flag to force delete application group, even if application group is in use by one or more rules.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "deleteOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateApplicationGroup(self, organizationId: str, id: str):
+ """
+ **Return the details of a specific private application group**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-application-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplicationGroups"],
+ "operation": "getOrganizationSecureConnectPrivateApplicationGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplicationGroups/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateApplications(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provides a list of private applications for an Organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-applications
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - nameIncludes (string): Optional parameter to filter the private applications list by application and associated application group names, case is ignored
+ - applicationGroupIds (array): Optional parameter for filtering the list of private applications belonging to the application group identified by the given IDs.
+ - appTypes (array): Optional parameter for filtering the list of private applications by applications that contain at least one destination with the specified accessType value.
+ - sortBy (string): Optional parameter to specify the field used to sort objects.
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is asc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["modifiedAt", "name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "getOrganizationSecureConnectPrivateApplications",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "nameIncludes",
+ "applicationGroupIds",
+ "appTypes",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "applicationGroupIds",
+ "appTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPrivateApplications: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectPrivateApplication(self, organizationId: str, name: str, destinations: list, **kwargs):
+ """
+ **Adds a new private application to the Organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - name (string): Name of Application. This is required and should be unique across all applications for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - destinations (array): List of IP address destinations.
+ - description (string): Optional Text description for Application
+ - appProtocol (string): Protocol for communication between proxy to private application. Applicable for Browser Based Access only.
+ - sni (string): Optional SNI. Applicable for Browser Based Access only. SNI should be a valid domain.
+ - externalFQDN (string): Cisco or Customer Managed URL for Application. Applicable for Browser Based Access only. This field is system generated based on the application name and organization ID and overrides user input in payload. This value must be unique across all applications for a given organization.
+ - sslVerificationEnabled (boolean): Enable Upstream SSL verification for the internally hosted URL by the customer. Applicable for Browser Based Access only. Default is true.
+ - applicationGroupIds (array): List of application group ids attached to this Private Application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "createOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications"
+
+ body_params = [
+ "name",
+ "description",
+ "destinations",
+ "appProtocol",
+ "sni",
+ "externalFQDN",
+ "sslVerificationEnabled",
+ "applicationGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateApplication: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateApplication(
+ self, organizationId: str, id: str, name: str, destinations: list, **kwargs
+ ):
+ """
+ **Updates a specific private application**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of Application. This is required and should be unique across all applications for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - destinations (array): List of IP address destinations.
+ - description (string): Optional Text description for Application
+ - appProtocol (string): Protocol for communication between proxy to private application. Applicable for Browser Based Access only.
+ - sni (string): Optional SNI. Applicable for Browser Based Access only. SNI should be a valid domain.
+ - externalFQDN (string): Cisco or Customer Managed URL for Application. Applicable for Browser Based Access only. This field is system generated based on the application name and organization ID and overrides user input in payload. This value must be unique across all applications for a given organization.
+ - sslVerificationEnabled (boolean): Enable Upstream SSL verification for the internally hosted URL by the customer. Applicable for Browser Based Access only. Default is true.
+ - applicationGroupIds (array): List of application group ids attached to this Private Application
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "updateOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "destinations",
+ "appProtocol",
+ "sni",
+ "externalFQDN",
+ "sslVerificationEnabled",
+ "applicationGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateApplication: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateApplication(self, organizationId: str, id: str, **kwargs):
+ """
+ **Deletes a specific private application**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - force (boolean): Boolean flag to force delete application, even if application is in use by one or more rules.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "deleteOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateApplication(self, organizationId: str, id: str):
+ """
+ **Return the details of a specific private application**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-application
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateApplications"],
+ "operation": "getOrganizationSecureConnectPrivateApplication",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateApplications/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateResourceGroups(self, organizationId: str):
+ """
+ **Provides a list of the private resource groups in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-resource-groups
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "getOrganizationSecureConnectPrivateResourceGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, name: str, **kwargs):
+ """
+ **Adds a new private resource group to an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - name (string): Name of group. This is required and should be unique across all groups for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - description (string): Optional text description for a group.
+ - resourceIds (array): List of resource ids assigned to this group.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "createOrganizationSecureConnectPrivateResourceGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups"
+
+ body_params = [
+ "name",
+ "description",
+ "resourceIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateResourceGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, id: str, name: str, **kwargs):
+ """
+ **Updates a specific private resource group.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of group. This is required and should be unique across all groups for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - description (string): Optional text description for a group.
+ - resourceIds (array): List of resource ids assigned to this group.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "updateOrganizationSecureConnectPrivateResourceGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "resourceIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateResourceGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateResourceGroup(self, organizationId: str, id: str):
+ """
+ **Deletes a specific private resource group.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-resource-group
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResourceGroups"],
+ "operation": "deleteOrganizationSecureConnectPrivateResourceGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResourceGroups/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPrivateResources(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provides a list of private resources for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-private-resources
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (string): Number of resources to return for a paginated response.
+ - startingAfter (string): The name of the resource to start after for a paginated response. Use '' for the first page.
+ - endingBefore (string): The name of the resource to end before for a paginated response. Use '' for the final page.
+ - sortBy (string): Parameter to specify the field used to sort objects, by default, resources are returned by name asc.
+ - sortOrder (string): Parameter to specify the direction used to sort objects, by default, resources are returned by name asc.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "getOrganizationSecureConnectPrivateResources",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPrivateResources: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectPrivateResource(
+ self, organizationId: str, name: str, accessTypes: list, resourceAddresses: list, **kwargs
+ ):
+ """
+ **Adds a new private resource to the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - name (string): Name of resource. This is required and should be unique across all resources for a given organization. Name cannot have any special characters other than spaces and hyphens.
+ - accessTypes (array): List of access types.
+ - resourceAddresses (array): List of resource addresses Protocols must be unique in this list.
+ - description (string): Optional text description for a resource.
+ - resourceGroupIds (array): List of resource group ids attached to this resource.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "createOrganizationSecureConnectPrivateResource",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources"
+
+ body_params = [
+ "name",
+ "description",
+ "accessTypes",
+ "resourceAddresses",
+ "resourceGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectPrivateResource: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSecureConnectPrivateResource(
+ self, organizationId: str, id: str, name: str, accessTypes: list, resourceAddresses: list, **kwargs
+ ):
+ """
+ **Updates a specific private resource.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of resource. This is required and should be unique across all resources for a given organization.Name cannot have any special characters other than spaces and hyphens.
+ - accessTypes (array): List of access types.
+ - resourceAddresses (array): List of resource addresses Protocols must be unique in this list.
+ - description (string): Optional text description for resource.
+ - resourceGroupIds (array): List of resource group ids attached to this resource.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "updateOrganizationSecureConnectPrivateResource",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "accessTypes",
+ "resourceAddresses",
+ "resourceGroupIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSecureConnectPrivateResource: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectPrivateResource(self, organizationId: str, id: str):
+ """
+ **Deletes a specific private resource**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-private-resource
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "privateResources"],
+ "operation": "deleteOrganizationSecureConnectPrivateResource",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/privateResources/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSecureConnectPublicApplications(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Provides a list of public applications for an Organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-public-applications
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - nameIncludes (string): Optional parameter to filter the public applications list by application name, case is ignored
+ - risks (array): List of risk levels to filter by
+ - categories (array): List of categories to filter by
+ - appTypes (array): List of app types to filter by
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - sortBy (string): Optional parameter to specify the field used to sort objects, by default, applications are returned by lastDetected desc
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is desc.
+ """
+
+ kwargs.update(locals())
+
+ if "sortBy" in kwargs:
+ options = ["appType", "category", "lastDetected", "name", "risk"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "publicApplications"],
+ "operation": "getOrganizationSecureConnectPublicApplications",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/publicApplications"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "nameIncludes",
+ "risks",
+ "categories",
+ "appTypes",
+ "t0",
+ "t1",
+ "timespan",
+ "sortBy",
+ "sortOrder",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "risks",
+ "categories",
+ "appTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectPublicApplications: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSecureConnectRegions(self, organizationId: str, **kwargs):
+ """
+ **List deployed cloud hubs and regions in this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-regions
+
+ - organizationId (string): Organization ID
+ - regionType (string): Filter results by region type
+ """
+
+ kwargs.update(locals())
+
+ if "regionType" in kwargs:
+ options = ["CNHE", "CloudHub", "Region", "ThirdParty"]
+ assert kwargs["regionType"] in options, (
+ f'''"regionType" cannot be "{kwargs["regionType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "regions"],
+ "operation": "getOrganizationSecureConnectRegions",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/regions"
+
+ query_params = [
+ "regionType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSecureConnectRegions: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSecureConnectRemoteAccessLog(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the latest 5000 events logged by remote access.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-log
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - identityids (string): An identity ID or comma-delimited list of identity ID.
+ - identitytypes (string): An identity type or comma-delimited list of identity type.
+ - connectionevent (string): Specify the type of connection event.
+ - anyconnectversions (string): Specify a comma-separated list of AnyConnect Roaming Security module
+ versions to filter the data.
+ - osversions (string): Specify a comma-separated list of OS versions to filter the data.
+ """
+
+ kwargs.update(locals())
+
+ if "connectionevent" in kwargs:
+ options = ["connected", "disconnected", "failed"]
+ assert kwargs["connectionevent"] in options, (
+ f'''"connectionevent" cannot be "{kwargs["connectionevent"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "monitor", "remoteAccessLog"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLog",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLog"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "identityids",
+ "identitytypes",
+ "connectionevent",
+ "anyconnectversions",
+ "osversions",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectRemoteAccessLog: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSecureConnectRemoteAccessLogsExports(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides a list of remote access logs exports for an Organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-logs-exports
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - status (string): Filter exports by status.
+ """
+
+ kwargs.update(locals())
+
+ if "status" in kwargs:
+ options = ["complete", "continue", "error", "in_progress", "new", "zip"]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLogsExports",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "status",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectRemoteAccessLogsExports: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, **kwargs):
+ """
+ **Creates an export for a provided timestamp interval.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-remote-access-logs-export
+
+ - organizationId (string): Organization ID
+ - t0 (string): The start of the interval, must be within the past 30 days. Must be provided with t1.
+ - t1 (string): The end of the interval, must not exceed the current date. Must be provided with t0.
+ - from (integer): Legacy start of the interval in epoch seconds, must be within the past 30 days. Must be provided with to.
+ - to (integer): Legacy end of the interval in epoch seconds, must not exceed the current date. Must be provided with from.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports"],
+ "operation": "createOrganizationSecureConnectRemoteAccessLogsExport",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports"
+
+ body_params = [
+ "t0",
+ "t1",
+ "from",
+ "to",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSecureConnectRemoteAccessLogsExport: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSecureConnectRemoteAccessLogsExportsDownload(
+ self, organizationId: str, id: str, fileType: str, **kwargs
+ ):
+ """
+ **Redirects to the download link of the completed export.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-logs-exports-download
+
+ - organizationId (string): Organization ID
+ - id (string): Export ID.
+ - fileType (string): Export download file type.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports", "download"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLogsExportsDownload",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports/download"
+
+ query_params = [
+ "id",
+ "fileType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSecureConnectRemoteAccessLogsExportsDownload: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, id: str):
+ """
+ **Return the details of a specific remote access logs export**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-remote-access-logs-export
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "remoteAccessLogsExports"],
+ "operation": "getOrganizationSecureConnectRemoteAccessLogsExport",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSecureConnectSites(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List sites in this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-secure-connect-sites
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): If provided, filters results by search string
+ - enrolledState (string): Filter results by sites that have already been enrolled or can be enrolled. Acceptable values are 'enrolled' or 'enrollable
+ """
+
+ kwargs.update(locals())
+
+ if "enrolledState" in kwargs:
+ options = ["enrollable", "enrolled"]
+ assert kwargs["enrolledState"] in options, (
+ f'''"enrolledState" cannot be "{kwargs["enrolledState"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "sites"],
+ "operation": "getOrganizationSecureConnectSites",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "enrolledState",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSecureConnectSites: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSecureConnectSite(self, organizationId: str, **kwargs):
+ """
+ **Enroll sites in this organization to Secure Connect**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-secure-connect-site
+
+ - organizationId (string): Organization ID
+ - enrollments (array): List of Meraki SD-WAN sites with the associated regions to be enrolled.
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "sites"],
+ "operation": "createOrganizationSecureConnectSite",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ body_params = [
+ "enrollments",
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationSecureConnectSite: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationSecureConnectSites(self, organizationId: str, **kwargs):
+ """
+ **Detach given sites from Secure Connect**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-secure-connect-sites
+
+ - organizationId (string): Organization ID
+ - sites (array): List of site IDs to detach
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["secureConnect", "configure", "sites"],
+ "operation": "deleteOrganizationSecureConnectSites",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/secureConnect/sites"
+
+ return self._session.delete(metadata, resource)
diff --git a/meraki/api/sensor.py b/meraki/api/sensor.py
index 2807976a..9c901dee 100644
--- a/meraki/api/sensor.py
+++ b/meraki/api/sensor.py
@@ -74,9 +74,10 @@ def createDeviceSensorCommand(self, serial: str, operation: str, **kwargs):
- serial (string): Serial
- operation (string): Operation to run on the sensor. 'enableDownstreamPower', 'disableDownstreamPower', and 'cycleDownstreamPower' turn power on/off to the device that is connected downstream of an MT40 power monitor. 'refreshData' causes an MT15 or MT40 device to upload its latest readings so that they are immediately available in the Dashboard API.
+ - arguments (array): Additional options to provide to commands run on the sensor, each with a corresponding 'name' and 'value'.
"""
- kwargs = locals()
+ kwargs.update(locals())
if "operation" in kwargs:
options = ["cycleDownstreamPower", "disableDownstreamPower", "enableDownstreamPower", "refreshData"]
@@ -92,6 +93,7 @@ def createDeviceSensorCommand(self, serial: str, operation: str, **kwargs):
resource = f"/devices/{serial}/sensor/commands"
body_params = [
+ "arguments",
"operation",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -456,6 +458,103 @@ def getNetworkSensorRelationships(self, networkId: str):
return self._session.get(metadata, resource)
+ def getNetworkSensorSchedules(self, networkId: str):
+ """
+ **Returns a list of all sensor schedules.**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sensor-schedules
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["sensor", "configure", "schedules"],
+ "operation": "getNetworkSensorSchedules",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sensor/schedules"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSensorAlerts(self, organizationId: str, networkIds: list, total_pages=1, direction="next", **kwargs):
+ """
+ **Return a list of sensor alert events**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sensor-alerts
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filters alerts by network. For now, this must be a single network ID.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 365 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 365 days. The default is 365 days.
+ - sensorSerial (string): Filters alerts to those triggered by this sensor.
+ - triggerMetric (string): Filters alerts to those triggered by this metric.
+ """
+
+ kwargs.update(locals())
+
+ if "triggerMetric" in kwargs:
+ options = [
+ "apparentPower",
+ "co2",
+ "current",
+ "door",
+ "frequency",
+ "humidity",
+ "indoorAirQuality",
+ "noise",
+ "pm25",
+ "powerFactor",
+ "realPower",
+ "temperature",
+ "tvoc",
+ "upstreamPower",
+ "voltage",
+ "water",
+ ]
+ assert kwargs["triggerMetric"] in options, (
+ f'''"triggerMetric" cannot be "{kwargs["triggerMetric"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["sensor", "monitor", "alerts"],
+ "operation": "getOrganizationSensorAlerts",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sensor/alerts"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "sensorSerial",
+ "networkIds",
+ "triggerMetric",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSensorAlerts: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationSensorGatewaysConnectionsLatest(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Returns latest sensor-gateway connectivity data.**
@@ -564,6 +663,72 @@ def getOrganizationSensorReadingsHistory(self, organizationId: str, total_pages=
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationSensorReadingsHistoryByInterval(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return all reported readings from sensors in a given timespan, summarized as a series of intervals, sorted by interval start time in descending order**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sensor-readings-history-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 730 days, 11 hours, 38 minutes, and 24 seconds from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 730 days, 11 hours, 38 minutes, and 24 seconds after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 730 days, 11 hours, 38 minutes, and 24 seconds. The default is 7 days. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 15, 120, 300, 900, 3600, 14400, 86400, 604800. The default is 86400. Interval is calculated if time params are provided.
+ - networkIds (array): Optional parameter to filter readings by network.
+ - serials (array): Optional parameter to filter readings by sensor.
+ - metrics (array): Types of sensor readings to retrieve. If no metrics are supplied, all available types of readings will be retrieved.
+ - models (array): Optional parameter to filter readings by one or more models.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sensor", "monitor", "readings", "history", "byInterval"],
+ "operation": "getOrganizationSensorReadingsHistoryByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sensor/readings/history/byInterval"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "serials",
+ "metrics",
+ "models",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "metrics",
+ "models",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSensorReadingsHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationSensorReadingsLatest(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**Return the latest available reading for each metric from each sensor, sorted by sensor serial**
diff --git a/meraki/api/sm.py b/meraki/api/sm.py
index c79ab088..e4f811c1 100644
--- a/meraki/api/sm.py
+++ b/meraki/api/sm.py
@@ -894,6 +894,379 @@ def getNetworkSmProfiles(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkSmScripts(self, networkId: str):
+ """
+ **List the scripts for this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-scripts
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "getNetworkSmScripts",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts"
+
+ return self._session.get(metadata, resource)
+
+ def createNetworkSmScript(self, networkId: str, name: str, platform: str, **kwargs):
+ """
+ **Create a new script**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-script
+
+ - networkId (string): Network ID
+ - name (string): Unique name to identify this script.
+ - platform (string): Platform that this script will run on.
+ - scope (string): The target scope of the script. (Either scope or targetGroupId must be present.)
+ - tags (array): The target tags of the script as an array of strings. Required if scope is one of withAny, withoutAny, withAll, withoutAll.
+ - targetGroupId (string): The tag target group ID that should be used to scope devices. Either scope or targetGroupId must be present.
+ - description (string): Description of this script.
+ - runAsUsername (string): Username that script should run as.
+ - externalSource (object): Properties for a script provided by a url instead of an upload
+ - upload (object): Properties for a script provided as an upload instead of a url
+ - schedule (object): When the script is intended to run
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs and kwargs["platform"] is not None:
+ options = ["Windows", "macOS"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+ if "scope" in kwargs:
+ options = ["all", "none", "withAll", "withAny", "withoutAll", "withoutAny"]
+ assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "createNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts"
+
+ body_params = [
+ "name",
+ "platform",
+ "scope",
+ "tags",
+ "targetGroupId",
+ "description",
+ "runAsUsername",
+ "externalSource",
+ "upload",
+ "schedule",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSmScript: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def createNetworkSmScriptsJob(self, networkId: str, scriptId: str, **kwargs):
+ """
+ **Create a job that will run a script on a set of devices**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-scripts-job
+
+ - networkId (string): Network ID
+ - scriptId (string): ID of script that should be run on the matching devices
+ - deviceIds (array): List of device IDs to run that should run this script
+ - deviceFilter (string): Create job on all devices in-scope or devices that have failed to run this script
+ """
+
+ kwargs.update(locals())
+
+ if "deviceFilter" in kwargs:
+ options = ["All", "Failed"]
+ assert kwargs["deviceFilter"] in options, (
+ f'''"deviceFilter" cannot be "{kwargs["deviceFilter"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "jobs"],
+ "operation": "createNetworkSmScriptsJob",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs"
+
+ body_params = [
+ "scriptId",
+ "deviceIds",
+ "deviceFilter",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSmScriptsJob: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getNetworkSmScriptsJobsStatusesLatestByScriptByInterval(self, networkId: str, **kwargs):
+ """
+ **List the latest script job statuses by script and by interval**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-scripts-jobs-statuses-latest-by-script-by-interval
+
+ - networkId (string): Network ID
+ - scriptIds (array): List of script IDs to fetch statuses
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 180 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 180 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "jobs", "statuses", "latest", "byScript", "byInterval"],
+ "operation": "getNetworkSmScriptsJobsStatusesLatestByScriptByInterval",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs/statuses/latest/byScript/byInterval"
+
+ query_params = [
+ "scriptIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "scriptIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkSmScriptsJobsStatusesLatestByScriptByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getNetworkSmScriptsJobsStatusesLatestByScriptAndDevice(
+ self, networkId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List jobs for a given script and/or device**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-scripts-jobs-statuses-latest-by-script-and-device
+
+ - networkId (string): Network ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - deviceId (string): Query parameter for filtering the list of script job statuses to those belonging to the specified deviceId.
+ - scriptId (string): Query parameter for filtering the list of script job statuses to those belonging to the specified script.
+ - inScopeOnly (boolean): If true, show only job statuses for scripts or devices that are in scope. This only applies when either deviceId or scriptId are given.
+ - status (string): Query parameter for filtering the list of job statuses to those having the specified status.
+ - sortOrder (string): Query parameter for specifying the direction of sorting to use for the given sortKey. This param is overridden if startingAfter or endingBefore is provided.
+ - sortKey (string): Query parameter to sort the script tasks by the value of the specified key. This param is overridden if startingAfter or endingBefore is provided.
+ - perPage (integer): Number of results to show per page.
+ - startingAfter (string): A statusId. Start the search cursor after the specified Status record.
+ - endingBefore (string): A statusId. Search backward with the cursor starting before the specified Status record.
+ """
+
+ kwargs.update(locals())
+
+ if "status" in kwargs:
+ options = [
+ "cancelled",
+ "command failed",
+ "completed",
+ "created",
+ "enqueued",
+ "error",
+ "failed",
+ "pending",
+ "running",
+ "success",
+ "unknown",
+ ]
+ assert kwargs["status"] in options, (
+ f'''"status" cannot be "{kwargs["status"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "sortKey" in kwargs:
+ options = ["completedAt", "createdAt", "enqueuedAt", "status", "updatedAt"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "jobs", "statuses", "latest", "byScriptAndDevice"],
+ "operation": "getNetworkSmScriptsJobsStatusesLatestByScriptAndDevice",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/jobs/statuses/latest/byScriptAndDevice"
+
+ query_params = [
+ "deviceId",
+ "scriptId",
+ "inScopeOnly",
+ "status",
+ "sortOrder",
+ "sortKey",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkSmScriptsJobsStatusesLatestByScriptAndDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createNetworkSmScriptsUpload(self, networkId: str, size: str, **kwargs):
+ """
+ **Creates an upload URL that can be used to upload a script**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-sm-scripts-upload
+
+ - networkId (string): Network ID
+ - size (string): Size of the file in bytes that will be uploaded.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts", "uploads"],
+ "operation": "createNetworkSmScriptsUpload",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/uploads"
+
+ body_params = [
+ "size",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSmScriptsUpload: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getNetworkSmScript(self, networkId: str, scriptId: str):
+ """
+ **Return a script**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "getNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkSmScript(self, networkId: str, scriptId: str, **kwargs):
+ """
+ **Update an existing script**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ - name (string): Unique name to identify this script.
+ - platform (string): Platform that this script will run on.
+ - scope (string): The target scope of the script. (Either scope or targetGroupId must be present.)
+ - tags (array): The target tags of the script as an array of strings. Required if scope is one of withAny, withoutAny, withAll, withoutAll.
+ - targetGroupId (string): The tag target group ID that should be used to scope devices. Either scope or targetGroupId must be present.
+ - description (string): Description of this script.
+ - runAsUsername (string): Username that script should run as.
+ - externalSource (object): Properties for a script provided by a url instead of an upload
+ - upload (object): Properties for a script provided as an upload instead of a url
+ - schedule (object): When the script is intended to run
+ """
+
+ kwargs.update(locals())
+
+ if "platform" in kwargs and kwargs["platform"] is not None:
+ options = ["Windows", "macOS"]
+ assert kwargs["platform"] in options, (
+ f'''"platform" cannot be "{kwargs["platform"]}", & must be set to one of: {options}'''
+ )
+ if "scope" in kwargs:
+ options = ["all", "none", "withAll", "withAny", "withoutAll", "withoutAny"]
+ assert kwargs["scope"] in options, f'''"scope" cannot be "{kwargs["scope"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "updateNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ body_params = [
+ "name",
+ "platform",
+ "scope",
+ "tags",
+ "targetGroupId",
+ "description",
+ "runAsUsername",
+ "externalSource",
+ "upload",
+ "schedule",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSmScript: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteNetworkSmScript(self, networkId: str, scriptId: str):
+ """
+ **Delete a script**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-sm-script
+
+ - networkId (string): Network ID
+ - scriptId (string): Script ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "scripts"],
+ "operation": "deleteNetworkSmScript",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ scriptId = urllib.parse.quote(str(scriptId), safe="")
+ resource = f"/networks/{networkId}/sm/scripts/{scriptId}"
+
+ return self._session.delete(metadata, resource)
+
def getNetworkSmTargetGroups(self, networkId: str, **kwargs):
"""
**List the target groups in this network**
@@ -1396,6 +1769,187 @@ def getOrganizationSmApnsCert(self, organizationId: str):
return self._session.get(metadata, resource)
+ def createOrganizationSmAppleCloudEnrollmentSyncJob(self, organizationId: str, **kwargs):
+ """
+ **Enqueue a sync job for an ADE account**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-sm-apple-cloud-enrollment-sync-job
+
+ - organizationId (string): Organization ID
+ - adeAccountId (string): ADE Account ID
+ - fullSync (boolean): Whether or not job is full sync (defaults to full sync)
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sm", "configure", "apple", "cloudEnrollment", "syncJobs"],
+ "operation": "createOrganizationSmAppleCloudEnrollmentSyncJob",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/apple/cloudEnrollment/syncJobs"
+
+ body_params = [
+ "adeAccountId",
+ "fullSync",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSmAppleCloudEnrollmentSyncJob: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSmAppleCloudEnrollmentSyncJob(self, organizationId: str, syncJobId: str):
+ """
+ **Retrieve the status of an ADE sync job**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sm-apple-cloud-enrollment-sync-job
+
+ - organizationId (string): Organization ID
+ - syncJobId (string): Sync job ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "apple", "cloudEnrollment", "syncJobs"],
+ "operation": "getOrganizationSmAppleCloudEnrollmentSyncJob",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ syncJobId = urllib.parse.quote(str(syncJobId), safe="")
+ resource = f"/organizations/{organizationId}/sm/apple/cloudEnrollment/syncJobs/{syncJobId}"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationSmBulkEnrollmentToken(self, organizationId: str, networkId: str, expiresAt: str, **kwargs):
+ """
+ **Create a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - networkId (string): The id of the associated node_group.
+ - expiresAt (string): The expiration date.
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "createOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token"
+
+ body_params = [
+ "networkId",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSmBulkEnrollmentToken: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str):
+ """
+ **Return a BulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "getOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str, **kwargs):
+ """
+ **Update a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ - networkId (string): The id of the associated node_group.
+ - expiresAt (string): The expiration date.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "updateOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ body_params = [
+ "networkId",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSmBulkEnrollmentToken: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSmBulkEnrollmentToken(self, organizationId: str, tokenId: str):
+ """
+ **Delete a PccBulkEnrollmentToken**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-sm-bulk-enrollment-token
+
+ - organizationId (string): Organization ID
+ - tokenId (string): Token ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "token"],
+ "operation": "deleteOrganizationSmBulkEnrollmentToken",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ tokenId = urllib.parse.quote(str(tokenId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/token/{tokenId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSmBulkEnrollmentTokens(self, organizationId: str):
+ """
+ **List all BulkEnrollmentTokens for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-sm-bulk-enrollment-tokens
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["sm", "configure", "bulkEnrollment", "tokens"],
+ "operation": "getOrganizationSmBulkEnrollmentTokens",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/sm/bulkEnrollment/tokens"
+
+ return self._session.get(metadata, resource)
+
def updateOrganizationSmSentryPoliciesAssignments(self, organizationId: str, items: list, **kwargs):
"""
**Update an Organizations Sentry Policies using the provided list**
diff --git a/meraki/api/support.py b/meraki/api/support.py
new file mode 100644
index 00000000..9fe7ab7e
--- /dev/null
+++ b/meraki/api/support.py
@@ -0,0 +1,24 @@
+import urllib
+
+
+class Support(object):
+ def __init__(self, session):
+ super(Support, self).__init__()
+ self._session = session
+
+ def getOrganizationSupportSalesRepresentatives(self, organizationId: str):
+ """
+ **Returns the organization's sales representatives**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-support-sales-representatives
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["support", "monitor", "salesRepresentatives"],
+ "operation": "getOrganizationSupportSalesRepresentatives",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/support/salesRepresentatives"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/api/switch.py b/meraki/api/switch.py
index 86ac6cc3..327f942b 100644
--- a/meraki/api/switch.py
+++ b/meraki/api/switch.py
@@ -6,14 +6,17 @@ def __init__(self, session):
super(Switch, self).__init__()
self._session = session
- def getDeviceSwitchPorts(self, serial: str):
+ def getDeviceSwitchPorts(self, serial: str, **kwargs):
"""
**List the switch ports for a switch**
https://developer.cisco.com/meraki/api-v1/#!get-device-switch-ports
- serial (string): Serial
+ - hideDefaultPorts (boolean): Optional flag that, when true, will hide modular switchports that may not be connected to the device at the moment
"""
+ kwargs.update(locals())
+
metadata = {
"tags": ["switch", "configure", "ports"],
"operation": "getDeviceSwitchPorts",
@@ -21,7 +24,18 @@ def getDeviceSwitchPorts(self, serial: str):
serial = urllib.parse.quote(str(serial), safe="")
resource = f"/devices/{serial}/switch/ports"
- return self._session.get(metadata, resource)
+ query_params = [
+ "hideDefaultPorts",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getDeviceSwitchPorts: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
def cycleDeviceSwitchPorts(self, serial: str, ports: list, **kwargs):
"""
@@ -54,6 +68,46 @@ def cycleDeviceSwitchPorts(self, serial: str, ports: list, **kwargs):
return self._session.post(metadata, resource, payload)
+ def updateDeviceSwitchPortsMirror(self, serial: str, source: dict, destination: dict, **kwargs):
+ """
+ **Update a port mirror**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-switch-ports-mirror
+
+ - serial (string): The switch identifier
+ - source (object): Source ports mirror configuration
+ - destination (object): Destination port mirror configuration
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "mirror"],
+ "operation": "updateDeviceSwitchPortsMirror",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/switch/ports/mirror"
+
+ body_params = [
+ "serial",
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceSwitchPortsMirror: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getDeviceSwitchPortsStatuses(self, serial: str, **kwargs):
"""
**Return the status for all the ports of a switch**
@@ -154,6 +208,7 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
- vlan (integer): The VLAN of the switch port. For a trunk port, this is the native VLAN. A null value will clear the value set for trunk ports.
- voiceVlan (integer): The voice VLAN of the switch port. Only applicable to access ports.
- allowedVlans (string): The VLANs allowed on the switch port. Only applicable to trunk ports.
+ - activeVlans (string): The VLANs that are active on the switch port. Only applicable to trunk ports.
- isolationEnabled (boolean): The isolation status of the switch port.
- rstpEnabled (boolean): The rapid spanning tree protocol status.
- stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard').
@@ -214,6 +269,7 @@ def updateDeviceSwitchPort(self, serial: str, portId: str, **kwargs):
"vlan",
"voiceVlan",
"allowedVlans",
+ "activeVlans",
"isolationEnabled",
"rstpEnabled",
"stpGuard",
@@ -303,6 +359,12 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -337,6 +399,12 @@ def createDeviceSwitchRoutingInterface(self, serial: str, name: str, **kwargs):
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -386,6 +454,12 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -417,6 +491,12 @@ def updateDeviceSwitchRoutingInterface(self, serial: str, interfaceId: str, **kw
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -1388,14 +1468,17 @@ def updateNetworkSwitchDscpToCosMappings(self, networkId: str, mappings: list, *
return self._session.put(metadata, resource, payload)
- def getNetworkSwitchLinkAggregations(self, networkId: str):
+ def getNetworkSwitchLinkAggregations(self, networkId: str, **kwargs):
"""
**List link aggregation groups**
https://developer.cisco.com/meraki/api-v1/#!get-network-switch-link-aggregations
- networkId (string): Network ID
+ - serials (array): Optional parameter to filter by device serial numbers. Matches multiple exact serials.
"""
+ kwargs.update(locals())
+
metadata = {
"tags": ["switch", "configure", "linkAggregations"],
"operation": "getNetworkSwitchLinkAggregations",
@@ -1403,7 +1486,26 @@ def getNetworkSwitchLinkAggregations(self, networkId: str):
networkId = urllib.parse.quote(str(networkId), safe="")
resource = f"/networks/{networkId}/switch/linkAggregations"
- return self._session.get(metadata, resource)
+ query_params = [
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getNetworkSwitchLinkAggregations: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
"""
@@ -1413,6 +1515,7 @@ def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
- networkId (string): Network ID
- switchPorts (array): Array of switch or stack ports for creating aggregation group. Minimum 2 and maximum 8 ports are supported.
- switchProfilePorts (array): Array of switch profile ports for creating aggregation group. Minimum 2 and maximum 8 ports are supported.
+ - esiMhPairId (string): ESI-MH pair ID. Required when creating a downstream aggregation across ESI-MH pair member switches.
"""
kwargs.update(locals())
@@ -1427,6 +1530,7 @@ def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs):
body_params = [
"switchPorts",
"switchProfilePorts",
+ "esiMhPairId",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1652,6 +1756,126 @@ def updateNetworkSwitchPortSchedule(self, networkId: str, portScheduleId: str, *
return self._session.put(metadata, resource, payload)
+ def getNetworkSwitchPortsProfiles(self, networkId: str):
+ """
+ **List the port profiles in a network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-switch-ports-profiles
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "getNetworkSwitchPortsProfiles",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles"
+
+ return self._session.get(metadata, resource)
+
+ def createNetworkSwitchPortsProfile(self, networkId: str, **kwargs):
+ """
+ **Create a port profile in a network**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "createNetworkSwitchPortsProfile",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles"
+
+ body_params = [
+ "name",
+ "description",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createNetworkSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateNetworkSwitchPortsProfile(self, networkId: str, id: str, **kwargs):
+ """
+ **Update a port profile in a network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - id (string): ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "updateNetworkSwitchPortsProfile",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteNetworkSwitchPortsProfile(self, networkId: str, id: str):
+ """
+ **Delete a port profile from a network**
+ https://developer.cisco.com/meraki/api-v1/#!delete-network-switch-ports-profile
+
+ - networkId (string): Network ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "deleteNetworkSwitchPortsProfile",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/networks/{networkId}/switch/ports/profiles/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getNetworkSwitchQosRules(self, networkId: str):
"""
**List quality of service rules**
@@ -1855,6 +2079,64 @@ def updateNetworkSwitchQosRule(self, networkId: str, qosRuleId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getNetworkSwitchRaGuardPolicy(self, networkId: str):
+ """
+ **Return RA Guard settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-switch-ra-guard-policy
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "raGuardPolicy"],
+ "operation": "getNetworkSwitchRaGuardPolicy",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/raGuardPolicy"
+
+ return self._session.get(metadata, resource)
+
+ def updateNetworkSwitchRaGuardPolicy(self, networkId: str, **kwargs):
+ """
+ **Update RA Guard settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-ra-guard-policy
+
+ - networkId (string): Network ID
+ - defaultPolicy (string): New Router Advertisers are 'allowed' or 'blocked'. Default value is 'allowed'.
+ - allowedServers (array): List the MAC addresses of Router Advertisers to permit on the network when defaultPolicy is set to blocked.
+ - blockedServers (array): List the MAC addresses of Router Advertisers to block on the network when defaultPolicy is set to allowed.
+ """
+
+ kwargs.update(locals())
+
+ if "defaultPolicy" in kwargs:
+ options = ["allowed", "blocked"]
+ assert kwargs["defaultPolicy"] in options, (
+ f'''"defaultPolicy" cannot be "{kwargs["defaultPolicy"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["switch", "configure", "raGuardPolicy"],
+ "operation": "updateNetworkSwitchRaGuardPolicy",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/raGuardPolicy"
+
+ body_params = [
+ "defaultPolicy",
+ "allowedServers",
+ "blockedServers",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchRaGuardPolicy: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSwitchRoutingMulticast(self, networkId: str):
"""
**Return multicast settings for a network**
@@ -2175,6 +2457,45 @@ def updateNetworkSwitchSettings(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkSwitchSpanningTree(self, networkId: str, **kwargs):
+ """
+ **Updates Spanning Tree configuration**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-spanning-tree
+
+ - networkId (string): Network ID
+ - enabled (boolean): Network-level spanning Tree enable
+ - mode (string): Catalyst Spanning Tree Protocol mode (mst, rpvst+)
+ - priorities (array): Spanning tree priority for switches/stacks or switch templates. An empty array will clear the priority settings.
+ """
+
+ kwargs.update(locals())
+
+ if "mode" in kwargs:
+ options = ["mst", "rpvst+"]
+ assert kwargs["mode"] in options, f'''"mode" cannot be "{kwargs["mode"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "spanningTree"],
+ "operation": "updateNetworkSwitchSpanningTree",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/switch/spanningTree"
+
+ body_params = [
+ "enabled",
+ "mode",
+ "priorities",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchSpanningTree: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkSwitchStacks(self, networkId: str):
"""
**List the switch stacks in a network**
@@ -2331,6 +2652,49 @@ def addNetworkSwitchStack(self, networkId: str, switchStackId: str, serial: str,
return self._session.post(metadata, resource, payload)
+ def updateNetworkSwitchStackPortsMirror(
+ self, networkId: str, switchStackId: str, source: dict, destination: dict, **kwargs
+ ):
+ """
+ **Update switch port mirrors for switch stacks**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-switch-stack-ports-mirror
+
+ - networkId (string): Network ID
+ - switchStackId (string): Switch stack ID
+ - source (object): Source port details
+ - destination (object): Destination port Details
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "stacks", "ports", "mirror"],
+ "operation": "updateNetworkSwitchStackPortsMirror",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ switchStackId = urllib.parse.quote(str(switchStackId), safe="")
+ resource = f"/networks/{networkId}/switch/stacks/{switchStackId}/ports/mirror"
+
+ body_params = [
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkSwitchStackPortsMirror: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def removeNetworkSwitchStack(self, networkId: str, switchStackId: str, serial: str, **kwargs):
"""
**Remove a switch from a stack**
@@ -2426,6 +2790,12 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -2461,6 +2831,12 @@ def createNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -2515,6 +2891,12 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
- multicastRouting (string): Enable multicast support if, multicast routing between VLANs is required. Options are: 'disabled', 'enabled' or 'IGMP snooping querier'. Default is 'disabled'.
- vlanId (integer): The VLAN this L3 interface is on. VLAN must be between 1 and 4094.
- defaultGateway (string): The next hop for any traffic that isn't going to a directly connected subnet or over a static route. This IP address must exist in a subnet with a L3 interface. Required if this is the first IPv4 interface.
+ - isSwitchDefaultGateway (boolean): When true, the switch uses the IPv4 uplink gateway as its IPv4 default gateway. This can only be set if the interface is designated as the IPv4 uplink and the switch is running IOS XE version >= 17.18.3.
+ - uplinkV4 (boolean): When true, this interface is used as static IPv4 uplink.
+ - candidateUplinkV4 (boolean): When true, this interface is a UAC candidate for IPv4 Uplink.
+ - uplinkV6 (boolean): When true, this interface is used as static IPv6 uplink.
+ - staticV4Dns1 (string): Primary IPv4 DNS server address
+ - staticV4Dns2 (string): Secondary IPv4 DNS server address
- ospfSettings (object): The OSPF routing settings of the interface.
- ipv6 (object): The IPv6 settings of the interface.
- vrf (object): The VRF settings of the interface. Requires IOS XE 17.18 or higher
@@ -2547,6 +2929,12 @@ def updateNetworkSwitchStackRoutingInterface(self, networkId: str, switchStackId
"multicastRouting",
"vlanId",
"defaultGateway",
+ "isSwitchDefaultGateway",
+ "uplinkV4",
+ "candidateUplinkV4",
+ "uplinkV6",
+ "staticV4Dns1",
+ "staticV4Dns2",
"ospfSettings",
"ipv6",
"vrf",
@@ -2946,31 +3334,85 @@ def updateNetworkSwitchStp(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
- def getOrganizationConfigTemplateSwitchProfiles(self, organizationId: str, configTemplateId: str):
+ def getOrganizationConfigTemplatesSwitchProfilesPortsMirrorsBySwitchProfile(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **List the switch templates for your switch template configuration**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profiles
+ **list the port mirror configurations in an organization by switch profile**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-config-templates-switch-profiles-ports-mirrors-by-switch-profile
- organizationId (string): Organization ID
- - configTemplateId (string): Config template ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - configTemplateIds (array): Optional parameter to filter the result set by the included set of config template IDs
+ - ids (array): A list of switch profile ids. The returned profiles will be filtered to only include these ids.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
+ kwargs.update(locals())
+
metadata = {
- "tags": ["switch", "configure", "configTemplates", "profiles"],
- "operation": "getOrganizationConfigTemplateSwitchProfiles",
+ "tags": ["switch", "configure", "configTemplates", "profiles", "ports", "mirrors", "bySwitchProfile"],
+ "operation": "getOrganizationConfigTemplatesSwitchProfilesPortsMirrorsBySwitchProfile",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
- resource = f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles"
+ resource = f"/organizations/{organizationId}/configTemplates/switch/profiles/ports/mirrors/bySwitchProfile"
- return self._session.get(metadata, resource)
+ query_params = [
+ "configTemplateIds",
+ "ids",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- def getOrganizationConfigTemplateSwitchProfilePorts(self, organizationId: str, configTemplateId: str, profileId: str):
- """
- **Return all the ports of a switch template**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profile-ports
+ array_params = [
+ "configTemplateIds",
+ "ids",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
- - organizationId (string): Organization ID
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationConfigTemplatesSwitchProfilesPortsMirrorsBySwitchProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationConfigTemplateSwitchProfiles(self, organizationId: str, configTemplateId: str):
+ """
+ **List the switch templates for your switch template configuration**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profiles
+
+ - organizationId (string): Organization ID
+ - configTemplateId (string): Config template ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "configTemplates", "profiles"],
+ "operation": "getOrganizationConfigTemplateSwitchProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
+ resource = f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationConfigTemplateSwitchProfilePorts(self, organizationId: str, configTemplateId: str, profileId: str):
+ """
+ **Return all the ports of a switch template**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-config-template-switch-profile-ports
+
+ - organizationId (string): Organization ID
- configTemplateId (string): Config template ID
- profileId (string): Profile ID
"""
@@ -2986,6 +3428,55 @@ def getOrganizationConfigTemplateSwitchProfilePorts(self, organizationId: str, c
return self._session.get(metadata, resource)
+ def updateOrganizationConfigTemplateSwitchProfilePortsMirror(
+ self, organizationId: str, configTemplateId: str, profileId: str, source: dict, destination: dict, **kwargs
+ ):
+ """
+ **Update a port mirror**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-config-template-switch-profile-ports-mirror
+
+ - organizationId (string): Organization ID
+ - configTemplateId (string): Config template ID
+ - profileId (string): Profile ID
+ - source (object): Source ports mirror configuration
+ - destination (object): Destination port mirror configuration
+ - tags (array): Port mirror tags
+ - role (string): Switch role can be source or destination
+ - comment (string): My pretty comment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "configTemplates", "profiles", "ports", "mirror"],
+ "operation": "updateOrganizationConfigTemplateSwitchProfilePortsMirror",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ configTemplateId = urllib.parse.quote(str(configTemplateId), safe="")
+ profileId = urllib.parse.quote(str(profileId), safe="")
+ resource = (
+ f"/organizations/{organizationId}/configTemplates/{configTemplateId}/switch/profiles/{profileId}/ports/mirror"
+ )
+
+ body_params = [
+ "source",
+ "destination",
+ "tags",
+ "role",
+ "comment",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationConfigTemplateSwitchProfilePortsMirror: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getOrganizationConfigTemplateSwitchProfilePort(
self, organizationId: str, configTemplateId: str, profileId: str, portId: str
):
@@ -3032,6 +3523,7 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
- vlan (integer): The VLAN of the switch template port. For a trunk port, this is the native VLAN. A null value will clear the value set for trunk ports.
- voiceVlan (integer): The voice VLAN of the switch template port. Only applicable to access ports.
- allowedVlans (string): The VLANs allowed on the switch template port. Only applicable to trunk ports.
+ - activeVlans (string): The VLANs that are active on the switch template port. Only applicable to trunk ports.
- isolationEnabled (boolean): The isolation status of the switch template port.
- rstpEnabled (boolean): The rapid spanning tree protocol status.
- stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard').
@@ -3094,6 +3586,7 @@ def updateOrganizationConfigTemplateSwitchProfilePort(
"vlan",
"voiceVlan",
"allowedVlans",
+ "activeVlans",
"isolationEnabled",
"rstpEnabled",
"stpGuard",
@@ -3163,89 +3656,37 @@ def getOrganizationSummarySwitchPowerHistory(self, organizationId: str, **kwargs
return self._session.get(metadata, resource, params)
- def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str, targetSerials: list, **kwargs):
- """
- **Clone port-level and some switch-level configuration settings from a source switch to one or more target switches**
- https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-devices
-
- - organizationId (string): Organization ID
- - sourceSerial (string): Serial number of the source switch (must be on a network not bound to a template)
- - targetSerials (array): Array of serial numbers of one or more target switches (must be on a network not bound to a template)
- """
-
- kwargs = locals()
-
- metadata = {
- "tags": ["switch", "configure", "devices"],
- "operation": "cloneOrganizationSwitchDevices",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/devices/clone"
-
- body_params = [
- "sourceSerial",
- "targetSerials",
- ]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
-
- if self._session._validate_kwargs:
- all_params = [] + body_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(f"cloneOrganizationSwitchDevices: ignoring unrecognized kwargs: {invalid}")
-
- return self._session.post(metadata, resource, payload)
-
- def getOrganizationSwitchPortsBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationSwitchAlertsPoeByDevice(self, organizationId: str, networkIds: list, **kwargs):
"""
- **List the switchports in an organization by switch**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-by-switch
+ **Gets all poe related alerts over a given network and returns information by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-alerts-poe-by-device
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 50.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "configure", "ports", "bySwitch"],
- "operation": "getOrganizationSwitchPortsBySwitch",
+ "tags": ["switch", "monitor", "alerts", "poe", "byDevice"],
+ "operation": "getOrganizationSwitchAlertsPoeByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/bySwitch"
+ resource = f"/organizations/{organizationId}/switch/alerts/poe/byDevice"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
"networkIds",
- "portProfileIds",
- "serial",
- "serials",
+ "t0",
+ "t1",
+ "timespan",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
- "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3256,66 +3697,60 @@ def getOrganizationSwitchPortsBySwitch(self, organizationId: str, total_pages=1,
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationSwitchPortsBySwitch: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationSwitchAlertsPoeByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsClientsOverviewByDevice(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def aurora2OrganizationSwitchSwitchTemplates(self, organizationId: str):
"""
- **List the number of clients for all switchports with at least one online client in an organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-clients-overview-by-device
+ **List switch templates running IOS XE Catalyst firmware.**
+ https://developer.cisco.com/meraki/api-v1/#!aurora-2-organization-switch-switch-templates
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 20.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ metadata = {
+ "tags": ["switch", "configure"],
+ "operation": "aurora2OrganizationSwitchSwitchTemplates",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/aurora2SwitchTemplates"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationSwitchClientsConnectionsAuthenticationByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarizes authentication outcomes per switch client across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-clients-connections-authentication-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "clients", "overview", "byDevice"],
- "operation": "getOrganizationSwitchPortsClientsOverviewByDevice",
+ "tags": ["switch", "monitor", "clients", "connections", "authentication", "byClient"],
+ "operation": "getOrganizationSwitchClientsConnectionsAuthenticationByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/clients/overview/byDevice"
+ resource = f"/organizations/{organizationId}/switch/clients/connections/authentication/byClient"
query_params = [
+ "networkIds",
"t0",
+ "t1",
"timespan",
- "perPage",
- "startingAfter",
- "endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
- "networkIds",
- "portProfileIds",
- "serial",
- "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
- "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3327,96 +3762,89 @@ def getOrganizationSwitchPortsClientsOverviewByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationSwitchPortsClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationSwitchClientsConnectionsAuthenticationByClient: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsOverview(self, organizationId: str, **kwargs):
+ def getOrganizationSwitchClientsConnectionsDhcpByClient(self, organizationId: str, **kwargs):
"""
- **Returns the counts of all active ports for the requested timespan, grouped by speed**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-overview
+ **Get IP assignment for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-clients-connections-dhcp-by-client
- organizationId (string): Organization ID
- - t0 (string): The beginning of the timespan for the data.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 12 hours and be less than or equal to 186 days. The default is 1 day.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "overview"],
- "operation": "getOrganizationSwitchPortsOverview",
+ "tags": ["switch", "monitor", "clients", "connections", "dhcp", "byClient"],
+ "operation": "getOrganizationSwitchClientsConnectionsDhcpByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/overview"
+ resource = f"/organizations/{organizationId}/switch/clients/connections/dhcp/byClient"
query_params = [
+ "networkIds",
"t0",
"t1",
"timespan",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
if self._session._validate_kwargs:
- all_params = query_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationSwitchPortsOverview: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationSwitchClientsConnectionsDhcpByClient: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsStatusesBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationSwitchClientsConnectionsSwitchPortStatusByClient(self, organizationId: str, **kwargs):
"""
- **List the switchports in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-statuses-by-switch
+ **Switch port status by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-clients-connections-switch-port-status-by-client
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "statuses", "bySwitch"],
- "operation": "getOrganizationSwitchPortsStatusesBySwitch",
+ "tags": ["switch", "monitor", "clients", "connections", "switchPortStatus", "byClient"],
+ "operation": "getOrganizationSwitchClientsConnectionsSwitchPortStatusByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/statuses/bySwitch"
+ resource = f"/organizations/{organizationId}/switch/clients/connections/switchPortStatus/byClient"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
"networkIds",
- "portProfileIds",
- "serial",
- "serials",
+ "t0",
+ "t1",
+ "timespan",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
- "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3428,66 +3856,265 @@ def getOrganizationSwitchPortsStatusesBySwitch(self, organizationId: str, total_
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationSwitchPortsStatusesBySwitch: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationSwitchClientsConnectionsSwitchPortStatusByClient: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationSwitchPortsTopologyDiscoveryByDevice(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def cloneOrganizationSwitchProfilesToTemplateNetwork(self, organizationId: str, **kwargs):
"""
- **List most recently seen LLDP/CDP discovery and topology information per switch port in an organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-topology-discovery-by-device
+ **Clone existing switch templates into a destination template network.**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-profiles-to-template-network
+
+ - organizationId (string): Organization ID
+ - profileIds (array): Switch profile IDs to clone
+ - templateNodeGroupId (string): Destination template network ID
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure"],
+ "operation": "cloneOrganizationSwitchProfilesToTemplateNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/cloneProfilesToTemplateNetwork"
+
+ body_params = [
+ "profileIds",
+ "templateNodeGroupId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"cloneOrganizationSwitchProfilesToTemplateNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchConnectivityLanLinkErrorsByDeviceByPort(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Lan link errors by device and port.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-connectivity-lan-link-errors-by-device-by-port
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "connectivity", "lanLink", "errors", "byDevice", "byPort"],
+ "operation": "getOrganizationSwitchConnectivityLanLinkErrorsByDeviceByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/connectivity/lanLink/errors/byDevice/byPort"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchConnectivityLanLinkErrorsByDeviceByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchConnectivityLanStpErrorsByDeviceByPort(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Lan STP errors by device and port.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-connectivity-lan-stp-errors-by-device-by-port
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "connectivity", "lanStp", "errors", "byDevice", "byPort"],
+ "operation": "getOrganizationSwitchConnectivityLanStpErrorsByDeviceByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/connectivity/lanStp/errors/byDevice/byPort"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchConnectivityLanStpErrorsByDeviceByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchConnectivityVrrpFailuresByDevice(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Gets all vrrp related alerts over a given network and returns information by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-connectivity-vrrp-failures-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "connectivity", "vrrp", "failures", "byDevice"],
+ "operation": "getOrganizationSwitchConnectivityVrrpFailuresByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/connectivity/vrrp/failures/byDevice"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchConnectivityVrrpFailuresByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def cloneOrganizationSwitchDevices(self, organizationId: str, sourceSerial: str, targetSerials: list, **kwargs):
+ """
+ **Clone port-level and some switch-level configuration settings from a source switch to one or more target switches**
+ https://developer.cisco.com/meraki/api-v1/#!clone-organization-switch-devices
+
+ - organizationId (string): Organization ID
+ - sourceSerial (string): Serial number of the source switch (must be on a network not bound to a template)
+ - targetSerials (array): Array of serial numbers of one or more target switches (must be on a network not bound to a template)
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "devices"],
+ "operation": "cloneOrganizationSwitchDevices",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/devices/clone"
+
+ body_params = [
+ "sourceSerial",
+ "targetSerials",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"cloneOrganizationSwitchDevices: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchDevicesSystemQueuesHistoryBySwitchByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return a historical record of packet transmission and loss, broken down by protocol, for insight into switch device health.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-devices-system-queues-history-by-switch-by-interval
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
- - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
- - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
- - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
- - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
- - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
+ - networkIds (array): Optional parameter to filter connectivity history by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter connectivity history by switch.
"""
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "topology", "discovery", "byDevice"],
- "operation": "getOrganizationSwitchPortsTopologyDiscoveryByDevice",
+ "tags": ["switch", "monitor", "devices", "system", "queues", "history", "bySwitch", "byInterval"],
+ "operation": "getOrganizationSwitchDevicesSystemQueuesHistoryBySwitchByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/topology/discovery/byDevice"
+ resource = f"/organizations/{organizationId}/switch/devices/system/queues/history/bySwitch/byInterval"
query_params = [
- "t0",
- "timespan",
"perPage",
"startingAfter",
"endingBefore",
- "configurationUpdatedAfter",
- "mac",
- "macs",
- "name",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
"networkIds",
- "portProfileIds",
- "serial",
"serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "macs",
"networkIds",
- "portProfileIds",
"serials",
]
for k, v in kwargs.items():
@@ -3500,28 +4127,25 @@ def getOrganizationSwitchPortsTopologyDiscoveryByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationSwitchPortsTopologyDiscoveryByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationSwitchDevicesSystemQueuesHistoryBySwitchByInterval: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationSwitchPortsBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **List the historical usage and traffic data of switchports in an organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-usage-history-by-device-by-interval
+ **List the switchports in an organization by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-by-switch
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 50.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - extendedParams (boolean): Optional flag to return all of the switchport data vs smaller dataset
+ - hideDefaultPorts (boolean): Optional flag that, when true, will hide modular switchports that may not be connected to the device at the moment
+ - type (array): Optional parameter to filter switchports by type ('access', 'trunk', 'stack', 'routed', 'svl' or 'dad'). All types are selected if not supplied.
- configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
- mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
- macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
@@ -3535,20 +4159,19 @@ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
kwargs.update(locals())
metadata = {
- "tags": ["switch", "monitor", "ports", "usage", "history", "byDevice", "byInterval"],
- "operation": "getOrganizationSwitchPortsUsageHistoryByDeviceByInterval",
+ "tags": ["switch", "configure", "ports", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsBySwitch",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/switch/ports/usage/history/byDevice/byInterval"
+ resource = f"/organizations/{organizationId}/switch/ports/bySwitch"
query_params = [
- "t0",
- "t1",
- "timespan",
- "interval",
"perPage",
"startingAfter",
"endingBefore",
+ "extendedParams",
+ "hideDefaultPorts",
+ "type",
"configurationUpdatedAfter",
"mac",
"macs",
@@ -3561,6 +4184,7 @@ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
+ "type",
"macs",
"networkIds",
"portProfileIds",
@@ -3575,8 +4199,3033 @@ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(
- f"getOrganizationSwitchPortsUsageHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ self._session._logger.warning(f"getOrganizationSwitchPortsBySwitch: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsClientsOverviewByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the number of clients for all switchports with at least one online client in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-clients-overview-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "clients", "overview", "byDevice"],
+ "operation": "getOrganizationSwitchPortsClientsOverviewByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/clients/overview/byDevice"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsMirrorsBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **list the port mirror configurations in an organization by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-mirrors-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): A list of serial numbers. The returned devices will be filtered to only include these serials.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "mirrors", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsMirrorsBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/mirrors/bySwitch"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsMirrorsBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsOverview(self, organizationId: str, **kwargs):
+ """
+ **Returns the counts of all active ports for the requested timespan, grouped by speed**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-overview
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 186 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 12 hours and be less than or equal to 186 days. The default is 1 day.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "overview"],
+ "operation": "getOrganizationSwitchPortsOverview",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/overview"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSwitchPortsOverview: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchPortsProfiles(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the port profiles in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Return the port profiles for the specified network(s)
+ - formattedStaticAssignments (boolean): Returns the list of static switchports that are assigned to the switchport profile
+ - searchQuery (string): Optional parameter to filter the result set by the search query
+ - radiusProfileEnabled (boolean): Optional parameter. If true, only return port profiles with a radius profile enabled
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "getOrganizationSwitchPortsProfiles",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles"
+
+ query_params = [
+ "networkIds",
+ "formattedStaticAssignments",
+ "searchQuery",
+ "radiusProfileEnabled",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSwitchPortsProfiles: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfile(self, organizationId: str, **kwargs):
+ """
+ **Create a port profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - isOrganizationWide (boolean): The scope of the profile whether it is organization level or network level
+ - networks (object): The networks which are included/excluded in the profile
+ - networkId (string): The network identifier
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "createOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles"
+
+ body_params = [
+ "name",
+ "description",
+ "isOrganizationWide",
+ "networks",
+ "networkId",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def batchOrganizationSwitchPortsProfilesAssignmentsAssign(self, organizationId: str, items: list, **kwargs):
+ """
+ **Batch assign or unassign port profiles to switch ports**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-switch-ports-profiles-assignments-assign
+
+ - organizationId (string): Organization ID
+ - items (array): Array of assignment operations (max 100)
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "assignments"],
+ "operation": "batchOrganizationSwitchPortsProfilesAssignmentsAssign",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/batchAssign"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchOrganizationSwitchPortsProfilesAssignmentsAssign: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchPortsProfilesAssignmentsByPort(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profile assignments in an organization, grouped by port**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-assignments-by-port
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - profileIds (array): Filter by specific profile IDs
+ - serials (array): Filter by switch serials
+ - networkIds (array): Filter by network IDs
+ - templateIds (array): Filter by template (node_profile) IDs
+ - types (array): Filter by port type: switch, template
+ - assignmentTypes (array): Filter by assignment type: direct, template, exception
+ - isActive (boolean): Filter by assignment status. true: only ports with active assignments, showing only active assignments per port. false: only ports with inactive assignments, showing only inactive assignments per port. Omit: all ports with all assignment layers.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "assignments", "byPort"],
+ "operation": "getOrganizationSwitchPortsProfilesAssignmentsByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/byPort"
+
+ query_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ "templateIds",
+ "types",
+ "assignmentTypes",
+ "isActive",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ "templateIds",
+ "types",
+ "assignmentTypes",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesAssignmentsByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsProfilesAssignmentsBySwitch(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profile assignments in an organization, grouped by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-assignments-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - profileIds (array): Filter by specific profile IDs
+ - serials (array): Filter by switch serials
+ - networkIds (array): Filter by network IDs
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "assignments", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsProfilesAssignmentsBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/assignments/bySwitch"
+
+ query_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "profileIds",
+ "serials",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesAssignmentsBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsProfilesAutomations(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **list the automation port profiles in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-automations
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - ids (array): Optional parameter to filter the result set by the included set of automation IDs
+ - networkIds (array): Optional parameter to filter the result set by the associated networks.
+ - isOrganizationWide (string): Optional parameter to filter the result set by automations org-wide flag.
+ - searchQuery (string): Optional parameter to filter the result set by the search query
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "getOrganizationSwitchPortsProfilesAutomations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations"
+
+ query_params = [
+ "ids",
+ "networkIds",
+ "isOrganizationWide",
+ "searchQuery",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ids",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesAutomations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, **kwargs):
+ """
+ **Create a port profile automation for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the port profile automation.
+ - description (string): Text describing the port profile automation.
+ - fallbackProfile (object): Configuration settings for port profile
+ - rules (array): Configuration settings for port profile automation rules
+ - assignedSwitchPorts (array): assigned switch ports
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "createOrganizationSwitchPortsProfilesAutomation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations"
+
+ body_params = [
+ "name",
+ "description",
+ "fallbackProfile",
+ "rules",
+ "assignedSwitchPorts",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchPortsProfilesAutomation: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile automation in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the port profile automation.
+ - description (string): Text describing the port profile automation.
+ - fallbackProfile (object): Configuration settings for port profile
+ - rules (array): Configuration settings for port profile automation rules
+ - assignedSwitchPorts (array): assigned switch ports
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "updateOrganizationSwitchPortsProfilesAutomation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "fallbackProfile",
+ "rules",
+ "assignedSwitchPorts",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSwitchPortsProfilesAutomation: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfilesAutomation(self, organizationId: str, id: str):
+ """
+ **Delete an automation port profile from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-automation
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "automations"],
+ "operation": "deleteOrganizationSwitchPortsProfilesAutomation",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/automations/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsProfilesNetworksAssignments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Fetch all Network - Smart Port Profile associations for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-networks-assignments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): Number of records per page
+ - page (integer): Page number
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "getOrganizationSwitchPortsProfilesNetworksAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments"
+
+ query_params = [
+ "perPage",
+ "page",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesNetworksAssignments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfilesNetworksAssignment(
+ self, organizationId: str, type: str, profile: dict, network: dict, **kwargs
+ ):
+ """
+ **Create Network and Smart Ports Profile association for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-networks-assignment
+
+ - organizationId (string): Organization ID
+ - type (string): Type of association
+ - profile (object): Smart Port Profile object
+ - network (object): Network object
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "createOrganizationSwitchPortsProfilesNetworksAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments"
+
+ body_params = [
+ "type",
+ "profile",
+ "network",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchPortsProfilesNetworksAssignment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate(self, organizationId: str, items: list, **kwargs):
+ """
+ **Batch Create Network and Smart Ports Profile associations for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!batch-organization-switch-ports-profiles-networks-assignments-create
+
+ - organizationId (string): Organization ID
+ - items (array): Array of network and profile associations
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/batchCreate"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"batchOrganizationSwitchPortsProfilesNetworksAssignmentsCreate: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete(self, organizationId: str, items: list, **kwargs):
+ """
+ **Bulk delete Network and Smart Port Profile associations**
+ https://developer.cisco.com/meraki/api-v1/#!bulk-organization-switch-ports-profiles-networks-assignments-delete
+
+ - organizationId (string): Organization ID
+ - items (array): Array of assignments to delete
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/bulkDelete"
+
+ body_params = [
+ "items",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"bulkOrganizationSwitchPortsProfilesNetworksAssignmentsDelete: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfilesNetworksAssignment(self, organizationId: str, assignmentId: str):
+ """
+ **Delete Network and Smart Port profile association for a specific profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-networks-assignment
+
+ - organizationId (string): Organization ID
+ - assignmentId (string): Assignment ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "networks", "assignments"],
+ "operation": "deleteOrganizationSwitchPortsProfilesNetworksAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ assignmentId = urllib.parse.quote(str(assignmentId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/networks/assignments/{assignmentId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsProfilesOverviewByProfile(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profiles in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-overview-by-profile
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Return the port profiles for the specified network(s)
+ - formattedStaticAssignments (boolean): Returns the list of static switchports that are assgined to the switchport profile
+ - searchQuery (string): Optional parameter to filter the result set by the search query
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "overview", "byProfile"],
+ "operation": "getOrganizationSwitchPortsProfilesOverviewByProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/overview/byProfile"
+
+ query_params = [
+ "networkIds",
+ "formattedStaticAssignments",
+ "searchQuery",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesOverviewByProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsProfilesRadiusAssignments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the port profile RADIUS assignments**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-radius-assignments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): If present, the networks to limit the assignments to
+ - portProfileIds (array): If present, the port profiles to limit the assignments to
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "getOrganizationSwitchPortsProfilesRadiusAssignments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments"
+
+ query_params = [
+ "networkIds",
+ "portProfileIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "portProfileIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsProfilesRadiusAssignments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, network: dict, **kwargs):
+ """
+ **Create a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - network (object): The network where the RADIUS name is assigned
+ - portProfile (object): The assigned port profile
+ - radius (object): The RADIUS options for this assignment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "createOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments"
+
+ body_params = [
+ "network",
+ "portProfile",
+ "radius",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchPortsProfilesRadiusAssignment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str):
+ """
+ **Return a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "getOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - network (object): The network where the RADIUS name is assigned
+ - portProfile (object): The assigned port profile
+ - radius (object): The RADIUS options for this assignment
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "updateOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ body_params = [
+ "network",
+ "portProfile",
+ "radius",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSwitchPortsProfilesRadiusAssignment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfilesRadiusAssignment(self, organizationId: str, id: str):
+ """
+ **Deletes a port profile RADIUS assignment**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profiles-radius-assignment
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles", "radius", "assignments"],
+ "operation": "deleteOrganizationSwitchPortsProfilesRadiusAssignment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/radius/assignments/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsProfile(self, organizationId: str, id: str):
+ """
+ **Get detailed information about a port profile**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "getOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationSwitchPortsProfile(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a port profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): The name of the profile.
+ - description (string): Text describing the profile.
+ - isOrganizationWide (boolean): The scope of the profile whether it is organization level or network level
+ - networks (object): The networks which are included/excluded in the profile
+ - networkId (string): The network identifier
+ - tags (array): Space-seperated list of tags
+ - defaultRadiusProfileName (string): When present, the default RADIUS attribute value for RADIUS-based port profile application
+ - authentication (object): Authentication settings for RADIUS-based port profile application.
+ - port (object): Configuration settings for port profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "updateOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "isOrganizationWide",
+ "networks",
+ "networkId",
+ "tags",
+ "defaultRadiusProfileName",
+ "authentication",
+ "port",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationSwitchPortsProfile: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchPortsProfile(self, organizationId: str, id: str):
+ """
+ **Delete a port profile from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-ports-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "ports", "profiles"],
+ "operation": "deleteOrganizationSwitchPortsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/profiles/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchPortsStatusesBySwitch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the switchports in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-statuses-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "statuses", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsStatusesBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/statuses/bySwitch"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsStatusesBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsStatusesPacketsByDeviceByPort(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Switch port packets by device and port.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-statuses-packets-by-device-by-port
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 1200, 14400, 86400. The default is 14400. Interval is calculated if time params are provided.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "statuses", "packets", "byDevice", "byPort"],
+ "operation": "getOrganizationSwitchPortsStatusesPacketsByDeviceByPort",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/statuses/packets/byDevice/byPort"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsStatusesPacketsByDeviceByPort: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationSwitchPortsTopologyDiscoveryByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List most recently seen LLDP/CDP discovery and topology information per switch port in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-topology-discovery-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "topology", "discovery", "byDevice"],
+ "operation": "getOrganizationSwitchPortsTopologyDiscoveryByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/topology/discovery/byDevice"
+
+ query_params = [
+ "t0",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsTopologyDiscoveryByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsTransceiversReadingsHistoryBySwitch(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return time-series digital optical monitoring (DOM) readings for ports on each DOM-enabled switch in an organization, in addition to thresholds for each relevant Small Form Factor Pluggable (SFP) module.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-transceivers-readings-history-by-switch
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
+ - networkIds (array): Networks for which information should be gathered.
+ - serials (array): Optional parameter to filter usage by switch.
+ - portIds (array): Optional parameter to filter usage by port ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "transceivers", "readings", "history", "bySwitch"],
+ "operation": "getOrganizationSwitchPortsTransceiversReadingsHistoryBySwitch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/transceivers/readings/history/bySwitch"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "serials",
+ "portIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "portIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsTransceiversReadingsHistoryBySwitch: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchPortsUsageHistoryByDeviceByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the historical usage and traffic data of switchports in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-ports-usage-history-by-device-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 1200, 14400, 86400. The default is 1200. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - configurationUpdatedAfter (string): Optional parameter to filter items to switches where the configuration has been updated after the given timestamp.
+ - mac (string): Optional parameter to filter items to switches with MAC addresses that contain the search term or are an exact match.
+ - macs (array): Optional parameter to filter items to switches that have one of the provided MAC addresses.
+ - name (string): Optional parameter to filter items to switches with names that contain the search term or are an exact match.
+ - networkIds (array): Optional parameter to filter items to switches in one of the provided networks.
+ - portProfileIds (array): Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles.
+ - serial (string): Optional parameter to filter items to switches with serial number that contains the search term or are an exact match.
+ - serials (array): Optional parameter to filter items to switches that have one of the provided serials.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "ports", "usage", "history", "byDevice", "byInterval"],
+ "operation": "getOrganizationSwitchPortsUsageHistoryByDeviceByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/ports/usage/history/byDevice/byInterval"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "configurationUpdatedAfter",
+ "mac",
+ "macs",
+ "name",
+ "networkIds",
+ "portProfileIds",
+ "serial",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "macs",
+ "networkIds",
+ "portProfileIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchPortsUsageHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpAutonomousSystems(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the autonomous systems configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-autonomous-systems
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - numbers (array): Optional parameter to filter autonomous systems by number. This filter uses multiple exact matches.
+ - autonomousSystemIds (array): Optional parameter to filter autonomous systems by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "getOrganizationSwitchRoutingBgpAutonomousSystems",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpAutonomousSystems: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, number: int, **kwargs):
+ """
+ **Create an autonomous system**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - number (integer): The autonomous system number (CLI: 'router bgp ')
+ - description (string): A description for the autonomous system
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "createOrganizationSwitchRoutingBgpAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems"
+
+ body_params = [
+ "number",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpAutonomousSystem: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpAutonomousSystemsOverviewByAutonomousSystem(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the autonomous systems configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-autonomous-systems-overview-by-autonomous-system
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - numbers (array): Optional parameter to filter autonomous systems by number. This filter uses multiple exact matches.
+ - autonomousSystemIds (array): Optional parameter to filter autonomous systems by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems", "overview", "byAutonomousSystem"],
+ "operation": "getOrganizationSwitchRoutingBgpAutonomousSystemsOverviewByAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/overview/byAutonomousSystem"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "numbers",
+ "autonomousSystemIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpAutonomousSystemsOverviewByAutonomousSystem: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, autonomousSystemId: str, **kwargs):
+ """
+ **Update an autonomous system**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - autonomousSystemId (string): Autonomous system ID
+ - number (integer): The autonomous system number (CLI: 'router bgp ')
+ - description (string): A description for the autonomous system
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "updateOrganizationSwitchRoutingBgpAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ autonomousSystemId = urllib.parse.quote(str(autonomousSystemId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/{autonomousSystemId}"
+
+ body_params = [
+ "number",
+ "description",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationSwitchRoutingBgpAutonomousSystem: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationSwitchRoutingBgpAutonomousSystem(self, organizationId: str, autonomousSystemId: str):
+ """
+ **Delete an autonomous system from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-autonomous-system
+
+ - organizationId (string): Organization ID
+ - autonomousSystemId (string): Autonomous system ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "autonomousSystems"],
+ "operation": "deleteOrganizationSwitchRoutingBgpAutonomousSystem",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ autonomousSystemId = urllib.parse.quote(str(autonomousSystemId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/autonomousSystems/{autonomousSystemId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingBgpFiltersFilterLists(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the filter lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-filter-lists
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter 'filter lists' by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter 'filter lists' by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersFilterLists",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersFilterLists: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy(
+ self, organizationId: str, filterList: dict, network: dict, rules: list, **kwargs
+ ):
+ """
+ **Create or update a filter list, in addition to its associated rules**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-filters-filter-lists-deploy
+
+ - organizationId (string): Organization ID
+ - filterList (object): Information regarding the filter list
+ - network (object): Information regarding the network the filter list belongs to
+ - rules (array): Information regarding the filter list rules
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/deploy"
+
+ body_params = [
+ "filterList",
+ "network",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpFiltersFilterListsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpFiltersFilterListsOverviewByFilterList(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the filter lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-filter-lists-overview-by-filter-list
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter 'filter list' overviews by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter 'filter list' overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "filters", "filterLists", "overview", "byFilterList"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersFilterListsOverviewByFilterList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/overview/byFilterList"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersFilterListsOverviewByFilterList: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpFiltersFilterListsRules(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the filter list rules configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-filter-lists-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter 'filter list' rules by network ID. This filter uses multiple exact matches.
+ - ruleIds (array): Optional parameter to filter 'filter list' rules by ID. This filter uses multiple exact matches.
+ - filterListIds (array): Optional parameter to filter 'filter lists' by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists", "rules"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersFilterListsRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/rules"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "ruleIds",
+ "filterListIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "ruleIds",
+ "filterListIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersFilterListsRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationSwitchRoutingBgpFiltersFilterList(self, organizationId: str, listId: str):
+ """
+ **Delete a filter list**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-filters-filter-list
+
+ - organizationId (string): Organization ID
+ - listId (string): List ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "filterLists"],
+ "operation": "deleteOrganizationSwitchRoutingBgpFiltersFilterList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ listId = urllib.parse.quote(str(listId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/filterLists/{listId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingBgpFiltersPrefixLists(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the prefix lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-prefix-lists
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter prefix lists by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter prefix lists by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersPrefixLists",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersPrefixLists: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy(
+ self, organizationId: str, network: dict, prefixList: dict, rules: list, **kwargs
+ ):
+ """
+ **Create or update a prefix list, in addition to its associated rules**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-filters-prefix-lists-deploy
+
+ - organizationId (string): Organization ID
+ - network (object): Information regarding the network the prefix list belongs to
+ - prefixList (object): Information regarding the prefix list
+ - rules (array): Information regarding the prefix list rules
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/deploy"
+
+ body_params = [
+ "network",
+ "prefixList",
+ "rules",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpFiltersPrefixListsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpFiltersPrefixListsOverviewByPrefixList(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the prefix lists configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-prefix-lists-overview-by-prefix-list
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter prefix list overviews by network ID. This filter uses multiple exact matches.
+ - listIds (array): Optional parameter to filter prefix list overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "filters", "prefixLists", "overview", "byPrefixList"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersPrefixListsOverviewByPrefixList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/overview/byPrefixList"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "listIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "listIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersPrefixListsOverviewByPrefixList: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpFiltersPrefixListsRules(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the prefix list rules configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-filters-prefix-lists-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter prefix list rules by network ID. This filter uses multiple exact matches.
+ - prefixListIds (array): Optional parameter to filter prefix list rules by prefix list ID. This filter uses multiple exact matches.
+ - ruleIds (array): Optional parameter to filter prefix list rules by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists", "rules"],
+ "operation": "getOrganizationSwitchRoutingBgpFiltersPrefixListsRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/rules"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "prefixListIds",
+ "ruleIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "prefixListIds",
+ "ruleIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpFiltersPrefixListsRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationSwitchRoutingBgpFiltersPrefixList(self, organizationId: str, listId: str):
+ """
+ **Delete a prefix list**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-filters-prefix-list
+
+ - organizationId (string): Organization ID
+ - listId (string): List ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "filters", "prefixLists"],
+ "operation": "deleteOrganizationSwitchRoutingBgpFiltersPrefixList",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ listId = urllib.parse.quote(str(listId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/filters/prefixLists/{listId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingBgpPeersGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the BGP peer groups configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer groups by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter peer groups by router ID. This filter uses multiple exact matches.
+ - profileIds (array): Optional parameter to filter peer groups by profile ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer groups by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroups: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersGroupsAddressFamiliesDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for multiple peer groups or address families configured in the given organization, including profile information, peer group address family information, neighbors, and listen ranges**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups-address-families-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer group address family deployments by network ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer group address family deployments by peer group
+ - addressFamilyIds (array): Optional parameter to filter peer group address family deployments by address family
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups", "addressFamilies", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroupsAddressFamiliesDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/addressFamilies/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "peerGroupIds",
+ "addressFamilyIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "peerGroupIds",
+ "addressFamilyIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroupsAddressFamiliesDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpPeersGroupsDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ network: dict,
+ peerGroup: dict,
+ peerGroupAddressFamilyBindingProfile: dict,
+ peerGroupProfile: dict,
+ policies: list,
+ router: dict,
+ **kwargs,
+ ):
+ """
+ **Create or update a peer group, in addition to an associated peer group profile, peer group address family binding, peer group address family binding profile and routing policies associated with the peer group**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-peers-groups-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family the peer group address family binding belongs to
+ - network (object): Information regarding the network the peer group profile belongs to
+ - peerGroup (object): Information regarding the peer group
+ - peerGroupAddressFamilyBindingProfile (object): Information regarding the peer group address family binding profile
+ - peerGroupProfile (object): Information regarding the peer group profile
+ - policies (array): Information regarding the routing policies
+ - router (object): Information regarding the router this peer group belongs to
+ - peerGroupAddressFamilyBinding (object): Information regarding the peer group address family binding. Only required when updating.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpPeersGroupsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/deploy"
+
+ body_params = [
+ "addressFamily",
+ "network",
+ "peerGroup",
+ "peerGroupAddressFamilyBinding",
+ "peerGroupAddressFamilyBindingProfile",
+ "peerGroupProfile",
+ "policies",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpPeersGroupsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpPeersGroupsDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for peer groups configured in the given organization, including peer group address family information, as well as routing policies**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer group deployments by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter peer group deployments by router ID. This filter uses multiple exact matches.
+ - profileIds (array): Optional parameter to filter peer group deployments by profile ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer group deployments by peer group ID. This filter uses multiple exact matches.
+ - afi (string): Optional parameter to filter deployments on each peer group by address family identifier (AFI).
+ - safi (string): Optional parameter to filter deployments on each peer group by subsequent address family identifier (SAFI).
+ """
+
+ kwargs.update(locals())
+
+ if "afi" in kwargs:
+ options = ["ipv4"]
+ assert kwargs["afi"] in options, f'''"afi" cannot be "{kwargs["afi"]}", & must be set to one of: {options}'''
+ if "safi" in kwargs:
+ options = ["unicast"]
+ assert kwargs["safi"] in options, f'''"safi" cannot be "{kwargs["safi"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "groups", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroupsDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ "afi",
+ "safi",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroupsDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersGroupsOverviewByPeerGroup(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the BGP peer groups configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-groups-overview-by-peer-group
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter peer group overviews by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter peer group overviews by router ID. This filter uses multiple exact matches.
+ - profileIds (array): Optional parameter to filter peer group overviews by profile ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter peer group overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "peers", "groups", "overview", "byPeerGroup"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersGroupsOverviewByPeerGroup",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/groups/overview/byPeerGroup"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "profileIds",
+ "peerGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersGroupsOverviewByPeerGroup: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersListenRanges(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the listen ranges configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-listen-ranges
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter listen ranges by network ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter listen ranges by router ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter listen ranges by peer group ID. This filter uses multiple exact matches.
+ - listenRangeIds (array): Optional parameter to filter listen ranges by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "listenRanges"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersListenRanges",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/listenRanges"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "routerIds",
+ "peerGroupIds",
+ "listenRangeIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "routerIds",
+ "peerGroupIds",
+ "listenRangeIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersListenRanges: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpPeersNeighbors(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the neighbors configured for BGP in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-neighbors
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter neighbors by network ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter neighbors by peer group ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter neighbors by router ID. This filter uses multiple exact matches.
+ - neighborIds (array): Optional parameter to filter neighbors by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "neighbors"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersNeighbors",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersNeighbors: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpPeersNeighborsDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ neighbor: dict,
+ neighborAddressFamilyBinding: dict,
+ peerGroup: dict,
+ policies: list,
+ router: dict,
+ **kwargs,
+ ):
+ """
+ **Create or update a neighor, in addition to an associated neighbor address family binding and routing policies associated with the neighbor**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-peers-neighbors-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family this binding is bound to
+ - neighbor (object): Information regarding the BPG neighbor
+ - neighborAddressFamilyBinding (object): Information regarding the neighbor address family binding
+ - peerGroup (object): Information regarding the peer group this neighbor belongs to
+ - policies (array): Information regarding the routing policies related to the neighbor
+ - router (object): Information regarding the router this neighbor peers with
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "neighbors", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpPeersNeighborsDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors/deploy"
+
+ body_params = [
+ "addressFamily",
+ "neighbor",
+ "neighborAddressFamilyBinding",
+ "peerGroup",
+ "policies",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpPeersNeighborsDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpPeersNeighborsDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for neighbors configured in the given organization, including address family information, as well as routing policies**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-peers-neighbors-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter neighbor deployments by network ID. This filter uses multiple exact matches.
+ - peerGroupIds (array): Optional parameter to filter neighbor deployments by peer group ID. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter neighbor deployments by router ID. This filter uses multiple exact matches.
+ - neighborIds (array): Optional parameter to filter neighbor deployments by neighbor ID. This filter uses multiple exact matches.
+ - afi (string): Optional parameter to filter deployments on each neighbor by address family identifier (AFI).
+ - safi (string): Optional parameter to filter deployments on each neighbor by subsequent address family identifier (SAFI).
+ """
+
+ kwargs.update(locals())
+
+ if "afi" in kwargs:
+ options = ["ipv4"]
+ assert kwargs["afi"] in options, f'''"afi" cannot be "{kwargs["afi"]}", & must be set to one of: {options}'''
+ if "safi" in kwargs:
+ options = ["unicast"]
+ assert kwargs["safi"] in options, f'''"safi" cannot be "{kwargs["safi"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "peers", "neighbors", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpPeersNeighborsDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/peers/neighbors/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ "afi",
+ "safi",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "peerGroupIds",
+ "routerIds",
+ "neighborIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpPeersNeighborsDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpRouters(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the routers configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-routers
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter routers by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter routers by serial. This filter uses multiple exact matches.
+ - switchNames (array): Optional parameter to filter routers by switch name. The filter uses multiple exact matches.
+ - asNumbers (array): Optional parameter to filter routers by autonomous system number. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter routers by ID. This filter uses multiple exact matches.
+ - switchStackIds (array): Optional parameter to filter routers by switch stack id. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers"],
+ "operation": "getOrganizationSwitchRoutingBgpRouters",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpRouters: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpRoutersDeploy(
+ self,
+ organizationId: str,
+ addressFamily: dict,
+ addressFamilyPrefixes: list,
+ addressFamilyProfile: dict,
+ autonomousSystem: dict,
+ router: dict,
+ switch: dict,
+ **kwargs,
+ ):
+ """
+ **Create a BGP router, in addition to an associated address family, address family prefixes, and address family profile**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-routers-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family
+ - addressFamilyPrefixes (array): The list of network prefixes to which the address family applies
+ - addressFamilyProfile (object): Information regarding the profile applied to the address family
+ - autonomousSystem (object): Information regarding the router's autonomous system
+ - router (object): Information regarding the BPG router
+ - switch (object): The router's switch node. When the router is part of a switch stack, this is the switch stack's active node
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpRoutersDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/deploy"
+
+ body_params = [
+ "addressFamily",
+ "addressFamilyPrefixes",
+ "addressFamilyProfile",
+ "autonomousSystem",
+ "router",
+ "switch",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpRoutersDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationSwitchRoutingBgpRoutersDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List all BGP deployment information for routers configured in a given organization, including all address families**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-routers-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter router deployments by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter router deployments by serial. This filter uses multiple exact matches.
+ - switchNames (array): Optional parameter to filter router deployments by switch name. The filter uses multiple exact matches.
+ - asNumbers (array): Optional parameter to filter router deployments by autonomous system number. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter router deployments by router ID. This filter uses multiple exact matches.
+ - switchStackIds (array): Optional parameter to filter router deployments by switch stack id. This filter uses multiple exact matches.
+ - afi (string): Optional parameter to filter deployments on each router by address family identifier (AFI).
+ - safi (string): Optional parameter to filter deployments on each router by subsequent address family identifier (SAFI).
+ """
+
+ kwargs.update(locals())
+
+ if "afi" in kwargs:
+ options = ["ipv4"]
+ assert kwargs["afi"] in options, f'''"afi" cannot be "{kwargs["afi"]}", & must be set to one of: {options}'''
+ if "safi" in kwargs:
+ options = ["unicast"]
+ assert kwargs["safi"] in options, f'''"safi" cannot be "{kwargs["safi"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers", "deployments"],
+ "operation": "getOrganizationSwitchRoutingBgpRoutersDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ "afi",
+ "safi",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ "switchStackIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpRoutersDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchRoutingBgpRoutersOverviewByRouter(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the overview of the routers configured in the given organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-bgp-routers-overview-by-router
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter router overviews by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter router overviews by serial. This filter uses multiple exact matches.
+ - switchNames (array): Optional parameter to filter router overviews by switch name. This filter uses multiple exact matches.
+ - asNumbers (array): Optional parameter to filter router overviews by autonomous system number. This filter uses multiple exact matches.
+ - routerIds (array): Optional parameter to filter router overviews by ID. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "bgp", "routers", "overview", "byRouter"],
+ "operation": "getOrganizationSwitchRoutingBgpRoutersOverviewByRouter",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/overview/byRouter"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "switchNames",
+ "asNumbers",
+ "routerIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingBgpRoutersOverviewByRouter: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationSwitchRoutingBgpRoutersPeersDeploy(
+ self, organizationId: str, addressFamily: dict, peerGroups: list, router: dict, **kwargs
+ ):
+ """
+ **Create and update listen ranges, update peers' enabled flag, and delete peer groups for a BGP router**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-switch-routing-bgp-routers-peers-deploy
+
+ - organizationId (string): Organization ID
+ - addressFamily (object): Information regarding the address family
+ - peerGroups (array): Information regarding the peer group peers for a router's peer group
+ - router (object): Information regarding the BPG router
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers", "peers", "deploy"],
+ "operation": "createOrganizationSwitchRoutingBgpRoutersPeersDeploy",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/peers/deploy"
+
+ body_params = [
+ "addressFamily",
+ "peerGroups",
+ "router",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationSwitchRoutingBgpRoutersPeersDeploy: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def deleteOrganizationSwitchRoutingBgpRouter(self, organizationId: str, routerId: str):
+ """
+ **Delete a router from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-switch-routing-bgp-router
+
+ - organizationId (string): Organization ID
+ - routerId (string): Router ID
+ """
+
+ metadata = {
+ "tags": ["switch", "configure", "routing", "bgp", "routers"],
+ "operation": "deleteOrganizationSwitchRoutingBgpRouter",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ routerId = urllib.parse.quote(str(routerId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/bgp/routers/{routerId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationSwitchRoutingStaticRoutes(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List layer 3 static routes for switches within an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-routing-static-routes
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "monitor", "routing", "staticRoutes"],
+ "operation": "getOrganizationSwitchRoutingStaticRoutes",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/routing/staticRoutes"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchRoutingStaticRoutes: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchSpanningTree(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns Spanning Tree configuration settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-spanning-tree
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "spanningTree"],
+ "operation": "getOrganizationSwitchSpanningTree",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/spanningTree"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationSwitchSpanningTree: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationSwitchStacksPortsMirrorsByStack(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the port mirror configurations in an organization by switch**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-switch-stacks-ports-mirrors-by-stack
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - ids (array): Return the port mirror configuration for the specified stack(s)
+ - networkIds (array): Return the port mirror configurations for the specified network(s)
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["switch", "configure", "stacks", "ports", "mirrors", "byStack"],
+ "operation": "getOrganizationSwitchStacksPortsMirrorsByStack",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/switch/stacks/ports/mirrors/byStack"
+
+ query_params = [
+ "ids",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ids",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationSwitchStacksPortsMirrorsByStack: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
diff --git a/meraki/api/users.py b/meraki/api/users.py
new file mode 100644
index 00000000..f48c8b52
--- /dev/null
+++ b/meraki/api/users.py
@@ -0,0 +1,838 @@
+import urllib
+
+
+class Users(object):
+ def __init__(self, session):
+ super(Users, self).__init__()
+ self._session = session
+
+ def getOrganizationIamUsersAuthorizations(
+ self, organizationId: str, userIds: list, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List specific authorizations for the list of Meraki end users.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-authorizations
+
+ - organizationId (string): Organization ID
+ - userIds (array): Meraki end user IDs
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "getOrganizationIamUsersAuthorizations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "userIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "userIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersAuthorizations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationIamUsersAuthorization(self, organizationId: str, authZone: dict, **kwargs):
+ """
+ **Authorize a Meraki end user for an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-authorization
+
+ - organizationId (string): Organization ID
+ - authZone (object): Auth zone
+ - email (string): Meraki end user's email
+ - idpUserId (string): Meraki end user's ID
+ - startsAt (string): Start time of the desired access for the authorization. Defaults to now.
+ - expiresAt (string): Expiration time of the desired access for the authorization
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "createOrganizationIamUsersAuthorization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ body_params = [
+ "email",
+ "idpUserId",
+ "authZone",
+ "startsAt",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationIamUsersAuthorization: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationIamUsersAuthorizations(self, organizationId: str, **kwargs):
+ """
+ **Update a Meraki end user's access to an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-authorizations
+
+ - organizationId (string): Organization ID
+ - authorizationId (string): Authorization ID
+ - email (string): Meraki end user's email
+ - authZone (object): Auth zone
+ - startsAt (string): Start time of the desired access for the authorization
+ - expiresAt (string): Expiration time of the desired access for the authorization
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "updateOrganizationIamUsersAuthorizations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations"
+
+ body_params = [
+ "authorizationId",
+ "email",
+ "authZone",
+ "startsAt",
+ "expiresAt",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationIamUsersAuthorizations: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def revokeOrganizationIamUsersAuthorizationsAuthorization(self, organizationId: str, authZone: dict, **kwargs):
+ """
+ **Revoke a Meraki end user's access to an auth zone.**
+ https://developer.cisco.com/meraki/api-v1/#!revoke-organization-iam-users-authorizations-authorization
+
+ - organizationId (string): Organization ID
+ - authZone (object): Auth zone
+ - email (string): Meraki end user's email
+ - authorizationId (string): Authorization ID
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations", "authorization"],
+ "operation": "revokeOrganizationIamUsersAuthorizationsAuthorization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/authorization/revoke"
+
+ body_params = [
+ "email",
+ "authorizationId",
+ "authZone",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"revokeOrganizationIamUsersAuthorizationsAuthorization: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersAuthorizationsZones(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List all of the available auth zones for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-authorizations-zones
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 10 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations", "zones"],
+ "operation": "getOrganizationIamUsersAuthorizationsZones",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/zones"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersAuthorizationsZones: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationIamUsersAuthorization(self, organizationId: str, authorizationId: str):
+ """
+ **Delete an authorization for a Meraki end user.**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-authorization
+
+ - organizationId (string): Organization ID
+ - authorizationId (string): Authorization ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "authorizations"],
+ "operation": "deleteOrganizationIamUsersAuthorization",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ authorizationId = urllib.parse.quote(str(authorizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/authorizations/{authorizationId}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationIamUsersIdp(self, organizationId: str, name: str, type: str, idpConfig: dict, **kwargs):
+ """
+ **Create an identity provider for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the identity provider
+ - type (string): Type of the identity provider
+ - idpConfig (object): Identity provider configuration. Required for external identity providers.
+ - description (string): Optional. Description of the identity provider
+ - syncType (string): The synchronization method for the identity provider. Set to 'proactive' to sync all users and groups from your identity provider.
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["Azure AD"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+ if "syncType" in kwargs and kwargs["syncType"] is not None:
+ options = ["proactive"]
+ assert kwargs["syncType"] in options, (
+ f'''"syncType" cannot be "{kwargs["syncType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "createOrganizationIamUsersIdp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps"
+
+ body_params = [
+ "name",
+ "type",
+ "description",
+ "idpConfig",
+ "syncType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def searchOrganizationIdpGroups(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Search all IdP groups for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!search-organization-idp-groups
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - idpIds (array): Filter IdP groups by IdP ID(s). Multiple IdP IDs can be passed as a comma separated list.
+ - authZone (object): Auth zone
+ - searchQuery (string): Fuzzy filter by group name
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "groups", "search"],
+ "operation": "searchOrganizationIdpGroups",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/groups/search"
+
+ body_params = [
+ "idpIds",
+ "authZone",
+ "searchQuery",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"searchOrganizationIdpGroups: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersIdpsProductIntegrations(self, organizationId: str):
+ """
+ **List all available IdP Product Integration urls for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idps-product-integrations
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "productIntegrations"],
+ "operation": "getOrganizationIamUsersIdpsProductIntegrations",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/productIntegrations"
+
+ return self._session.get(metadata, resource)
+
+ def createOrganizationIamUsersIdpsSearch(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Search all IdPs for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-search
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - idpIds (array): Filter identity providers by id(s). Multiple ids can be passed as a comma separated list.
+ - type (string): Filter identity providers by idp type.
+ - authZone (object): Filter by auth zone
+ """
+
+ kwargs.update(locals())
+
+ if "type" in kwargs:
+ options = ["Azure AD"]
+ assert kwargs["type"] in options, f'''"type" cannot be "{kwargs["type"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "search"],
+ "operation": "createOrganizationIamUsersIdpsSearch",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/search"
+
+ body_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "idpIds",
+ "type",
+ "authZone",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdpsSearch: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersIdpsSyncHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get the IdP sync status records for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idps-sync-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - idpId (string): Identity provider ID. Optional.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync", "history"],
+ "operation": "getOrganizationIamUsersIdpsSyncHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/sync/history"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "idpId",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersIdpsSyncHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationIamUsersIdpsSyncLatest(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get the latest IdP sync status records for all IdPs in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idps-sync-latest
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - idpIds (array): Identity provider IDs. Optional.
+ - authZoneId (string): Auth Zone ID
+ - authZoneType (string): Auth Zone type
+ """
+
+ kwargs.update(locals())
+
+ if "authZoneType" in kwargs:
+ options = ["access_policy", "node_group", "product", "ssid"]
+ assert kwargs["authZoneType"] in options, (
+ f'''"authZoneType" cannot be "{kwargs["authZoneType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync", "latest"],
+ "operation": "getOrganizationIamUsersIdpsSyncLatest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/sync/latest"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "idpIds",
+ "authZoneId",
+ "authZoneType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "idpIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationIamUsersIdpsSyncLatest: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationIamUsersIdpsTestConnectivity(self, organizationId: str, **kwargs):
+ """
+ **Test connectivity to an Entra ID identity provider.**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-test-connectivity
+
+ - organizationId (string): Organization ID
+ - idpId (string): Id of the identity provider
+ - idpConfig (object): Identity provider configuration. Required for external identity providers.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "testConnectivity"],
+ "operation": "createOrganizationIamUsersIdpsTestConnectivity",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/testConnectivity"
+
+ body_params = [
+ "idpId",
+ "idpConfig",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationIamUsersIdpsTestConnectivity: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createOrganizationIamUsersIdpsUser(self, organizationId: str, **kwargs):
+ """
+ **Create a Meraki user**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - displayName (string): A human-readable identifier for the created user.
+ - email (string): An email address identified with the user.
+ - password (string): The password for the user account.
+ - sendPassword (boolean): If true, sends an email with the password to the user.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "createOrganizationIamUsersIdpsUser",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users"
+
+ body_params = [
+ "displayName",
+ "email",
+ "password",
+ "sendPassword",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdpsUser: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationIamUsersIdpsUser(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update a Meraki user**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - displayName (string): A human-readable identifier for the created user.
+ - email (string): An email address identified with the user.
+ - password (string): The password for the user account.
+ - sendPassword (boolean): If true, sends an email with the password to the user.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "updateOrganizationIamUsersIdpsUser",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users/{id}"
+
+ body_params = [
+ "displayName",
+ "email",
+ "password",
+ "sendPassword",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationIamUsersIdpsUser: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationIamUsersIdpsUser(self, organizationId: str, id: str):
+ """
+ **Delete a Meraki end user**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-idps-user
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "deleteOrganizationIamUsersIdpsUser",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/users/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def createOrganizationIamUsersIdpSync(self, organizationId: str, idpId: str, **kwargs):
+ """
+ **Trigger an IdP sync for an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-iam-users-idp-sync
+
+ - organizationId (string): Organization ID
+ - idpId (string): Idp ID
+ - emails (array): List of emails to sync
+ - force (boolean): Force a complete sync of all users and groups
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync"],
+ "operation": "createOrganizationIamUsersIdpSync",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{idpId}/sync"
+
+ body_params = [
+ "emails",
+ "force",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"createOrganizationIamUsersIdpSync: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersIdpSyncLatest(self, organizationId: str, idpId: str):
+ """
+ **Get the latest IdP sync status for an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idp-sync-latest
+
+ - organizationId (string): Organization ID
+ - idpId (string): Idp ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "sync", "latest"],
+ "operation": "getOrganizationIamUsersIdpSyncLatest",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ idpId = urllib.parse.quote(str(idpId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{idpId}/sync/latest"
+
+ return self._session.get(metadata, resource)
+
+ def updateOrganizationIamUsersIdp(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the identity provider
+ - description (string): Description of the identity provider
+ - idpConfig (object): Identity provider configuration. You can update individual attributes
+ - syncType (string): The synchronization method for the identity provider. Set to 'proactive' to sync all users and groups from your identity provider. Set to 'null' for on-demand user and group provisioning.
+ """
+
+ kwargs.update(locals())
+
+ if "syncType" in kwargs and kwargs["syncType"] is not None:
+ options = ["proactive"]
+ assert kwargs["syncType"] in options, (
+ f'''"syncType" cannot be "{kwargs["syncType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "updateOrganizationIamUsersIdp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}"
+
+ body_params = [
+ "name",
+ "description",
+ "idpConfig",
+ "syncType",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateOrganizationIamUsersIdp: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationIamUsersIdp(self, organizationId: str, id: str):
+ """
+ **Delete a identity provider from an organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-iam-users-idp
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps"],
+ "operation": "deleteOrganizationIamUsersIdp",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationIamUsersIdpAuthZones(self, organizationId: str, id: str):
+ """
+ **List all auth zones for an identity provider**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-idp-auth-zones
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "idps", "authZones"],
+ "operation": "getOrganizationIamUsersIdpAuthZones",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/idps/{id}/authZones"
+
+ return self._session.get(metadata, resource)
+
+ def searchOrganizationUsers(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the end users and their associated identity providers for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!search-organization-users
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 50. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - userIds (array): Filter end users by id(s).
+ - idpIds (array): Filter by identity provider id(s).
+ - groupIds (array): Filter by identity provider group id(s).
+ - accessTypes (array): Filter by access type(s).
+ - searchQuery (string): Fuzzy filter by display name, user name and email.
+ - statuses (array): Filter by user status(es).
+ - sortKey (string): Optional parameter to specify the field used to sort results. (default: username)
+ - sortOrder (string): Optional parameter to specify the sort order. (default: asc)
+ """
+
+ kwargs.update(locals())
+
+ if "sortKey" in kwargs:
+ options = ["created_at", "updated_at", "username"]
+ assert kwargs["sortKey"] in options, (
+ f'''"sortKey" cannot be "{kwargs["sortKey"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "search"],
+ "operation": "searchOrganizationUsers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/search"
+
+ body_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "userIds",
+ "idpIds",
+ "groupIds",
+ "accessTypes",
+ "searchQuery",
+ "statuses",
+ "sortKey",
+ "sortOrder",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"searchOrganizationUsers: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationIamUsersSummaryPanel(self, organizationId: str):
+ """
+ **Get the count of users and user groups for an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-iam-users-summary-panel
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["users", "configure", "iam", "summaryPanel"],
+ "operation": "getOrganizationIamUsersSummaryPanel",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/iam/users/summaryPanel"
+
+ return self._session.get(metadata, resource)
diff --git a/meraki/api/wireless.py b/meraki/api/wireless.py
index 38af3999..cc0c21d8 100644
--- a/meraki/api/wireless.py
+++ b/meraki/api/wireless.py
@@ -68,6 +68,7 @@ def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs):
Dashboard's automatically generated value.
- minor (integer): Desired minor value of the beacon. If the value is set to null it will reset to
Dashboard's automatically generated value.
+ - transmit (object): Transmit settings including power, interval, and advertised power.
"""
kwargs.update(locals())
@@ -83,6 +84,7 @@ def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs):
"uuid",
"major",
"minor",
+ "transmit",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -196,6 +198,23 @@ def updateDeviceWirelessElectronicShelfLabel(self, serial: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getDeviceWirelessHealthScores(self, serial: str):
+ """
+ **Fetch the health scores for a given AP on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-health-scores
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "healthScores"],
+ "operation": "getDeviceWirelessHealthScores",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getDeviceWirelessLatencyStats(self, serial: str, **kwargs):
"""
**Aggregated latency info for a given AP on this network**
@@ -248,6 +267,123 @@ def getDeviceWirelessLatencyStats(self, serial: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getDeviceWirelessRadioAfcPosition(self, serial: str):
+ """
+ **Return the position for a wireless device**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-afc-position
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "position"],
+ "operation": "getDeviceWirelessRadioAfcPosition",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/position"
+
+ return self._session.get(metadata, resource)
+
+ def updateDeviceWirelessRadioAfcPosition(self, serial: str, **kwargs):
+ """
+ **Update the position attributes for this device**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-wireless-radio-afc-position
+
+ - serial (string): Serial
+ - height (object): Height attributes
+ - gps (object): GPS attributes
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "position"],
+ "operation": "updateDeviceWirelessRadioAfcPosition",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/position"
+
+ body_params = [
+ "height",
+ "gps",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceWirelessRadioAfcPosition: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getDeviceWirelessRadioAfcPowerLimits(self, serial: str):
+ """
+ **Return the AFC power limits for a wireless device**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-afc-power-limits
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "powerLimits"],
+ "operation": "getDeviceWirelessRadioAfcPowerLimits",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/afc/powerLimits"
+
+ return self._session.get(metadata, resource)
+
+ def getDeviceWirelessRadioOverrides(self, serial: str):
+ """
+ **Return the radio overrides of a device**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-overrides
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "overrides"],
+ "operation": "getDeviceWirelessRadioOverrides",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/overrides"
+
+ return self._session.get(metadata, resource)
+
+ def updateDeviceWirelessRadioOverrides(self, serial: str, **kwargs):
+ """
+ **Update 2.4 GHz, 5 GHz, and 6 GHz radio settings (channel, channel width, power, and enable/disable) that override RF profiles.**
+ https://developer.cisco.com/meraki/api-v1/#!update-device-wireless-radio-overrides
+
+ - serial (string): Serial
+ - rfProfile (object): This device's RF profile
+ - radios (array): Radio overrides.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "overrides"],
+ "operation": "updateDeviceWirelessRadioOverrides",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/overrides"
+
+ body_params = [
+ "rfProfile",
+ "radios",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateDeviceWirelessRadioOverrides: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
def getDeviceWirelessRadioSettings(self, serial: str):
"""
**Return the manually configured radio settings overrides of a device, which take precedence over RF profiles.**
@@ -300,6 +436,23 @@ def updateDeviceWirelessRadioSettings(self, serial: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def getDeviceWirelessRadioStatus(self, serial: str):
+ """
+ **Show the status of this device's radios**
+ https://developer.cisco.com/meraki/api-v1/#!get-device-wireless-radio-status
+
+ - serial (string): Serial
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "status"],
+ "operation": "getDeviceWirelessRadioStatus",
+ }
+ serial = urllib.parse.quote(str(serial), safe="")
+ resource = f"/devices/{serial}/wireless/radio/status"
+
+ return self._session.get(metadata, resource)
+
def getDeviceWirelessStatus(self, serial: str):
"""
**Return the SSID statuses of an access point**
@@ -655,6 +808,7 @@ def updateNetworkWirelessBluetoothSettings(self, networkId: str, **kwargs):
- majorMinorAssignmentMode (string): The way major and minor number should be assigned to nodes in the network. ('Unique', 'Non-unique')
- major (integer): The major number to be used in the beacon identifier. Only valid in 'Non-unique' mode.
- minor (integer): The minor number to be used in the beacon identifier. Only valid in 'Non-unique' mode.
+ - transmit (object): Transmit settings.
"""
kwargs.update(locals())
@@ -679,6 +833,7 @@ def updateNetworkWirelessBluetoothSettings(self, networkId: str, **kwargs):
"majorMinorAssignmentMode",
"major",
"minor",
+ "transmit",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -848,6 +1003,23 @@ def getNetworkWirelessClientsConnectionStats(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessClientsHealthScores(self, networkId: str):
+ """
+ **Fetch the health scores for all clients on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-clients-health-scores
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "healthScores"],
+ "operation": "getNetworkWirelessClientsHealthScores",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getNetworkWirelessClientsLatencyStats(self, networkId: str, **kwargs):
"""
**Aggregated latency info for this network, grouped by clients**
@@ -902,6 +1074,53 @@ def getNetworkWirelessClientsLatencyStats(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessClientsOnboardingHistory(self, networkId: str, **kwargs):
+ """
+ **Return counts of distinct wireless clients connecting to a network over time**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-clients-onboarding-history
+
+ - networkId (string): Network ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
+ - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 300. The default is 300.
+ - band (string): Filter results by band (either '2.4', '5' or '6'); this cannot be combined with the SSID filter.
+ - ssid (integer): Filter results by SSID number; this cannot be combined with the band filter.
+ """
+
+ kwargs.update(locals())
+
+ if "band" in kwargs:
+ options = ["2.4", "5", "6"]
+ assert kwargs["band"] in options, f'''"band" cannot be "{kwargs["band"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "onboardingHistory"],
+ "operation": "getNetworkWirelessClientsOnboardingHistory",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/onboardingHistory"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "resolution",
+ "band",
+ "ssid",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkWirelessClientsOnboardingHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
def getNetworkWirelessClientConnectionStats(self, networkId: str, clientId: str, **kwargs):
"""
**Aggregated connectivity info for a given client on this network**
@@ -1038,6 +1257,25 @@ def getNetworkWirelessClientConnectivityEvents(
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getNetworkWirelessClientHealthScores(self, networkId: str, clientId: str):
+ """
+ **Fetch the health scores for a given client on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-client-health-scores
+
+ - networkId (string): Network ID
+ - clientId (string): Client ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "healthScores"],
+ "operation": "getNetworkWirelessClientHealthScores",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/{clientId}/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getNetworkWirelessClientLatencyHistory(self, networkId: str, clientId: str, **kwargs):
"""
**Return the latency history for a client**
@@ -1133,6 +1371,53 @@ def getNetworkWirelessClientLatencyStats(self, networkId: str, clientId: str, **
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessClientRoamingHistory(self, networkId: str, clientId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get client roam events within the specified timespan.**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-client-roaming-history
+
+ - networkId (string): Network ID
+ - clientId (string): Client ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "roaming", "history"],
+ "operation": "getNetworkWirelessClientRoamingHistory",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/networks/{networkId}/wireless/clients/{clientId}/roaming/history"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getNetworkWirelessClientRoamingHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getNetworkWirelessConnectionStats(self, networkId: str, **kwargs):
"""
**Aggregated connectivity info for this network**
@@ -1284,6 +1569,23 @@ def getNetworkWirelessDevicesConnectionStats(self, networkId: str, **kwargs):
return self._session.get(metadata, resource, params)
+ def getNetworkWirelessDevicesHealthScores(self, networkId: str):
+ """
+ **Fetch the health scores of all APs on this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-devices-health-scores
+
+ - networkId (string): Network ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "healthScores"],
+ "operation": "getNetworkWirelessDevicesHealthScores",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/devices/healthScores"
+
+ return self._session.get(metadata, resource)
+
def getNetworkWirelessDevicesLatencyStats(self, networkId: str, **kwargs):
"""
**Aggregated latency info for this network, grouped by node**
@@ -1439,6 +1741,7 @@ def createNetworkWirelessEthernetPortsProfile(self, networkId: str, name: str, p
- name (string): AP port profile name
- ports (array): AP ports configuration
- usbPorts (array): AP usb ports configuration
+ - security (object): AP port security configuration
"""
kwargs.update(locals())
@@ -1454,6 +1757,7 @@ def createNetworkWirelessEthernetPortsProfile(self, networkId: str, name: str, p
"name",
"ports",
"usbPorts",
+ "security",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1564,6 +1868,7 @@ def updateNetworkWirelessEthernetPortsProfile(self, networkId: str, profileId: s
- name (string): AP port profile name
- ports (array): AP ports configuration
- usbPorts (array): AP usb ports configuration
+ - security (object): AP port security configuration
"""
kwargs.update(locals())
@@ -1580,6 +1885,7 @@ def updateNetworkWirelessEthernetPortsProfile(self, networkId: str, profileId: s
"name",
"ports",
"usbPorts",
+ "security",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1811,6 +2117,41 @@ def updateNetworkWirelessLocationScanning(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
+ def updateNetworkWirelessLocationWayfinding(self, networkId: str, **kwargs):
+ """
+ **Change client wayfinding settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-location-wayfinding
+
+ - networkId (string): Network ID
+ - enabled (boolean): Whether to enable client wayfinding on that network (only supported on Wireless networks).
+ - maintenanceWindow (object): Maintenance window during which optimization might take place to improve location accuracy.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "wayfinding"],
+ "operation": "updateNetworkWirelessLocationWayfinding",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/location/wayfinding"
+
+ body_params = [
+ "enabled",
+ "maintenanceWindow",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkWirelessLocationWayfinding: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
def getNetworkWirelessMeshStatuses(self, networkId: str, total_pages=1, direction="next", **kwargs):
"""
**List wireless mesh statuses for repeaters**
@@ -1848,32 +2189,26 @@ def getNetworkWirelessMeshStatuses(self, networkId: str, total_pages=1, directio
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
+ def updateNetworkWirelessOpportunisticPcap(self, networkId: str, **kwargs):
"""
- **Update the AutoRF settings for a wireless network**
- https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-rrm
+ **Update the Opportunistic Pcap settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-opportunistic-pcap
- networkId (string): Network ID
- - busyHour (object): Busy Hour settings
- - channel (object): Channel settings
- - fra (object): FRA settings
- - ai (object): AI settings
+ - enablement (object): Enablement settings
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "radio", "rrm"],
- "operation": "updateNetworkWirelessRadioRrm",
+ "tags": ["wireless", "configure", "opportunisticPcap"],
+ "operation": "updateNetworkWirelessOpportunisticPcap",
}
networkId = urllib.parse.quote(str(networkId), safe="")
- resource = f"/networks/{networkId}/wireless/radio/rrm"
+ resource = f"/networks/{networkId}/wireless/opportunisticPcap"
body_params = [
- "busyHour",
- "channel",
- "fra",
- "ai",
+ "enablement",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1881,14 +2216,90 @@ def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
all_params = [] + body_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"updateNetworkWirelessRadioRrm: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"updateNetworkWirelessOpportunisticPcap: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.put(metadata, resource, payload)
- def getNetworkWirelessRfProfiles(self, networkId: str, **kwargs):
+ def updateNetworkWirelessRadioAutoRf(self, networkId: str, **kwargs):
"""
- **List RF profiles for this network**
- https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-rf-profiles
+ **Update the AutoRF settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-auto-rf
+
+ - networkId (string): Network ID
+ - busyHour (object): Busy Hour settings
+ - channel (object): Channel settings
+ - fra (object): FRA settings
+ - aiRrm (object): AI-RRM settings
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "autoRf"],
+ "operation": "updateNetworkWirelessRadioAutoRf",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/radio/autoRf"
+
+ body_params = [
+ "busyHour",
+ "channel",
+ "fra",
+ "aiRrm",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkWirelessRadioAutoRf: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def updateNetworkWirelessRadioRrm(self, networkId: str, **kwargs):
+ """
+ **Update the AutoRF settings for a wireless network**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-radio-rrm
+
+ - networkId (string): Network ID
+ - busyHour (object): Busy Hour settings
+ - channel (object): Channel settings
+ - fra (object): FRA settings
+ - ai (object): AI settings
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "rrm"],
+ "operation": "updateNetworkWirelessRadioRrm",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ resource = f"/networks/{networkId}/wireless/radio/rrm"
+
+ body_params = [
+ "busyHour",
+ "channel",
+ "fra",
+ "ai",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"updateNetworkWirelessRadioRrm: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.put(metadata, resource, payload)
+
+ def getNetworkWirelessRfProfiles(self, networkId: str, **kwargs):
+ """
+ **List RF profiles for this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-network-wireless-rf-profiles
- networkId (string): Network ID
- includeTemplateProfiles (boolean): If the network is bound to a template, this parameter controls whether or not the non-basic RF profiles defined on the template should be included in the response alongside the non-basic profiles defined on the bound network. Defaults to false.
@@ -1933,6 +2344,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
- transmission (object): Settings related to radio transmission.
- perSsidSettings (object): Per-SSID radio settings by number.
- flexRadios (object): Flex radio settings.
+ - dot11be (object): 802.11be settings
"""
kwargs.update(locals())
@@ -1967,6 +2379,7 @@ def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectio
"transmission",
"perSsidSettings",
"flexRadios",
+ "dot11be",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -1998,6 +2411,7 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
- transmission (object): Settings related to radio transmission.
- perSsidSettings (object): Per-SSID radio settings by number.
- flexRadios (object): Flex radio settings.
+ - dot11be (object): 802.11be settings
"""
kwargs.update(locals())
@@ -2035,6 +2449,7 @@ def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwa
"transmission",
"perSsidSettings",
"flexRadios",
+ "dot11be",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -2252,6 +2667,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
- number (string): Number
- name (string): The name of the SSID
- enabled (boolean): Whether or not the SSID is enabled
+ - localAuth (boolean): Extended local auth flag for Enterprise NAC
- authMode (string): The association control method for the SSID ('open', 'open-enhanced', 'psk', 'open-with-radius', 'open-enhanced-with-radius', 'open-with-nac', '8021x-meraki', '8021x-nac', '8021x-radius', '8021x-google', '8021x-entra', '8021x-localradius', 'ipsk-with-radius', 'ipsk-without-radius', 'ipsk-with-nac' or 'ipsk-with-radius-easy-psk')
- enterpriseAdminAccess (string): Whether or not an SSID is accessible by 'enterprise' administrators ('access disabled' or 'access enabled')
- ssidAdminAccessible (boolean): SSID Administrator access status
@@ -2283,6 +2699,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
- radiusAccountingInterimInterval (integer): The interval (in seconds) in which accounting information is updated and sent to the RADIUS accounting server.
- radiusAttributeForGroupPolicies (string): Specify the RADIUS attribute used to look up group policies ('Filter-Id', 'Reply-Message', 'Airespace-ACL-Name' or 'Aruba-User-Role'). Access points must receive this attribute in the RADIUS Access-Accept message
- ipAssignmentMode (string): The client IP assignment mode ('NAT mode', 'Bridge mode', 'Layer 3 roaming', 'Ethernet over GRE', 'Layer 3 roaming with a concentrator', 'VPN' or 'Campus Gateway')
+ - campusGateway (object): Campus gateway settings
- useVlanTagging (boolean): Whether or not traffic should be directed to use specific VLANs. This param is only valid if the ipAssignmentMode is 'Bridge mode' or 'Layer 3 roaming'
- concentratorNetworkId (string): The concentrator to use when the ipAssignmentMode is 'Layer 3 roaming with a concentrator' or 'VPN'.
- secondaryConcentratorNetworkId (string): The secondary concentrator to use when the ipAssignmentMode is 'VPN'. If configured, the APs will switch to using this concentrator if the primary concentrator is unreachable. This param is optional. ('disabled' represents no secondary concentrator.)
@@ -2404,6 +2821,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
body_params = [
"name",
"enabled",
+ "localAuth",
"authMode",
"enterpriseAdminAccess",
"ssidAdminAccessible",
@@ -2435,6 +2853,7 @@ def updateNetworkWirelessSsid(self, networkId: str, number: str, **kwargs):
"radiusAccountingInterimInterval",
"radiusAttributeForGroupPolicies",
"ipAssignmentMode",
+ "campusGateway",
"useVlanTagging",
"concentratorNetworkId",
"secondaryConcentratorNetworkId",
@@ -3017,6 +3436,154 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw
return self._session.put(metadata, resource, payload)
+ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, number: str, **kwargs):
+ """
+ **Update the client exclusion status configuration for a given SSID**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-ssid-policies-client-exclusion
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - static (object): Static client exclusion status
+ - dynamic (object): Dynamic client exclusion configuration
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion"],
+ "operation": "updateNetworkWirelessSsidPoliciesClientExclusion",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion"
+
+ body_params = [
+ "static",
+ "dynamic",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkWirelessSsidPoliciesClientExclusion: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Replace the static client exclusion list for the given SSID (use PUT /exclusions)**
+ https://developer.cisco.com/meraki/api-v1/#!update-network-wireless-ssid-policies-client-exclusion-static-exclusions
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to set as static exclusion list
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions"],
+ "operation": "updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Add MAC addresses to the existing static client exclusion list for the given SSID (use POST /bulkAdd)**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-wireless-ssid-policies-client-exclusion-static-exclusions-bulk-add
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to add to static exclusion
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions", "bulkAdd"],
+ "operation": "createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions/bulkAdd"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove(
+ self, networkId: str, number: str, macs: list, **kwargs
+ ):
+ """
+ **Remove MAC addresses from the existing static client exclusion list for the given SSID (use POST /bulkRemove)**
+ https://developer.cisco.com/meraki/api-v1/#!create-network-wireless-ssid-policies-client-exclusion-static-exclusions-bulk-remove
+
+ - networkId (string): Network ID
+ - number (string): Number
+ - macs (array): MAC addresses to remove from static exclusion
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions", "bulkRemove"],
+ "operation": "createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove",
+ }
+ networkId = urllib.parse.quote(str(networkId), safe="")
+ number = urllib.parse.quote(str(number), safe="")
+ resource = f"/networks/{networkId}/wireless/ssids/{number}/policies/clientExclusion/static/exclusions/bulkRemove"
+
+ body_params = [
+ "macs",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
def getNetworkWirelessSsidSchedules(self, networkId: str, number: str):
"""
**List the outage schedule for the SSID**
@@ -3105,6 +3672,7 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
- redirectUrl (string): The custom redirect URL where the users will go after the splash page.
- useRedirectUrl (boolean): The Boolean indicating whether the the user will be redirected to the custom redirect URL after the splash page. A custom redirect URL must be set if this is true.
- welcomeMessage (string): The welcome message for the users on the splash page.
+ - language (string): Language of splash page.
- userConsent (object): User consent settings
- themeId (string): The id of the selected splash theme.
- splashLogo (object): The logo used in the splash page.
@@ -3126,6 +3694,32 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
assert kwargs["splashTimeout"] in options, (
f'''"splashTimeout" cannot be "{kwargs["splashTimeout"]}", & must be set to one of: {options}'''
)
+ if "language" in kwargs:
+ options = [
+ "DA",
+ "DE",
+ "EL",
+ "EN",
+ "ES",
+ "FI",
+ "FR",
+ "GL",
+ "IT",
+ "JA",
+ "KO",
+ "NL",
+ "NO",
+ "PL",
+ "PT",
+ "RU",
+ "SK",
+ "SV",
+ "UK",
+ "ZH",
+ ]
+ assert kwargs["language"] in options, (
+ f'''"language" cannot be "{kwargs["language"]}", & must be set to one of: {options}'''
+ )
if "controllerDisconnectionBehavior" in kwargs:
options = ["default", "open", "restricted"]
assert kwargs["controllerDisconnectionBehavior"] in options, (
@@ -3147,6 +3741,7 @@ def updateNetworkWirelessSsidSplashSettings(self, networkId: str, number: str, *
"redirectUrl",
"useRedirectUrl",
"welcomeMessage",
+ "language",
"userConsent",
"themeId",
"splashLogo",
@@ -3379,34 +3974,38 @@ def updateNetworkWirelessZigbee(self, networkId: str, **kwargs):
return self._session.put(metadata, resource, payload)
- def getOrganizationWirelessAirMarshalRules(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceConnectivityWirelessRfHealthByBand(self, organizationId: str, networkIds: list, **kwargs):
"""
- **Returns the current Air Marshal rules for this organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-rules
+ **Show the by-device RF Health score overview information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-connectivity-wireless-rf-health-by-band
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): (optional) The set of network IDs to include.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Networks for which information should be gathered.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 3600, 14400, 86400. The default is 3600. Interval is calculated if time params are provided.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "airMarshal", "rules"],
- "operation": "getOrganizationWirelessAirMarshalRules",
+ "tags": ["wireless", "configure", "connectivity", "rfHealth", "byBand"],
+ "operation": "getOrganizationAssuranceConnectivityWirelessRfHealthByBand",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/airMarshal/rules"
+ resource = f"/organizations/{organizationId}/assurance/connectivity/wireless/rfHealth/byBand"
query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
"networkIds",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -3423,23 +4022,26 @@ def getOrganizationWirelessAirMarshalRules(self, organizationId: str, total_page
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessAirMarshalRules: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceConnectivityWirelessRfHealthByBand: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessAirMarshalSettingsByNetwork(
+ def getOrganizationAssuranceImpactedDeviceWirelessByNetwork(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Returns the current Air Marshal settings for this network**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-settings-by-network
+ **Returns count of impacted wireless devices per network on a given organization and time range.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-impacted-device-wireless-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): The network IDs to include in the result set.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 2 hours and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
@@ -3447,14 +4049,17 @@ def getOrganizationWirelessAirMarshalSettingsByNetwork(
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "airMarshal", "settings", "byNetwork"],
- "operation": "getOrganizationWirelessAirMarshalSettingsByNetwork",
+ "tags": ["wireless", "monitor", "impactedDevice", "byNetwork"],
+ "operation": "getOrganizationAssuranceImpactedDeviceWirelessByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/airMarshal/settings/byNetwork"
+ resource = f"/organizations/{organizationId}/assurance/impactedDevice/wireless/byNetwork"
query_params = [
- "networkIds",
+ "networkGroupIds",
+ "t0",
+ "t1",
+ "timespan",
"perPage",
"startingAfter",
"endingBefore",
@@ -3462,7 +4067,7 @@ def getOrganizationWirelessAirMarshalSettingsByNetwork(
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "networkIds",
+ "networkGroupIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3474,23 +4079,29 @@ def getOrganizationWirelessAirMarshalSettingsByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessAirMarshalSettingsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceImpactedDeviceWirelessByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **List access point client count at the moment in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-overview-by-device
+ **Summarizes wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): Optional parameter to filter access points client counts by network ID. This filter uses multiple exact matches.
- - serials (array): Optional parameter to filter access points client counts by its serial numbers. This filter uses multiple exact matches.
- - campusGatewayClusterIds (array): Optional parameter to filter access points client counts by MCG cluster IDs. This filter uses multiple exact matches.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
@@ -3498,16 +4109,20 @@ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, to
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "clients", "overview", "byDevice"],
- "operation": "getOrganizationWirelessClientsOverviewByDevice",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/clients/overview/byDevice"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork"
query_params = [
"networkIds",
"serials",
- "campusGatewayClusterIds",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
"perPage",
"startingAfter",
"endingBefore",
@@ -3517,7 +4132,8 @@ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, to
array_params = [
"networkIds",
"serials",
- "campusGatewayClusterIds",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3529,57 +4145,61 @@ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, to
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationByDevice(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByBand(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get average channel utilization for all bands in a network, split by AP**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-device
+ **Summarizes wireless post connection capacity successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-band
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "byDevice"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationByDevice",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByBand",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byDevice"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byBand"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3591,57 +4211,61 @@ def getOrganizationWirelessDevicesChannelUtilizationByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationByNetwork(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClient(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get average channel utilization across all bands for all networks in the organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-network
+ **Summarizes wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-client
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "byNetwork"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationByNetwork",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClient",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byNetwork"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byClient"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3653,57 +4277,61 @@ def getOrganizationWirelessDevicesChannelUtilizationByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientOs(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get a time-series of average channel utilization for all bands, segmented by device.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-device-by-interval
+ **Summarizes wireless post connection capacity successes and failures by client OS and driver version.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-client-os
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byDevice", "byInterval"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientOs",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byDevice/byInterval"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byClientOs"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3715,57 +4343,61 @@ def getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientType(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get a time-series of average channel utilization for all bands**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-network-by-interval
+ **Summarizes wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-client-type
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
- - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byNetwork", "byInterval"],
- "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientType",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byNetwork/byInterval"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byClientType"
query_params = [
"networkIds",
"serials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
- "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3777,44 +4409,61 @@ def getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesEthernetStatuses(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **List the most recent Ethernet link speed, duplex, aggregation and power mode and status information for wireless devices.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-ethernet-statuses
+ **Summarizes wireless post connection capacity successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-device
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): A list of Meraki network IDs to filter results to contain only specified networks. E.g.: networkIds[]=N_12345678&networkIds[]=L_3456
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "ethernet", "statuses"],
- "operation": "getOrganizationWirelessDevicesEthernetStatuses",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/ethernet/statuses"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byDevice"
query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3826,59 +4475,63 @@ def getOrganizationWirelessDevicesEthernetStatuses(self, organizationId: str, to
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesEthernetStatuses: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPacketLossByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Get average packet loss for the given timespan for all clients in the organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-client
+ **Time-series of wireless post connection capacity successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-interval
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - ssids (array): Filter results by SSID number.
- - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
- - macs (array): Filter results by client mac address(es).
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "packetLoss", "byClient"],
- "operation": "getOrganizationWirelessDevicesPacketLossByClient",
+ "tags": ["wireless", "monitor", "experience", "channelAvailability", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byClient"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/byInterval"
query_params = [
"networkIds",
- "ssids",
+ "serials",
+ "ssidNumbers",
"bands",
- "macs",
- "perPage",
- "startingAfter",
- "endingBefore",
"t0",
"t1",
"timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
- "ssids",
+ "serials",
+ "ssidNumbers",
"bands",
- "macs",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -3890,58 +4543,60 @@ def getOrganizationWirelessDevicesPacketLossByClient(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPacketLossByClient: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPacketLossByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Get average packet loss for the given timespan for all devices in the organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-device
+ **Summarizes wireless post connection capacity successes and failures by ssid.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-by-network-by-ssid
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - ssids (array): Filter results by SSID number.
- - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "packetLoss", "byDevice"],
- "operation": "getOrganizationWirelessDevicesPacketLossByDevice",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkBySsid",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byDevice"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/byNetwork/bySsid"
query_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
- "perPage",
- "startingAfter",
- "endingBefore",
"t0",
"t1",
"timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
]
for k, v in kwargs.items():
@@ -3954,60 +4609,77 @@ def getOrganizationWirelessDevicesPacketLossByDevice(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPacketLossByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPacketLossByNetwork(
+ def getOrganizationAssuranceWirelessExperienceChannelAvailabilityInsightsByNetwork(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **Get average packet loss for the given timespan for all networks in the organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-network
+ **Provides insights into wireless capacity experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-channel-availability-insights-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- networkIds (array): Filter results by network.
- - serials (array): Filter results by device.
- - ssids (array): Filter results by SSID number.
- - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
"""
kwargs.update(locals())
+ if "contributor" in kwargs:
+ options = ["Co-channel interference", "High traffic", "Non-wifi interference"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "monitor", "devices", "packetLoss", "byNetwork"],
- "operation": "getOrganizationWirelessDevicesPacketLossByNetwork",
+ "tags": ["wireless", "configure", "experience", "channelAvailability", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceChannelAvailabilityInsightsByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byNetwork"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/channelAvailability/insights/byNetwork"
query_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "contributor",
+ "subContributor",
+ "insights",
"t0",
"t1",
"timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
- "ssids",
+ "ssidNumbers",
"bands",
]
for k, v in kwargs.items():
@@ -4020,53 +4692,143 @@ def getOrganizationWirelessDevicesPacketLossByNetwork(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPacketLossByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceChannelAvailabilityInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesPowerModeHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationAssuranceWirelessExperienceClientsInsights(self, organizationId: str, **kwargs):
"""
- **Return a record of power mode changes for wireless devices in the organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-power-mode-history
+ **Returns the top wireless service-level insights for the specified time window, including each network and the impacted client count per metric.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-clients-insights
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days.
+ - limit (integer): Number of top networks to return. Default is 5. Maximum is 10.
+ """
+
+ kwargs.update(locals())
+
+ if "limit" in kwargs:
+ options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ assert kwargs["limit"] in options, f'''"limit" cannot be "{kwargs["limit"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "clients", "insights"],
+ "operation": "getOrganizationAssuranceWirelessExperienceClientsInsights",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/clients/insights"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "limit",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceClientsInsights: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceClientsOverviewHistoryByInterval(self, organizationId: str, **kwargs):
+ """
+ **Returns time series data for impacted and active clients for organization wireless experience metrics.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-clients-overview-history-by-interval
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 300, 600, 900, 1800, 3600, 86400. The default is 300.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "clients", "overview", "history", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceClientsOverviewHistoryByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/clients/overview/history/byInterval"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "resolution",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceClientsOverviewHistoryByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
- - serials (array): Optional parameter to filter device availabilities history by device serial numbers
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "power", "mode", "history"],
- "operation": "getOrganizationWirelessDevicesPowerModeHistory",
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/power/mode/history"
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork"
query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
"t0",
"t1",
"timespan",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
"serials",
+ "ssidNumbers",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4078,133 +4840,5359 @@ def getOrganizationWirelessDevicesPowerModeHistory(self, organizationId: str, to
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesPowerModeHistory: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetwork: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesProvisioningDeployments(
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByBand(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **List the zero touch deployments for wireless access points in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-deployments
+ **Summarizes wireless coverage successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-band
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 20.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - search (string): Filter by MAC address, serial number, new device name, old device name, or model.
- - sortBy (string): Field used to sort results. Default is 'status'.
- - sortOrder (string): Sort order. Default is 'asc'.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByBand",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byBand"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientOs(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Time-series of wireless coverage successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "coverage", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless coverage successes and failures by SSID.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceCoverageInsightsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides insights into wireless coverage experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-coverage-insights-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "contributor" in kwargs:
+ options = ["Admin power restriction", "Insufficient AP density", "Sticky client", "Transient weak signal"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "coverage", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceCoverageInsightsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/coverage/insights/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "contributor",
+ "subContributor",
+ "insights",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceCoverageInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceMetricsOverviewHistoryByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns organization wireless experience metrics overview grouped by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-metrics-overview-history-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "metrics", "overview", "history", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceMetricsOverviewHistoryByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/metrics/overview/history/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceMetricsOverviewHistoryByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceMostImpactedNetworks(self, organizationId: str, **kwargs):
+ """
+ **Returns the most impacted wireless experience networks and the top failure contributor for each network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-most-impacted-networks
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - limit (integer): Number of most impacted networks to return. Default is 5. Maximum is 10.
+ """
+
+ kwargs.update(locals())
+
+ if "limit" in kwargs:
+ options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ assert kwargs["limit"] in options, f'''"limit" cannot be "{kwargs["limit"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "mostImpactedNetworks"],
+ "operation": "getOrganizationAssuranceWirelessExperienceMostImpactedNetworks",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/mostImpactedNetworks"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "limit",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceMostImpactedNetworks: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceMostImpactedXMs(self, organizationId: str, **kwargs):
+ """
+ **Returns the most impacted wireless experience metrics and the top failure contributor for each metric/network pair.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-most-impacted-x-ms
+
+ - organizationId (string): Organization ID
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - limit (integer): Number of most impacted XMs to return. Default is 5. Maximum is 10.
+ """
+
+ kwargs.update(locals())
+
+ if "limit" in kwargs:
+ options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ assert kwargs["limit"] in options, f'''"limit" cannot be "{kwargs["limit"]}", & must be set to one of: {options}'''
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "mostImpactedXMs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceMostImpactedXMs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/mostImpactedXMs"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "limit",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceMostImpactedXMs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByBand(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-band
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByBand",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byBand"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 10000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientOs(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Time-series of wireless connection successes and failures by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "successfulConnects", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByServer(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-server
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "byServer"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/byServer"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by ssid.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides insights into wireless successful connects experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-insights-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "contributor" in kwargs:
+ options = ["assoc", "auth", "dhcp", "dns"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "successfulConnects", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/insights/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "contributor",
+ "subContributor",
+ "insights",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless time to connect metrics by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByBand(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by band.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-band
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byBand"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByBand",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byBand"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByBand: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless time to connect metrics by client.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 10000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byClient"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientOs(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client OS.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-client-os
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byClientOs"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientOs",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byClientOs"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientOs: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientType(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection successes and failures by client type.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-client-type
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byClientType"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientType",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byClientType"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByClientType: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection time to connect metrics by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byDevice"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Time-series of wireless time to connect by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 14 days. The default is 2 hours. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 60, 300, 600, 3600, 14400, 86400. The default is 300. Interval is calculated if time params are provided.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "experience", "timeToConnect", "byNetwork", "byInterval"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByServer(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection time to connect metrics by server.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-server
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "byServer"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByServer",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/byServer"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkByServer: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarizes wireless connection time to connect metrics by ssid.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "byNetwork", "bySsid"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationAssuranceWirelessExperienceTimeToConnectInsightsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Provides insights into wireless time to connect experience by network.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-time-to-connect-insights-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial.
+ - ssidNumbers (array): Filter results by SSID number.
+ - bands (array): Filter results by band.
+ - contributor (string): Contributor for which to retrieve insights. If not specified, returns overall insights.
+ - subContributor (string): Sub-contributor for which to retrieve insights. If not specified, returns all sub contributor insights.
+ - insights (string): Insights version to use. Defaults to 2.
+ - variant (string): Wireless State Machine variant to use.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 15 minutes and be less than or equal to 14 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "contributor" in kwargs:
+ options = ["assoc", "auth", "dhcp", "dns"]
+ assert kwargs["contributor"] in options, (
+ f'''"contributor" cannot be "{kwargs["contributor"]}", & must be set to one of: {options}'''
+ )
+ if "insights" in kwargs:
+ options = ["1", "2"]
+ assert kwargs["insights"] in options, (
+ f'''"insights" cannot be "{kwargs["insights"]}", & must be set to one of: {options}'''
+ )
+ if "variant" in kwargs:
+ options = ["A", "B"]
+ assert kwargs["variant"] in options, (
+ f'''"variant" cannot be "{kwargs["variant"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "experience", "timeToConnect", "insights", "byNetwork"],
+ "operation": "getOrganizationAssuranceWirelessExperienceTimeToConnectInsightsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/assurance/wireless/experience/timeToConnect/insights/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ "contributor",
+ "subContributor",
+ "insights",
+ "variant",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssidNumbers",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationAssuranceWirelessExperienceTimeToConnectInsightsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessAirMarshalRules(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns the current Air Marshal rules for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-rules
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): (optional) The set of network IDs to include.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "airMarshal", "rules"],
+ "operation": "getOrganizationWirelessAirMarshalRules",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/airMarshal/rules"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessAirMarshalRules: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessAirMarshalSettingsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns the current Air Marshal settings for this network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-air-marshal-settings-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): The network IDs to include in the result set.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "airMarshal", "settings", "byNetwork"],
+ "operation": "getOrganizationWirelessAirMarshalSettingsByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/airMarshal/settings/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessAirMarshalSettingsByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessAlertsLowPowerByDevice(self, organizationId: str, networkIds: list, **kwargs):
+ """
+ **Gets all low power related alerts over a given network and returns information by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-alerts-low-power-by-device
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "alerts", "lowPower", "byDevice"],
+ "operation": "getOrganizationWirelessAlertsLowPowerByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/alerts/lowPower/byDevice"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessAlertsLowPowerByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessCertificatesOpenRoamingCertificateAuthority(self, organizationId: str):
+ """
+ **Query for details on the organization's OpenRoaming Certificate Authority certificate (CAs).**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-certificates-open-roaming-certificate-authority
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "certificates", "openRoaming", "certificateAuthority"],
+ "operation": "getOrganizationWirelessCertificatesOpenRoamingCertificateAuthority",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/certificates/openRoaming/certificateAuthority"
+
+ return self._session.get(metadata, resource)
+
+ def getOrganizationWirelessClientsConnectionsAssociationByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarize association outcomes per wireless client across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-association-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "association", "byClient"],
+ "operation": "getOrganizationWirelessClientsConnectionsAssociationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/association/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsAssociationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsConnectionsAuthenticationByClient(self, organizationId: str, **kwargs):
+ """
+ **Summarize authentication outcomes per wireless client across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-authentication-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "authentication", "byClient"],
+ "operation": "getOrganizationWirelessClientsConnectionsAuthenticationByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/authentication/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsAuthenticationByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsConnectionsDhcpByClient(self, organizationId: str, **kwargs):
+ """
+ **Get IP assignment for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-dhcp-by-client
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 7 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 2 hours.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "dhcp", "byClient"],
+ "operation": "getOrganizationWirelessClientsConnectionsDhcpByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/dhcp/byClient"
+
+ query_params = [
+ "networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsDhcpByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsConnectionsFailuresHistoryByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns failed wireless client connections for this organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-failures-history-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - connectionTimeSortOrder (string): (optional) Sort order of events by connection start time. (default desc)
+ - failureSteps (array): (optional) The step in the connection process that failed
+ - clientMac (string): (optional) The MAC address of the client with which the list of events will be filtered.
+ - serials (array): (optional) Filter devices by serial number
+ - timespan (integer): (optional) The timespan, in seconds, for the failed connections. The period will be from [timespan] seconds ago until now. The maximum allowed timespan is 1 month. Default: 86400 (24 hours)
+ - ssidNumber (integer): (optional) The SSID number to include
+ - networkIds (array): (optional) The set of network IDs to include.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ if "connectionTimeSortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["connectionTimeSortOrder"] in options, (
+ f'''"connectionTimeSortOrder" cannot be "{kwargs["connectionTimeSortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "ssidNumber" in kwargs:
+ options = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
+ assert kwargs["ssidNumber"] in options, (
+ f'''"ssidNumber" cannot be "{kwargs["ssidNumber"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "connections", "failures", "history", "byDevice"],
+ "operation": "getOrganizationWirelessClientsConnectionsFailuresHistoryByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/failures/history/byDevice"
+
+ query_params = [
+ "connectionTimeSortOrder",
+ "failureSteps",
+ "clientMac",
+ "serials",
+ "timespan",
+ "ssidNumber",
+ "networkIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "failureSteps",
+ "serials",
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsFailuresHistoryByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsConnectionsImpactedByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Summarize the number of wireless clients impacted by connection failures on network SSIDs, across an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-connections-impacted-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 7 days. The default is 2 hours.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "connections", "impacted", "byNetwork", "bySsid"],
+ "operation": "getOrganizationWirelessClientsConnectionsImpactedByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/connections/impacted/byNetwork/bySsid"
+
+ query_params = [
+ "networkIds",
+ "networkGroupIds",
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsConnectionsImpactedByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsOverviewByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List access point client count at the moment in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-overview-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter access points client counts by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter access points client counts by its serial numbers. This filter uses multiple exact matches.
+ - campusGatewayClusterIds (array): Optional parameter to filter access points client counts by MCG cluster IDs. This filter uses multiple exact matches.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "overview", "byDevice"],
+ "operation": "getOrganizationWirelessClientsOverviewByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/overview/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "campusGatewayClusterIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "campusGatewayClusterIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsOverviewByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def byOrganizationWirelessClientsRfHealthOverviewNetwork(self, organizationId: str, **kwargs):
+ """
+ **Show the by-network client information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!by-organization-wireless-clients-rf-health-overview-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Networks for which information should be gathered.
+ - bands (array): Bands for which information should be gathered. Valid bands are 2.4, 5, and 6.
+ - channels (array): Channel for which information should be gathered.
+ - serials (array): Serial number of the devices for which information should be gathered.
+ - gFloorplanId (string): Geoaligned floorplan ID nodes for which information is gathered belong to.
+ - tags (array): Access Point tags for which information should be gathered.
+ - models (array): Access Point models for which information should be gathered.
+ - rfProfiles (array): Rf Profiles for which information should be gathered.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
+ - retryOnEmpty (boolean): If true, the query will be retried with a longer timeframe if the results are empty.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "rfHealth", "overview"],
+ "operation": "byOrganizationWirelessClientsRfHealthOverviewNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/rfHealth/overview/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "gFloorplanId",
+ "tags",
+ "models",
+ "rfProfiles",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ "retryOnEmpty",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"byOrganizationWirelessClientsRfHealthOverviewNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessClientsStickyEvents(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get sticky client events within the specified timespan.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-sticky-events
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - clientIds (array): Filter results by client id.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "clients", "stickyEvents"],
+ "operation": "getOrganizationWirelessClientsStickyEvents",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/stickyEvents"
+
+ query_params = [
+ "networkIds",
+ "clientIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "clientIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsStickyEvents: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsUsageByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns client usage details for wireless networks within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-usage-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - networkIds (array): Filter results by a list of network IDs.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - gatewayNetworkIds (array): Limit the results to clients tunneled to campus gateways in the provided networks.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "usage", "byNetwork"],
+ "operation": "getOrganizationWirelessClientsUsageByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/usage/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsUsageByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsUsageByNetworkBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns client usage details for wireless network SSIDs within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-usage-by-network-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - networkIds (array): Filter results by a list of network IDs.
+ - networkGroupIds (array): Filter results by a list of network group IDs.
+ - ssidIds (array): Filter results by a list of SSID IDs.
+ - ssidNames (array): Filter results by a list of SSID names.
+ - gatewayNetworkIds (array): Limit the results to clients tunneled to campus gateways in the provided networks.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "usage", "byNetwork", "bySsid"],
+ "operation": "getOrganizationWirelessClientsUsageByNetworkBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/usage/byNetwork/bySsid"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "networkGroupIds",
+ "ssidIds",
+ "ssidNames",
+ "gatewayNetworkIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "networkGroupIds",
+ "ssidIds",
+ "ssidNames",
+ "gatewayNetworkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsUsageByNetworkBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessClientsUsageBySsid(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Returns client usage details for SSIDs within an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-clients-usage-by-ssid
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 8 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 1 hour and be less than or equal to 7 days. The default is 2 hours.
+ - ssidNames (array): Filter results by a list of SSID names.
+ - networkIds (array): Limit the results to clients that belong to one of the provided networks.
+ - networkGroupIds (array): Limit the results to clients that belong to one of the provided network groups.
+ - gatewayNetworkIds (array): Limit the results to clients tunneled to campus gateways in the provided networks.
+ - usageUnits (string): Usage units to use in the response.
+ """
+
+ kwargs.update(locals())
+
+ if "usageUnits" in kwargs:
+ options = ["GB", "KB", "MB", "TB"]
+ assert kwargs["usageUnits"] in options, (
+ f'''"usageUnits" cannot be "{kwargs["usageUnits"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "monitor", "clients", "usage", "bySsid"],
+ "operation": "getOrganizationWirelessClientsUsageBySsid",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/clients/usage/bySsid"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "ssidNames",
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ "usageUnits",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "ssidNames",
+ "networkIds",
+ "networkGroupIds",
+ "gatewayNetworkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessClientsUsageBySsid: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesAccelerometerStatuses(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the most recent AP accelerometer status information for wireless devices that support it.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-accelerometer-statuses
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of Meraki network IDs to filter results to contain only specified networks. E.g.: networkIds[]=N_12345678&networkIds[]=L_3456
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "accelerometer", "statuses"],
+ "operation": "getOrganizationWirelessDevicesAccelerometerStatuses",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/accelerometer/statuses"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesAccelerometerStatuses: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average channel utilization for all bands in a network, split by AP**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average channel utilization across all bands for all networks in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get a time-series of average channel utilization for all bands, segmented by device.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-device-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byDevice", "byInterval"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byDevice/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationHistoryByDeviceByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get a time-series of average channel utilization for all bands**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-channel-utilization-history-by-network-by-interval
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 3600, 7200, 14400, 21600. The default is 3600.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "channelUtilization", "history", "byNetwork", "byInterval"],
+ "operation": "getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/channelUtilization/history/byNetwork/byInterval"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesChannelUtilizationHistoryByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesDataRateByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get average uplink and downlink datarates for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-data-rate-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - macs (array): Filter results by client mac address(es).
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "dataRate", "byClient"],
+ "operation": "getOrganizationWirelessDevicesDataRateByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/dataRate/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesDataRateByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesEthernetStatuses(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the most recent Ethernet link speed, duplex, aggregation and power mode and status information for wireless devices.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-ethernet-statuses
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of Meraki network IDs to filter results to contain only specified networks. E.g.: networkIds[]=N_12345678&networkIds[]=L_3456
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "ethernet", "statuses"],
+ "operation": "getOrganizationWirelessDevicesEthernetStatuses",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/ethernet/statuses"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesEthernetStatuses: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesLatencyByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get latency summaries for all wireless devices in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-latency-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - networkIds (array): Filter results by network.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssids (array): Filter results by SSID number.
+ - macs (array): Filter results by client mac address(es).
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "latency", "byClient"],
+ "operation": "getOrganizationWirelessDevicesLatencyByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/latency/byClient"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "bands",
+ "ssids",
+ "macs",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "bands",
+ "ssids",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesLatencyByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesLatencyByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get latency summaries for all wireless devices in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-latency-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssids (array): Filter results by SSID number.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "latency", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesLatencyByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/latency/byDevice"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesLatencyByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesLatencyByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get per-network latency summaries for all wireless networks in an organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-latency-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 90 days. The default is 7 days.
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - ssids (array): Filter results by SSID number.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "latency", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesLatencyByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/latency/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "bands",
+ "ssids",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesLatencyByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessDevicesLiveToolsClientDisconnect(self, organizationId: str, clientId: str, **kwargs):
+ """
+ **Enqueue a job to disconnect a client from an AP**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-live-tools-client-disconnect
+
+ - organizationId (string): Organization ID
+ - clientId (string): Client ID
+ - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "liveTools", "devices", "clients", "disconnect"],
+ "operation": "createOrganizationWirelessDevicesLiveToolsClientDisconnect",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ clientId = urllib.parse.quote(str(clientId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/liveTools/clients/{clientId}/disconnect"
+
+ body_params = [
+ "callback",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWirelessDevicesLiveToolsClientDisconnect: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def getOrganizationWirelessDevicesPacketLossByClient(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get average packet loss for the given timespan for all clients in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - macs (array): Filter results by client mac address(es).
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "packetLoss", "byClient"],
+ "operation": "getOrganizationWirelessDevicesPacketLossByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byClient"
+
+ query_params = [
+ "networkIds",
+ "ssids",
+ "bands",
+ "macs",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "ssids",
+ "bands",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPacketLossByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesPacketLossByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Get average packet loss for the given timespan for all devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "packetLoss", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesPacketLossByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPacketLossByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesPacketLossByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average packet loss for the given timespan for all networks in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-packet-loss-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 90 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 90 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 90 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "packetLoss", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesPacketLossByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/packetLoss/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPacketLossByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesPowerModeHistory(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return a record of power mode changes for wireless devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-power-mode-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): Optional parameter to filter device availabilities history by device serial numbers
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "power", "mode", "history"],
+ "operation": "getOrganizationWirelessDevicesPowerModeHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/power/mode/history"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesPowerModeHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesProvisioningDeployments(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List the zero touch deployments for wireless access points in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-deployments
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 20.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - search (string): Filter by MAC address, serial number, new device name, old device name, or model.
+ - sortBy (string): Field used to sort results. Default is 'status'.
+ - sortOrder (string): Sort order. Default is 'asc'.
- deploymentType (string): Filter deployments by type.
"""
kwargs.update(locals())
- if "sortBy" in kwargs:
- options = ["afterAction", "createdAt", "deploymentId", "name", "status"]
- assert kwargs["sortBy"] in options, (
- f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
- )
- if "sortOrder" in kwargs:
- options = ["asc", "desc"]
- assert kwargs["sortOrder"] in options, (
- f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
- )
- if "deploymentType" in kwargs:
- options = ["deploy", "replace"]
- assert kwargs["deploymentType"] in options, (
- f'''"deploymentType" cannot be "{kwargs["deploymentType"]}", & must be set to one of: {options}'''
- )
+ if "sortBy" in kwargs:
+ options = ["afterAction", "createdAt", "deploymentId", "name", "status"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+ if "deploymentType" in kwargs:
+ options = ["deploy", "replace"]
+ assert kwargs["deploymentType"] in options, (
+ f'''"deploymentType" cannot be "{kwargs["deploymentType"]}", & must be set to one of: {options}'''
+ )
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "getOrganizationWirelessDevicesProvisioningDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "search",
+ "sortBy",
+ "sortOrder",
+ "deploymentType",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ if self._session._validate_kwargs:
+ all_params = query_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, items: list, **kwargs):
+ """
+ **Create a zero touch deployment for a wireless access point**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-provisioning-deployment
+
+ - organizationId (string): Organization ID
+ - items (array): List of zero touch deployments to create
+ - meta (object): Metadata relevant to the paginated dataset
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "createOrganizationWirelessDevicesProvisioningDeployment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+
+ body_params = [
+ "items",
+ "meta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWirelessDevicesProvisioningDeployment: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationId: str, items: list, **kwargs):
+ """
+ **Update a zero touch deployment**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-provisioning-deployments
+
+ - organizationId (string): Organization ID
+ - items (array): List of zero touch deployments to create
+ - meta (object): Metadata relevant to the paginated dataset
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "updateOrganizationWirelessDevicesProvisioningDeployments",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+
+ body_params = [
+ "items",
+ "meta",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def getOrganizationWirelessDevicesProvisioningDeploymentsByNewDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns deployment IDs for the given new node serial numbers**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-deployments-by-new-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 80.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - serials (array): Array of new device serial numbers to query
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments", "byNewDevice"],
+ "operation": "getOrganizationWirelessDevicesProvisioningDeploymentsByNewDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/byNewDevice"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesProvisioningDeploymentsByNewDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def deleteOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, deploymentId: str):
+ """
+ **Delete a zero touch deployment**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-devices-provisioning-deployment
+
+ - organizationId (string): Organization ID
+ - deploymentId (string): Deployment ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
+ "operation": "deleteOrganizationWirelessDevicesProvisioningDeployment",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ deploymentId = urllib.parse.quote(str(deploymentId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/{deploymentId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationWirelessDevicesProvisioningRecommendationsTags(self, organizationId: str, **kwargs):
+ """
+ **List the recommended device tags for zero touch deployments available for the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-provisioning-recommendations-tags
+
+ - organizationId (string): Organization ID
+ - networkIds (array): The list of networks to use as hints for device tags recommendations.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "provisioning", "recommendations", "tags"],
+ "operation": "getOrganizationWirelessDevicesProvisioningRecommendationsTags",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/provisioning/recommendations/tags"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesProvisioningRecommendationsTags: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ """
+ **Query for details on the organization's RadSec device Certificate Authority certificates (CAs)**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
+ "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def updateOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ """
+ **Update an organization's RadSec device Certificate Authority (CA) state**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-radsec-certificates-authorities
+
+ - organizationId (string): Organization ID
+ - status (string): The "status" to update the Certificate Authority to. Only valid option is "trusted".
+ - certificateAuthorityId (string): The ID of the Certificate Authority to update.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
+ "operation": "updateOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+
+ body_params = [
+ "status",
+ "certificateAuthorityId",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def createOrganizationWirelessDevicesRadsecCertificatesAuthority(self, organizationId: str):
+ """
+ **Create an organization's RadSec device Certificate Authority (CA)**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-radsec-certificates-authority
+
+ - organizationId (string): Organization ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
+ "operation": "createOrganizationWirelessDevicesRadsecCertificatesAuthority",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+
+ return self._session.post(metadata, resource)
+
+ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls(self, organizationId: str, **kwargs):
+ """
+ **Query for certificate revocation list (CRL) for the organization's RadSec device Certificate Authorities (CAs).**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls"],
+ "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas(self, organizationId: str, **kwargs):
+ """
+ **Query for all delta certificate revocation list (CRL) for the organization's RadSec device Certificate Authority (CA) with the given id.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls-deltas
+
+ - organizationId (string): Organization ID
+ - certificateAuthorityIds (array): Parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls", "deltas"],
+ "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls/deltas"
+
+ query_params = [
+ "certificateAuthorityIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "certificateAuthorityIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessDevicesSignalQualityByClient(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average signal quality for all clients in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-signal-quality-by-client
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - macs (array): Filter results by client mac address(es).
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "signalQuality", "byClient"],
+ "operation": "getOrganizationWirelessDevicesSignalQualityByClient",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/signalQuality/byClient"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "macs",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSignalQualityByClient: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesSignalQualityByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average signal quality for all devices in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-signal-quality-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "signalQuality", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesSignalQualityByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/signalQuality/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSignalQualityByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesSignalQualityByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Get average signal quality for all networks in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-signal-quality-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Filter results by network.
+ - serials (array): Filter results by device serial number.
+ - ssids (array): Filter results by SSID number.
+ - bands (array): Filter results by band. Valid bands are: 2.4, 5, and 6.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days. The default is 7 days.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "signalQuality", "byNetwork"],
+ "operation": "getOrganizationWirelessDevicesSignalQualityByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/signalQuality/byNetwork"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "ssids",
+ "bands",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSignalQualityByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesSystemCpuLoadHistory(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return the CPU Load history for a list of wireless devices in the organization.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-system-cpu-load-history
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
+ - serials (array): Optional parameter to filter device availabilities history by device serial numbers
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "system", "cpu", "load", "history"],
+ "operation": "getOrganizationWirelessDevicesSystemCpuLoadHistory",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/system/cpu/load/history"
+
+ query_params = [
+ "t0",
+ "t1",
+ "timespan",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesSystemCpuLoadHistory: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesTelemetry(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the wireless device telemetry of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-telemetry
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 200. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 3 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 minutes after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be greater than or equal to 5 minutes and be less than or equal to 30 minutes. The default is 30 minutes.
+ - networkIds (array): Optional parameter to filter results by network.
+ - serials (array): Optional parameter to filter results by device serial.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "telemetry"],
+ "operation": "getOrganizationWirelessDevicesTelemetry",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/telemetry"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "t0",
+ "t1",
+ "timespan",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesTelemetry: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessDevicesWirelessControllersByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List of Catalyst access points information**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-wireless-controllers-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter access points by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter access points by its cloud ID. This filter uses multiple exact matches.
+ - controllerSerials (array): Optional parameter to filter access points by its wireless LAN controller cloud ID. This filter uses multiple exact matches.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "monitor", "devices", "wirelessControllers", "byDevice"],
+ "operation": "getOrganizationWirelessDevicesWirelessControllersByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/devices/wirelessControllers/byDevice"
+
+ query_params = [
+ "networkIds",
+ "serials",
+ "controllerSerials",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ "controllerSerials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessDevicesWirelessControllersByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessLocationScanningByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return scanning API settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter scanning settings by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "byNetwork"],
+ "operation": "getOrganizationWirelessLocationScanningByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessLocationScanningByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessLocationScanningReceivers(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return scanning API receivers**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-receivers
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter scanning API receivers by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "getOrganizationWirelessLocationScanningReceivers",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessLocationScanningReceivers: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessLocationScanningReceiver(
+ self, organizationId: str, network: dict, url: str, version: str, radio: dict, sharedSecret: str, **kwargs
+ ):
+ """
+ **Add new receiver for scanning API**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-location-scanning-receiver
+
+ - organizationId (string): Organization ID
+ - network (object): Add scanning API receiver for network
+ - url (string): Receiver Url
+ - version (string): Scanning API Version
+ - radio (object): Add scanning API Radio
+ - sharedSecret (string): Secret Value for Receiver
+ """
+
+ kwargs = locals()
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "createOrganizationWirelessLocationScanningReceiver",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+
+ body_params = [
+ "network",
+ "url",
+ "version",
+ "radio",
+ "sharedSecret",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"createOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
+
+ def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str, **kwargs):
+ """
+ **Change scanning API receiver settings**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-location-scanning-receiver
+
+ - organizationId (string): Organization ID
+ - receiverId (string): Receiver ID
+ - url (string): Receiver Url
+ - version (string): Scanning API Version
+ - radio (object): Add scanning API Radio
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "updateOrganizationWirelessLocationScanningReceiver",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ receiverId = urllib.parse.quote(str(receiverId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
+
+ body_params = [
+ "url",
+ "version",
+ "radio",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str):
+ """
+ **Delete a scanning API receiver**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-location-scanning-receiver
+
+ - organizationId (string): Organization ID
+ - receiverId (string): Receiver ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "scanning", "receivers"],
+ "operation": "deleteOrganizationWirelessLocationScanningReceiver",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ receiverId = urllib.parse.quote(str(receiverId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
+
+ return self._session.delete(metadata, resource)
+
+ def getOrganizationWirelessLocationWayfindingByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Return Client wayfinding settings**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-wayfinding-by-network
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter wayfinding settings by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "location", "wayfinding", "byNetwork"],
+ "operation": "getOrganizationWirelessLocationWayfindingByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/location/wayfinding/byNetwork"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessLocationWayfindingByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessMqttSettings(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **Return MQTT Settings for networks**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-mqtt-settings
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter mqtt settings by network ID.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "mqtt", "settings"],
+ "operation": "getOrganizationWirelessMqttSettings",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def updateOrganizationWirelessMqttSettings(self, organizationId: str, network: dict, mqtt: dict, **kwargs):
+ """
+ **Add new broker config for wireless MQTT**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-mqtt-settings
+
+ - organizationId (string): Organization ID
+ - network (object): Add MQTT Settings for network
+ - mqtt (object): MQTT Settings for network
+ - ble (object): MQTT BLE Settings for network
+ - wifi (object): MQTT Wi-Fi Settings for network
+ """
+
+ kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "getOrganizationWirelessDevicesProvisioningDeployments",
+ "tags": ["wireless", "configure", "mqtt", "settings"],
+ "operation": "updateOrganizationWirelessMqttSettings",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+ resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+
+ body_params = [
+ "network",
+ "mqtt",
+ "ble",
+ "wifi",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def byOrganizationWirelessOpportunisticPcapLicenseNetwork(self, organizationId: str, **kwargs):
+ """
+ **Check the Opportunistic Pcap license status of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!by-organization-wireless-opportunistic-pcap-license-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter results by network.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "opportunisticPcap", "license"],
+ "operation": "byOrganizationWirelessOpportunisticPcapLicenseNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/opportunisticPcap/license/byNetwork"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"byOrganizationWirelessOpportunisticPcapLicenseNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessRadioAfcPositionByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ """
+ **List the AFC power limits of an organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-afc-position-by-device
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter device's AFC position by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter device's AFC position by device serial numbers. This filter uses multiple exact matches.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "afc", "position", "byDevice"],
+ "operation": "getOrganizationWirelessRadioAfcPositionByDevice",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/radio/afc/position/byDevice"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
- "search",
- "sortBy",
- "sortOrder",
- "deploymentType",
+ "networkIds",
+ "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
if self._session._validate_kwargs:
- all_params = query_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioAfcPositionByDevice: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def createOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, items: list, **kwargs):
+ def getOrganizationWirelessRadioAfcPowerLimitsByDevice(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Create a zero touch deployment for a wireless access point**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-provisioning-deployment
+ **List the AFC power limits of an organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-afc-power-limits-by-device
- organizationId (string): Organization ID
- - items (array): List of zero touch deployments to create
- - meta (object): Metadata relevant to the paginated dataset
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter device's AFC power limits by network ID. This filter uses multiple exact matches.
+ - serials (array): Optional parameter to filter device's AFC power limits by device serial numbers. This filter uses multiple exact matches.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "createOrganizationWirelessDevicesProvisioningDeployment",
+ "tags": ["wireless", "configure", "radio", "afc", "powerLimits", "byDevice"],
+ "operation": "getOrganizationWirelessRadioAfcPowerLimitsByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+ resource = f"/organizations/{organizationId}/wireless/radio/afc/powerLimits/byDevice"
+
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "serials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessRadioAfcPowerLimitsByDevice: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def getOrganizationWirelessRadioAutoRfByNetwork(self, organizationId: str, **kwargs):
+ """
+ **List the AutoRF settings of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-auto-rf-by-network
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter results by network.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "autoRf", "byNetwork"],
+ "operation": "getOrganizationWirelessRadioAutoRfByNetwork",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/radio/autoRf/byNetwork"
+
+ query_params = [
+ "networkIds",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessRadioAutoRfByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get(metadata, resource, params)
+
+ def getOrganizationWirelessRadioAutoRfChannelsPlanningActivities(self, organizationId: str, **kwargs):
+ """
+ **List the channel planning activities of an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-auto-rf-channels-planning-activities
+
+ - organizationId (string): Organization ID
+ - networkIds (array): Optional parameter to filter results by network.
+ - deviceSerials (array): Optional parameter to filter results by device serial.
+ - bands (array): Optional parameter to filter results by bands. Valid bands are 2.4, 5, and 6.
+ - channels (array): Optional parameter to filter results by channels.
+ - serials (array): Serial number of the devices for which information should be gathered.
+ - gFloorplanId (string): Geoaligned floorplan ID nodes for which information is gathered belong to.
+ - tags (array): Optional parameter to filter results by node tags.
+ - models (array): Optional parameter to filter results by access point models.
+ - rfProfiles (array): Optional parameter to filter results by RF Profiles.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "radio", "autoRf", "channels", "planning", "activities"],
+ "operation": "getOrganizationWirelessRadioAutoRfChannelsPlanningActivities",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/planning/activities"
+
+ query_params = [
+ "networkIds",
+ "deviceSerials",
+ "bands",
+ "channels",
+ "serials",
+ "gFloorplanId",
+ "tags",
+ "models",
+ "rfProfiles",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- body_params = [
- "items",
- "meta",
+ array_params = [
+ "networkIds",
+ "deviceSerials",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"createOrganizationWirelessDevicesProvisioningDeployment: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioAutoRfChannelsPlanningActivities: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.post(metadata, resource, payload)
+ return self._session.get(metadata, resource, params)
- def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationId: str, items: list, **kwargs):
+ def recalculateOrganizationWirelessRadioAutoRfChannels(self, organizationId: str, networkIds: list, **kwargs):
"""
- **Update a zero touch deployment**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-provisioning-deployments
+ **Recalculates automatically assigned channels for every AP within specified the specified network(s)**
+ https://developer.cisco.com/meraki/api-v1/#!recalculate-organization-wireless-radio-auto-rf-channels
- organizationId (string): Organization ID
- - items (array): List of zero touch deployments to create
- - meta (object): Metadata relevant to the paginated dataset
+ - networkIds (array): A list of network ids (limit: 15).
"""
- kwargs.update(locals())
+ kwargs = locals()
metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "updateOrganizationWirelessDevicesProvisioningDeployments",
+ "tags": ["wireless", "configure", "radio", "autoRf", "channels"],
+ "operation": "recalculateOrganizationWirelessRadioAutoRfChannels",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments"
+ resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/recalculate"
body_params = [
- "items",
- "meta",
+ "networkIds",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -4213,55 +10201,47 @@ def updateOrganizationWirelessDevicesProvisioningDeployments(self, organizationI
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessDevicesProvisioningDeployments: ignoring unrecognized kwargs: {invalid}"
+ f"recalculateOrganizationWirelessRadioAutoRfChannels: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
-
- def deleteOrganizationWirelessDevicesProvisioningDeployment(self, organizationId: str, deploymentId: str):
- """
- **Delete a zero touch deployment**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-devices-provisioning-deployment
-
- - organizationId (string): Organization ID
- - deploymentId (string): Deployment ID
- """
-
- metadata = {
- "tags": ["wireless", "configure", "devices", "provisioning", "deployments"],
- "operation": "deleteOrganizationWirelessDevicesProvisioningDeployment",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- deploymentId = urllib.parse.quote(str(deploymentId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/provisioning/deployments/{deploymentId}"
-
- return self._session.delete(metadata, resource)
+ return self._session.post(metadata, resource, payload)
- def getOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ def getOrganizationWirelessRadioOverridesByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Query for details on the organization's RadSec device Certificate Authority certificates (CAs)**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities
+ **Return a list of radio overrides**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-overrides-by-device
- organizationId (string): Organization ID
- - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): A list of network IDs. The returned radio overrides will be filtered to only include these networks.
+ - serials (array): A list of serial numbers. The returned radio overrides will be filtered to only include these serials.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
- "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ "tags": ["wireless", "configure", "radio", "overrides", "byDevice"],
+ "operation": "getOrganizationWirelessRadioOverridesByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+ resource = f"/organizations/{organizationId}/wireless/radio/overrides/byDevice"
query_params = [
- "certificateAuthorityIds",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "serials",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "certificateAuthorityIds",
+ "networkIds",
+ "serials",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4273,88 +10253,132 @@ def getOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizati
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioOverridesByDevice: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get(metadata, resource, params)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def updateOrganizationWirelessDevicesRadsecCertificatesAuthorities(self, organizationId: str, **kwargs):
+ def byOrganizationWirelessRadioRfHealthNeighborsRssiDevice(self, organizationId: str, **kwargs):
"""
- **Update an organization's RadSec device Certificate Authority (CA) state**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-devices-radsec-certificates-authorities
+ **Show the by-device neighbor rssi information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!by-organization-wireless-radio-rf-health-neighbors-rssi-device
- organizationId (string): Organization ID
- - status (string): The "status" to update the Certificate Authority to. Only valid option is "trusted".
- - certificateAuthorityId (string): The ID of the Certificate Authority to update.
+ - networkIds (array): Networks for which information should be gathered.
+ - bands (array): Bands for which information should be gathered. Valid bands are 2.4, 5, and 6.
+ - channels (array): Channel for which information should be gathered.
+ - serials (array): Serial number of the devices for which information should be gathered.
+ - tags (array): Access Point tags for which information should be gathered.
+ - models (array): Access Point models for which information should be gathered.
+ - rfProfiles (array): Rf Profiles for which information should be gathered.
+ - gFloorplanId (string): Geoaligned floorplan ID nodes for which information is gathered belong to.
+ - minimumNeighborRssi (integer): Minimum Neighbor RSSI score for a neighbor entry to be retrieved.
+ - maximumNeighborRssi (integer): Maximum Neighbor RSSI score for a neighbor entry to be retrieved.
+ - minimumRfHealthScore (integer): Minimum RF Health score for an AP to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for an AP to be retrieved.
+ - rfScoreInterval (integer): Size of the rf score interval in seconds.
+ - rfScoreRetryOnEmpty (boolean): If true, the query will be retried further back if no data is present in the latest rf score interval.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
- "operation": "updateOrganizationWirelessDevicesRadsecCertificatesAuthorities",
+ "tags": ["wireless", "configure", "radio", "rfHealth", "neighbors", "rssi"],
+ "operation": "byOrganizationWirelessRadioRfHealthNeighborsRssiDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
+ resource = f"/organizations/{organizationId}/wireless/radio/rfHealth/neighbors/rssi/byDevice"
- body_params = [
- "status",
- "certificateAuthorityId",
+ query_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
+ "gFloorplanId",
+ "minimumNeighborRssi",
+ "maximumNeighborRssi",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ "rfScoreInterval",
+ "rfScoreRetryOnEmpty",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "bands",
+ "channels",
+ "serials",
+ "tags",
+ "models",
+ "rfProfiles",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessDevicesRadsecCertificatesAuthorities: ignoring unrecognized kwargs: {invalid}"
+ f"byOrganizationWirelessRadioRfHealthNeighborsRssiDevice: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
-
- def createOrganizationWirelessDevicesRadsecCertificatesAuthority(self, organizationId: str):
- """
- **Create an organization's RadSec device Certificate Authority (CA)**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-devices-radsec-certificates-authority
-
- - organizationId (string): Organization ID
- """
-
- metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities"],
- "operation": "createOrganizationWirelessDevicesRadsecCertificatesAuthority",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities"
-
- return self._session.post(metadata, resource)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls(self, organizationId: str, **kwargs):
+ def getOrganizationWirelessRadioRfHealthOverviewByNetworkByInterval(self, organizationId: str, **kwargs):
"""
- **Query for certificate revocation list (CRL) for the organization's RadSec device Certificate Authorities (CAs).**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls
+ **Show the by-network RF Health score overview information for the organization in the given interval**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-rf-health-overview-by-network-by-interval
- organizationId (string): Organization ID
- - certificateAuthorityIds (array): Optional parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 182 days, 14 hours, 54 minutes, and 36 seconds from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 30 days, 10 hours, 29 minutes, and 6 seconds after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 30 days, 10 hours, 29 minutes, and 6 seconds. The default is 14 days. If interval is provided, the timespan will be autocalculated.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 7200, 86400. The default is 7200. Interval is calculated if time params are provided.
+ - networkIds (array): Networks for which information should be gathered.
+ - bands (array): Bands for which information should be gathered. Valid bands are 2.4, 5, and 6.
+ - minimumRfHealthScore (integer): Minimum RF Health score for a network to be retrieved.
+ - maximumRfHealthScore (integer): Maximum RF Health score for a network to be retrieved.
+ - minimumHighCciPercentage (integer): Minimum percentage of radios with high CCI for a network to be retrieved.
+ - maximumHighCciPercentage (integer): Maximum percentage of radios with high CCI for a network to be retrieved.
+ - minimumChannelChanges (integer): Minimum number of channel changes for a network to be retrieved.
+ - maximumChannelChanges (integer): Maximum number of channel changes for a network to be retrieved.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls"],
- "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls",
+ "tags": ["wireless", "configure", "radio", "rfHealth", "overview", "byNetwork", "byInterval"],
+ "operation": "getOrganizationWirelessRadioRfHealthOverviewByNetworkByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls"
+ resource = f"/organizations/{organizationId}/wireless/radio/rfHealth/overview/byNetwork/byInterval"
query_params = [
- "certificateAuthorityIds",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
+ "networkIds",
+ "bands",
+ "minimumRfHealthScore",
+ "maximumRfHealthScore",
+ "minimumHighCciPercentage",
+ "maximumHighCciPercentage",
+ "minimumChannelChanges",
+ "maximumChannelChanges",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "certificateAuthorityIds",
+ "networkIds",
+ "bands",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4366,36 +10390,52 @@ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls(self, organi
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrls: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioRfHealthOverviewByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get(metadata, resource, params)
- def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas(self, organizationId: str, **kwargs):
+ def getOrganizationWirelessRadioRrmByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Query for all delta certificate revocation list (CRL) for the organization's RadSec device Certificate Authority (CA) with the given id.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-radsec-certificates-authorities-crls-deltas
+ **List the AutoRF settings of an organization by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-rrm-by-network
- organizationId (string): Organization ID
- - certificateAuthorityIds (array): Parameter to filter CAs by one or more CA IDs. All returned CAs will have an ID that is an exact match.
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): Optional parameter to filter results by network.
+ - startingAfter (string): Retrieving items after this network ID
+ - endingBefore (string): Retrieving items before this network ID
+ - perPage (integer): Number of items per page
+ - sortOrder (string): The sort order of items
"""
kwargs.update(locals())
+ if "sortOrder" in kwargs:
+ options = ["ascending", "descending"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "devices", "radsec", "certificates", "authorities", "crls", "deltas"],
- "operation": "getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas",
+ "tags": ["wireless", "configure", "radio", "rrm", "byNetwork"],
+ "operation": "getOrganizationWirelessRadioRrmByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/radsec/certificates/authorities/crls/deltas"
+ resource = f"/organizations/{organizationId}/wireless/radio/rrm/byNetwork"
query_params = [
- "certificateAuthorityIds",
+ "networkIds",
+ "startingAfter",
+ "endingBefore",
+ "perPage",
+ "sortOrder",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "certificateAuthorityIds",
+ "networkIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4407,47 +10447,31 @@ def getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas(self,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesRadsecCertificatesAuthoritiesCrlsDeltas: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioRrmByNetwork: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get(metadata, resource, params)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessDevicesSystemCpuLoadHistory(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationWirelessRadioStatusByNetwork(self, organizationId: str, **kwargs):
"""
- **Return the CPU Load history for a list of wireless devices in the organization.**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-system-cpu-load-history
+ **Show the status of this organization's radios, categorized by network and device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-status-by-network
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today.
- - t1 (string): The end of the timespan for the data. t1 can be a maximum of 1 day after t0.
- - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 1 day. The default is 1 day.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 20. Default is 10.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter the result set by the included set of network IDs
- - serials (array): Optional parameter to filter device availabilities history by device serial numbers
+ - networkIds (array): Networks for which radio status should be returned.
+ - serials (array): Serials for which radio status should be returned.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "system", "cpu", "load", "history"],
- "operation": "getOrganizationWirelessDevicesSystemCpuLoadHistory",
+ "tags": ["wireless", "configure", "radio", "status", "byNetwork"],
+ "operation": "getOrganizationWirelessRadioStatusByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/system/cpu/load/history"
+ resource = f"/organizations/{organizationId}/wireless/radio/status/byNetwork"
query_params = [
- "t0",
- "t1",
- "timespan",
- "perPage",
- "startingAfter",
- "endingBefore",
"networkIds",
"serials",
]
@@ -4467,52 +10491,66 @@ def getOrganizationWirelessDevicesSystemCpuLoadHistory(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesSystemCpuLoadHistory: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRadioStatusByNetwork: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessDevicesWirelessControllersByDevice(
+ def getOrganizationWirelessRfProfilesAssignmentsByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
"""
- **List of Catalyst access points information**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-devices-wireless-controllers-by-device
+ **List the RF profiles of an organization by device**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-rf-profiles-assignments-by-device
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): Optional parameter to filter access points by network ID. This filter uses multiple exact matches.
- - serials (array): Optional parameter to filter access points by its cloud ID. This filter uses multiple exact matches.
- - controllerSerials (array): Optional parameter to filter access points by its wireless LAN controller cloud ID. This filter uses multiple exact matches.
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter devices by network.
+ - productTypes (array): Optional parameter to filter devices by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
+ - name (string): Optional parameter to filter RF profiles by device name. All returned devices will have a name that contains the search term or is an exact match.
+ - mac (string): Optional parameter to filter RF profiles by device MAC address. All returned devices will have a MAC address that contains the search term or is an exact match.
+ - serial (string): Optional parameter to filter RF profiles by device serial number. All returned devices will have a serial number that contains the search term or is an exact match.
+ - model (string): Optional parameter to filter RF profiles by device model. All returned devices will have a model that contains the search term or is an exact match.
+ - macs (array): Optional parameter to filter RF profiles by one or more device MAC addresses. All returned devices will have a MAC address that is an exact match.
+ - serials (array): Optional parameter to filter RF profiles by one or more device serial numbers. All returned devices will have a serial number that is an exact match.
+ - models (array): Optional parameter to filter RF profiles by one or more device models. All returned devices will have a model that is an exact match.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "monitor", "devices", "wirelessControllers", "byDevice"],
- "operation": "getOrganizationWirelessDevicesWirelessControllersByDevice",
+ "tags": ["wireless", "configure", "rfProfiles", "assignments", "byDevice"],
+ "operation": "getOrganizationWirelessRfProfilesAssignmentsByDevice",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/devices/wirelessControllers/byDevice"
+ resource = f"/organizations/{organizationId}/wireless/rfProfiles/assignments/byDevice"
query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
"networkIds",
+ "productTypes",
+ "name",
+ "mac",
+ "serial",
+ "model",
+ "macs",
"serials",
- "controllerSerials",
- "perPage",
- "startingAfter",
- "endingBefore",
+ "models",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "productTypes",
+ "macs",
"serials",
- "controllerSerials",
+ "models",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4524,39 +10562,39 @@ def getOrganizationWirelessDevicesWirelessControllersByDevice(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessDevicesWirelessControllersByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRfProfilesAssignmentsByDevice: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessLocationScanningByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessRoamingByNetworkByInterval(self, organizationId: str, networkIds: list, **kwargs):
"""
- **Return scanning API settings**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-by-network
+ **Get all wireless clients' roam events within the specified timespan grouped by network and time interval.**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-roaming-by-network-by-interval
- organizationId (string): Organization ID
- - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- - direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
- - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter scanning settings by network ID.
+ - networkIds (array): Filter results by network.
+ - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 14 days from today.
+ - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0.
+ - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 7 days.
+ - interval (integer): The time interval in seconds for returned data. The valid intervals are: 300, 600, 1800, 3600, 7200, 10800, 14400, 18000, 21600, 25200, 28800, 32400, 36000, 39600, 43200, 86400, 604800. The default is 7200.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "byNetwork"],
- "operation": "getOrganizationWirelessLocationScanningByNetwork",
+ "tags": ["wireless", "monitor", "roaming", "byNetwork", "byInterval"],
+ "operation": "getOrganizationWirelessRoamingByNetworkByInterval",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/byNetwork"
+ resource = f"/organizations/{organizationId}/wireless/roaming/byNetwork/byInterval"
query_params = [
- "perPage",
- "startingAfter",
- "endingBefore",
"networkIds",
+ "t0",
+ "t1",
+ "timespan",
+ "interval",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -4573,44 +10611,49 @@ def getOrganizationWirelessLocationScanningByNetwork(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessLocationScanningByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessRoamingByNetworkByInterval: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.get(metadata, resource, params)
- def getOrganizationWirelessLocationScanningReceivers(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Return scanning API receivers**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-location-scanning-receivers
+ **List the L2 isolation allow list MAC entry in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-firewall-isolation-allowlist-entries
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter scanning API receivers by network ID.
+ - networkIds (array): networkIds array to filter out results
+ - ssids (array): ssids number array to filter out results
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "getOrganizationWirelessLocationScanningReceivers",
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
"networkIds",
+ "ssids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "ssids",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4622,41 +10665,39 @@ def getOrganizationWirelessLocationScanningReceivers(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessLocationScanningReceivers: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def createOrganizationWirelessLocationScanningReceiver(
- self, organizationId: str, network: dict, url: str, version: str, radio: dict, sharedSecret: str, **kwargs
+ def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
+ self, organizationId: str, client: dict, ssid: dict, network: dict, **kwargs
):
"""
- **Add new receiver for scanning API**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-location-scanning-receiver
+ **Create isolation allow list MAC entry for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-firewall-isolation-allowlist-entry
- organizationId (string): Organization ID
- - network (object): Add scanning API receiver for network
- - url (string): Receiver Url
- - version (string): Scanning API Version
- - radio (object): Add scanning API Radio
- - sharedSecret (string): Secret Value for Receiver
+ - client (object): The client of allowlist
+ - ssid (object): The SSID that allowlist belongs to
+ - network (object): The Network that allowlist belongs to
+ - description (string): The description of mac address
"""
- kwargs = locals()
+ kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "createOrganizationWirelessLocationScanningReceiver",
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers"
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
body_params = [
+ "description",
+ "client",
+ "ssid",
"network",
- "url",
- "version",
- "radio",
- "sharedSecret",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -4665,37 +10706,54 @@ def createOrganizationWirelessLocationScanningReceiver(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"createOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ f"createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
)
return self._session.post(metadata, resource, payload)
- def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str, **kwargs):
+ def deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str):
"""
- **Change scanning API receiver settings**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-location-scanning-receiver
+ **Destroy isolation allow list MAC entry for this organization**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-firewall-isolation-allowlist-entry
- organizationId (string): Organization ID
- - receiverId (string): Receiver ID
- - url (string): Receiver Url
- - version (string): Scanning API Version
- - radio (object): Add scanning API Radio
+ - entryId (string): Entry ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ entryId = urllib.parse.quote(str(entryId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
+
+ return self._session.delete(metadata, resource)
+
+ def updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str, **kwargs):
+ """
+ **Update isolation allow list MAC entry info**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-firewall-isolation-allowlist-entry
+
+ - organizationId (string): Organization ID
+ - entryId (string): Entry ID
+ - description (string): The description of mac address
+ - client (object): The client of allowlist
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "updateOrganizationWirelessLocationScanningReceiver",
+ "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
+ "operation": "updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- receiverId = urllib.parse.quote(str(receiverId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
+ entryId = urllib.parse.quote(str(entryId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
body_params = [
- "url",
- "version",
- "radio",
+ "description",
+ "client",
]
payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
@@ -4704,58 +10762,41 @@ def updateOrganizationWirelessLocationScanningReceiver(self, organizationId: str
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessLocationScanningReceiver: ignoring unrecognized kwargs: {invalid}"
+ f"updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
)
return self._session.put(metadata, resource, payload)
- def deleteOrganizationWirelessLocationScanningReceiver(self, organizationId: str, receiverId: str):
- """
- **Delete a scanning API receiver**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-location-scanning-receiver
-
- - organizationId (string): Organization ID
- - receiverId (string): Receiver ID
- """
-
- metadata = {
- "tags": ["wireless", "configure", "location", "scanning", "receivers"],
- "operation": "deleteOrganizationWirelessLocationScanningReceiver",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- receiverId = urllib.parse.quote(str(receiverId), safe="")
- resource = f"/organizations/{organizationId}/wireless/location/scanning/receivers/{receiverId}"
-
- return self._session.delete(metadata, resource)
-
- def getOrganizationWirelessMqttSettings(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessSsidsOpenRoamingByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Return MQTT Settings for networks**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-mqtt-settings
+ **Returns an array of objects, each containing SSID OpenRoaming configs for the corresponding network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-open-roaming-by-network
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 250. Default is 50.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter mqtt settings by network ID.
+ - networkIds (array): Optional parameter to filter OpenRoaming configuration by Network Id.
+ - includeDisabledSsids (boolean): Optional parameter to include OpenRoaming configuration for disabled ssids.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "mqtt", "settings"],
- "operation": "getOrganizationWirelessMqttSettings",
+ "tags": ["wireless", "configure", "ssids", "openRoaming", "byNetwork"],
+ "operation": "getOrganizationWirelessSsidsOpenRoamingByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+ resource = f"/organizations/{organizationId}/wireless/ssids/openRoaming/byNetwork"
query_params = [
"perPage",
"startingAfter",
"endingBefore",
"networkIds",
+ "includeDisabledSsids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
@@ -4771,123 +10812,108 @@ def getOrganizationWirelessMqttSettings(self, organizationId: str, total_pages=1
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
- self._session._logger.warning(f"getOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}")
+ self._session._logger.warning(
+ f"getOrganizationWirelessSsidsOpenRoamingByNetwork: ignoring unrecognized kwargs: {invalid}"
+ )
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def updateOrganizationWirelessMqttSettings(self, organizationId: str, network: dict, mqtt: dict, **kwargs):
+ def getOrganizationWirelessSsidsPoliciesClientExclusionBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Add new broker config for wireless MQTT**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-mqtt-settings
+ **Returns an array of objects, each containing client exclusion enablement statuses for one SSID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-policies-client-exclusion-by-ssid
- organizationId (string): Organization ID
- - network (object): Add MQTT Settings for network
- - mqtt (object): MQTT Settings for network
- - ble (object): MQTT BLE Settings for network
- - wifi (object): MQTT Wi-Fi Settings for network
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter by Network ID.
+ - includeDisabledSsids (boolean): Optional parameter to include disabled SSID's.
+ - ssidNumbers (array): Optional parameter to filter by SSID numbers.
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "mqtt", "settings"],
- "operation": "updateOrganizationWirelessMqttSettings",
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "bySsid"],
+ "operation": "getOrganizationWirelessSsidsPoliciesClientExclusionBySsid",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/mqtt/settings"
+ resource = f"/organizations/{organizationId}/wireless/ssids/policies/clientExclusion/bySsid"
- body_params = [
- "network",
- "mqtt",
- "ble",
- "wifi",
+ query_params = [
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ "networkIds",
+ "includeDisabledSsids",
+ "ssidNumbers",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
-
- if self._session._validate_kwargs:
- all_params = [] + body_params
- invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
- if invalid and self._session._logger:
- self._session._logger.warning(
- f"updateOrganizationWirelessMqttSettings: ignoring unrecognized kwargs: {invalid}"
- )
-
- return self._session.put(metadata, resource, payload)
-
- def recalculateOrganizationWirelessRadioAutoRfChannels(self, organizationId: str, networkIds: list, **kwargs):
- """
- **Recalculates automatically assigned channels for every AP within specified the specified network(s)**
- https://developer.cisco.com/meraki/api-v1/#!recalculate-organization-wireless-radio-auto-rf-channels
-
- - organizationId (string): Organization ID
- - networkIds (array): A list of network ids (limit: 15).
- """
-
- kwargs = locals()
-
- metadata = {
- "tags": ["wireless", "configure", "radio", "autoRf", "channels"],
- "operation": "recalculateOrganizationWirelessRadioAutoRfChannels",
- }
- organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/radio/autoRf/channels/recalculate"
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
- body_params = [
+ array_params = [
"networkIds",
+ "ssidNumbers",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"recalculateOrganizationWirelessRadioAutoRfChannels: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsPoliciesClientExclusionBySsid: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.post(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessRadioRrmByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
- """
- **List the AutoRF settings of an organization by network**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-radio-rrm-by-network
+ def getOrganizationWirelessSsidsPoliciesClientExclusionStaticExclusionsBySsid(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **Returns an array of objects, each containing a list of MAC's excluded from a given SSID**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-policies-client-exclusion-static-exclusions-by-ssid
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
- - networkIds (array): Optional parameter to filter results by network.
- - startingAfter (string): Retrieving items after this network ID
- - endingBefore (string): Retrieving items before this network ID
- - perPage (integer): Number of items per page
- - sortOrder (string): The sort order of items
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - networkIds (array): Optional parameter to filter Network ID.
+ - includeDisabledSsids (boolean): Optional parameter to include disabled SSID's.
+ - ssidNumbers (array): Optional parameter to filter by SSID numbers.
"""
kwargs.update(locals())
- if "sortOrder" in kwargs:
- options = ["ascending", "descending"]
- assert kwargs["sortOrder"] in options, (
- f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
- )
-
metadata = {
- "tags": ["wireless", "configure", "radio", "rrm", "byNetwork"],
- "operation": "getOrganizationWirelessRadioRrmByNetwork",
+ "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion", "static", "exclusions", "bySsid"],
+ "operation": "getOrganizationWirelessSsidsPoliciesClientExclusionStaticExclusionsBySsid",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/radio/rrm/byNetwork"
+ resource = f"/organizations/{organizationId}/wireless/ssids/policies/clientExclusion/static/exclusions/bySsid"
query_params = [
- "networkIds",
+ "perPage",
"startingAfter",
"endingBefore",
- "perPage",
- "sortOrder",
+ "networkIds",
+ "includeDisabledSsids",
+ "ssidNumbers",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
+ "ssidNumbers",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4899,66 +10925,61 @@ def getOrganizationWirelessRadioRrmByNetwork(self, organizationId: str, total_pa
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessRadioRrmByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsPoliciesClientExclusionStaticExclusionsBySsid: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessRfProfilesAssignmentsByDevice(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationWirelessSsidsProfiles(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **List the RF profiles of an organization by device**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-rf-profiles-assignments-by-device
+ **Returns the SSID profiles for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
+ - name (string): (Optional) Filter results by name. Case insensitive substring match.
+ - sortBy (string): Column to sort results by. Default is `name`.
+ - sortOrder (string): Direction to sort results by. Default is `asc`.
+ - profileIds (array): (Optional) Filter results by a list of SSID profile IDs.
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter devices by network.
- - productTypes (array): Optional parameter to filter devices by product type. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, sensor, wirelessController, campusGateway, and secureConnect.
- - name (string): Optional parameter to filter RF profiles by device name. All returned devices will have a name that contains the search term or is an exact match.
- - mac (string): Optional parameter to filter RF profiles by device MAC address. All returned devices will have a MAC address that contains the search term or is an exact match.
- - serial (string): Optional parameter to filter RF profiles by device serial number. All returned devices will have a serial number that contains the search term or is an exact match.
- - model (string): Optional parameter to filter RF profiles by device model. All returned devices will have a model that contains the search term or is an exact match.
- - macs (array): Optional parameter to filter RF profiles by one or more device MAC addresses. All returned devices will have a MAC address that is an exact match.
- - serials (array): Optional parameter to filter RF profiles by one or more device serial numbers. All returned devices will have a serial number that is an exact match.
- - models (array): Optional parameter to filter RF profiles by one or more device models. All returned devices will have a model that is an exact match.
"""
kwargs.update(locals())
+ if "sortBy" in kwargs:
+ options = ["name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "rfProfiles", "assignments", "byDevice"],
- "operation": "getOrganizationWirelessRfProfilesAssignmentsByDevice",
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "getOrganizationWirelessSsidsProfiles",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/rfProfiles/assignments/byDevice"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles"
query_params = [
+ "name",
+ "sortBy",
+ "sortOrder",
+ "profileIds",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "productTypes",
- "name",
- "mac",
- "serial",
- "model",
- "macs",
- "serials",
- "models",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "networkIds",
- "productTypes",
- "macs",
- "serials",
- "models",
+ "profileIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -4968,51 +10989,87 @@ def getOrganizationWirelessRfProfilesAssignmentsByDevice(
if self._session._validate_kwargs:
all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(f"getOrganizationWirelessSsidsProfiles: ignoring unrecognized kwargs: {invalid}")
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def createOrganizationWirelessSsidsProfile(self, organizationId: str, name: str, ssid: dict, **kwargs):
+ """
+ **Create a new SSID profile in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - name (string): Name of the SSID profile
+ - ssid (object): SSID configuration for the profile
+ - precedence (object): Precedence configuration for the SSID profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "createOrganizationWirelessSsidsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles"
+
+ body_params = [
+ "name",
+ "precedence",
+ "ssid",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessRfProfilesAssignmentsByDevice: ignoring unrecognized kwargs: {invalid}"
+ f"createOrganizationWirelessSsidsProfile: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ return self._session.post(metadata, resource, payload)
- def getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries(
- self, organizationId: str, total_pages=1, direction="next", **kwargs
- ):
+ def getOrganizationWirelessSsidsProfilesAssignments(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **List the L2 isolation allow list MAC entry in an organization**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-firewall-isolation-allowlist-entries
+ **List the SSID profile assignments in an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles-assignments
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): The network IDs to include in the result set.
+ - ssidIds (array): The SSID IDs to include in the result set.
+ - profileIds (array): The SSID profile IDs to include in the result set.
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): networkIds array to filter out results
- - ssids (array): ssids number array to filter out results
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments"],
+ "operation": "getOrganizationWirelessSsidsProfilesAssignments",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
query_params = [
+ "networkIds",
+ "ssidIds",
+ "profileIds",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "ssids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
"networkIds",
- "ssids",
+ "ssidIds",
+ "profileIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -5024,37 +11081,33 @@ def getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessSsidsFirewallIsolationAllowlistEntries: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsProfilesAssignments: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
- self, organizationId: str, client: dict, ssid: dict, network: dict, **kwargs
- ):
+ def createOrganizationWirelessSsidsProfilesAssignment(self, organizationId: str, profile: dict, ssid: dict, **kwargs):
"""
- **Create isolation allow list MAC entry for this organization**
- https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-firewall-isolation-allowlist-entry
+ **Assigns an SSID profile to an SSID in the organization**
+ https://developer.cisco.com/meraki/api-v1/#!create-organization-wireless-ssids-profiles-assignment
- organizationId (string): Organization ID
- - client (object): The client of allowlist
- - ssid (object): The SSID that allowlist belongs to
- - network (object): The Network that allowlist belongs to
- - description (string): The description of mac address
+ - profile (object): SSID profile to assign
+ - ssid (object): SSID to assign the SSID profile to
+ - network (object): Network containing the SSID (required if SSID number is used)
"""
kwargs.update(locals())
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments"],
+ "operation": "createOrganizationWirelessSsidsProfilesAssignment",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
body_params = [
- "description",
- "client",
+ "profile",
"ssid",
"network",
]
@@ -5065,102 +11118,161 @@ def createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"createOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
+ f"createOrganizationWirelessSsidsProfilesAssignment: ignoring unrecognized kwargs: {invalid}"
)
return self._session.post(metadata, resource, payload)
- def deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str):
+ def deleteOrganizationWirelessSsidsProfilesAssignments(self, organizationId: str, ssid: dict, **kwargs):
"""
- **Destroy isolation allow list MAC entry for this organization**
- https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-firewall-isolation-allowlist-entry
+ **Unassigns the SSID profile assigned to an SSID**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-profiles-assignments
- organizationId (string): Organization ID
- - entryId (string): Entry ID
+ - ssid (object): SSID to delete the SSID profile assignment of
+ - network (object): Network containing the SSID (required if SSID number is used)
"""
+ kwargs.update(locals())
+
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "deleteOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments"],
+ "operation": "deleteOrganizationWirelessSsidsProfilesAssignments",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- entryId = urllib.parse.quote(str(entryId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments"
return self._session.delete(metadata, resource)
- def updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry(self, organizationId: str, entryId: str, **kwargs):
+ def getOrganizationWirelessSsidsProfilesAssignmentsByNetwork(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
"""
- **Update isolation allow list MAC entry info**
- https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-firewall-isolation-allowlist-entry
+ **List the SSID profile assignments in an organization, grouped by network**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles-assignments-by-network
- organizationId (string): Organization ID
- - entryId (string): Entry ID
- - description (string): The description of mac address
- - client (object): The client of allowlist
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - networkIds (array): The network IDs to include in the result set.
+ - profileIds (array): The SSID profile IDs to include in the result set.
+ - networkGroupIds (array): The network group IDs to include in the result set.
+ - includeAllNetworks (boolean): When set to true, include all networks in the organization, even those without any SSID profile assignments. Defaults to false.
+ - excludeProfileIds (array): The SSID profile IDs to exclude from the result set.
+ - sortBy (string): Optional parameter to specify the field used to sort results. (default: network)
+ - sortOrder (string): Optional parameter to specify the sort order. Default value is asc.
+ - search (string): Optional parameter to search on network name or network group name.
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
"""
kwargs.update(locals())
+ if "sortBy" in kwargs:
+ options = ["group", "network"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "ssids", "firewall", "isolation", "allowlist", "entries"],
- "operation": "updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry",
+ "tags": ["wireless", "configure", "ssids", "profiles", "assignments", "byNetwork"],
+ "operation": "getOrganizationWirelessSsidsProfilesAssignmentsByNetwork",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- entryId = urllib.parse.quote(str(entryId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/firewall/isolation/allowlist/entries/{entryId}"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/assignments/byNetwork"
- body_params = [
- "description",
- "client",
+ query_params = [
+ "networkIds",
+ "profileIds",
+ "networkGroupIds",
+ "includeAllNetworks",
+ "excludeProfileIds",
+ "sortBy",
+ "sortOrder",
+ "search",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
]
- payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "networkIds",
+ "profileIds",
+ "networkGroupIds",
+ "excludeProfileIds",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
if self._session._validate_kwargs:
- all_params = [] + body_params
+ all_params = query_params + array_params
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"updateOrganizationWirelessSsidsFirewallIsolationAllowlistEntry: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsProfilesAssignmentsByNetwork: ignoring unrecognized kwargs: {invalid}"
)
- return self._session.put(metadata, resource, payload)
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
- def getOrganizationWirelessSsidsOpenRoamingByNetwork(self, organizationId: str, total_pages=1, direction="next", **kwargs):
+ def getOrganizationWirelessSsidsProfilesOverviews(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
- **Returns an array of objects, each containing SSID OpenRoaming configs for the corresponding network**
- https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-open-roaming-by-network
+ **Returns the SSID profiles' overview information for an organization**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-ssids-profiles-overviews
- organizationId (string): Organization ID
- total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
- direction (string): direction to paginate, either "next" (default) or "prev" page
+ - name (string): (Optional) Filter results by name. Case insensitive substring match.
+ - sortBy (string): Column to sort results by. Default is `name`.
+ - sortOrder (string): Direction to sort results by. Default is `asc`.
+ - profileIds (array): (Optional) Filter results by a list of SSID profile IDs.
- perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000.
- startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
- - networkIds (array): Optional parameter to filter OpenRoaming configuration by Network Id.
- - includeDisabledSsids (boolean): Optional parameter to include OpenRoaming configuration for disabled ssids.
"""
kwargs.update(locals())
+ if "sortBy" in kwargs:
+ options = ["name"]
+ assert kwargs["sortBy"] in options, (
+ f'''"sortBy" cannot be "{kwargs["sortBy"]}", & must be set to one of: {options}'''
+ )
+ if "sortOrder" in kwargs:
+ options = ["asc", "desc"]
+ assert kwargs["sortOrder"] in options, (
+ f'''"sortOrder" cannot be "{kwargs["sortOrder"]}", & must be set to one of: {options}'''
+ )
+
metadata = {
- "tags": ["wireless", "configure", "ssids", "openRoaming", "byNetwork"],
- "operation": "getOrganizationWirelessSsidsOpenRoamingByNetwork",
+ "tags": ["wireless", "configure", "ssids", "profiles", "overviews"],
+ "operation": "getOrganizationWirelessSsidsProfilesOverviews",
}
organizationId = urllib.parse.quote(str(organizationId), safe="")
- resource = f"/organizations/{organizationId}/wireless/ssids/openRoaming/byNetwork"
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/overviews"
query_params = [
+ "name",
+ "sortBy",
+ "sortOrder",
+ "profileIds",
"perPage",
"startingAfter",
"endingBefore",
- "networkIds",
- "includeDisabledSsids",
]
params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
array_params = [
- "networkIds",
+ "profileIds",
]
for k, v in kwargs.items():
if k.strip() in array_params:
@@ -5172,11 +11284,67 @@ def getOrganizationWirelessSsidsOpenRoamingByNetwork(self, organizationId: str,
invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
if invalid and self._session._logger:
self._session._logger.warning(
- f"getOrganizationWirelessSsidsOpenRoamingByNetwork: ignoring unrecognized kwargs: {invalid}"
+ f"getOrganizationWirelessSsidsProfilesOverviews: ignoring unrecognized kwargs: {invalid}"
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def updateOrganizationWirelessSsidsProfile(self, organizationId: str, id: str, **kwargs):
+ """
+ **Update this SSID profile**
+ https://developer.cisco.com/meraki/api-v1/#!update-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ - name (string): Name of the SSID profile
+ - ssid (object): SSID configuration for the profile
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "updateOrganizationWirelessSsidsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/{id}"
+
+ body_params = [
+ "name",
+ "ssid",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"updateOrganizationWirelessSsidsProfile: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.put(metadata, resource, payload)
+
+ def deleteOrganizationWirelessSsidsProfile(self, organizationId: str, id: str):
+ """
+ **Delete an SSID profile**
+ https://developer.cisco.com/meraki/api-v1/#!delete-organization-wireless-ssids-profile
+
+ - organizationId (string): Organization ID
+ - id (string): ID
+ """
+
+ metadata = {
+ "tags": ["wireless", "configure", "ssids", "profiles"],
+ "operation": "deleteOrganizationWirelessSsidsProfile",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ id = urllib.parse.quote(str(id), safe="")
+ resource = f"/organizations/{organizationId}/wireless/ssids/profiles/{id}"
+
+ return self._session.delete(metadata, resource)
+
def getOrganizationWirelessSsidsStatusesByDevice(self, organizationId: str, total_pages=1, direction="next", **kwargs):
"""
**List status information of all BSSIDs in your organization**
diff --git a/meraki/api/wirelessController.py b/meraki/api/wirelessController.py
index 23510e42..3ba7fa19 100644
--- a/meraki/api/wirelessController.py
+++ b/meraki/api/wirelessController.py
@@ -177,6 +177,59 @@ def getOrganizationWirelessControllerConnections(self, organizationId: str, tota
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+ def getOrganizationWirelessControllerConnectionsUnassigned(
+ self, organizationId: str, total_pages=1, direction="next", **kwargs
+ ):
+ """
+ **List of unassigned Catalyst access points and summary information**
+ https://developer.cisco.com/meraki/api-v1/#!get-organization-wireless-controller-connections-unassigned
+
+ - organizationId (string): Organization ID
+ - total_pages (integer or string): use with perPage to get total results up to total_pages*perPage; -1 or "all" for all pages
+ - direction (string): direction to paginate, either "next" (default) or "prev" page
+ - controllerSerials (array): Optional parameter to filter access points by wireless LAN controller cloud ID. This filter uses multiple exact matches.
+ - supported (boolean): Optional parameter to filter access points based on if they are supported for dashboard monitoring. Values can be true/false, if not provided then all unassigned APs will be returned
+ - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100.
+ - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it.
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wirelessController", "configure", "connections", "unassigned"],
+ "operation": "getOrganizationWirelessControllerConnectionsUnassigned",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wirelessController/connections/unassigned"
+
+ query_params = [
+ "controllerSerials",
+ "supported",
+ "perPage",
+ "startingAfter",
+ "endingBefore",
+ ]
+ params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params}
+
+ array_params = [
+ "controllerSerials",
+ ]
+ for k, v in kwargs.items():
+ if k.strip() in array_params:
+ params[f"{k.strip()}[]"] = kwargs[f"{k}"]
+ params.pop(k.strip())
+
+ if self._session._validate_kwargs:
+ all_params = query_params + array_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"getOrganizationWirelessControllerConnectionsUnassigned: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
def getOrganizationWirelessControllerDevicesInterfacesL2ByDevice(
self, organizationId: str, total_pages=1, direction="next", **kwargs
):
@@ -861,3 +914,36 @@ def getOrganizationWirelessControllerOverviewByDevice(
)
return self._session.get_pages(metadata, resource, params, total_pages, direction)
+
+ def generateOrganizationWirelessControllerRegulatoryDomainPackage(self, organizationId: str, **kwargs):
+ """
+ **Generate the regulatory domain package**
+ https://developer.cisco.com/meraki/api-v1/#!generate-organization-wireless-controller-regulatory-domain-package
+
+ - organizationId (string): Organization ID
+ - networkIds (array): A list of network IDs to filter by
+ """
+
+ kwargs.update(locals())
+
+ metadata = {
+ "tags": ["wirelessController", "configure", "regulatoryDomain", "package"],
+ "operation": "generateOrganizationWirelessControllerRegulatoryDomainPackage",
+ }
+ organizationId = urllib.parse.quote(str(organizationId), safe="")
+ resource = f"/organizations/{organizationId}/wirelessController/regulatoryDomain/package/generate"
+
+ body_params = [
+ "networkIds",
+ ]
+ payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
+
+ if self._session._validate_kwargs:
+ all_params = [] + body_params
+ invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"]
+ if invalid and self._session._logger:
+ self._session._logger.warning(
+ f"generateOrganizationWirelessControllerRegulatoryDomainPackage: ignoring unrecognized kwargs: {invalid}"
+ )
+
+ return self._session.post(metadata, resource, payload)
diff --git a/meraki/common.py b/meraki/common.py
index 80c4e366..207ea5f3 100644
--- a/meraki/common.py
+++ b/meraki/common.py
@@ -51,6 +51,17 @@ def validate_user_agent(be_geo_id, caller):
return caller_string
+def validate_meraki_app_value(argument, value):
+ # Meraki app ID / bearer token must fit within a 127-character header value
+ if value and len(str(value)) > 127:
+ raise SessionInputError(
+ argument,
+ value,
+ f"{argument} must be 127 characters or fewer (got {len(str(value))}).",
+ None,
+ )
+
+
def reject_v0_base_url(self):
if "v0" in self._base_url:
sys.exit(
@@ -83,7 +94,10 @@ def validate_base_url(self, url):
"gov-meraki.com",
]
parsed_url = urllib.parse.urlparse(url)
- if any(domain in parsed_url.netloc for domain in allowed_domains):
+ # Match on the host boundary to avoid lookalike-host SSRF (e.g.
+ # "api.meraki.com.attacker.net"). Lowercase and strip any port first.
+ host = parsed_url.netloc.lower().split(":")[0]
+ if any(host == domain or host.endswith("." + domain) for domain in allowed_domains):
abs_url = url
else:
abs_url = self._base_url + url
diff --git a/meraki/config.py b/meraki/config.py
index 0dc893ac..3bf90ad6 100644
--- a/meraki/config.py
+++ b/meraki/config.py
@@ -1,17 +1,32 @@
-# Package Constants
+from pathlib import Path
+
+# =============================================================================
+# CONNECTION & AUTH
+# =============================================================================
+
+# --- API Key ---
# Meraki dashboard API key, set either at instantiation or as an environment variable
API_KEY_ENVIRONMENT_VARIABLE = "MERAKI_DASHBOARD_API_KEY"
+# --- Meraki App ---
+# Meraki app ID, set either at instantiation or as an environment variable
+MERAKI_APP_ID = ""
+
+# Meraki app bearer token, set either at instantiation or as an environment variable
+MERAKI_APP_BEARER_TOKEN = ""
+
+# --- Base URL ---
# Base URL preceding all endpoint resources
DEFAULT_BASE_URL = "https://api.meraki.com/api/v1"
-# Alternate base URLs
+# Regional base URLs
CANADA_BASE_URL = "https://api.meraki.ca/api/v1"
CHINA_BASE_URL = "https://api.meraki.cn/api/v1"
INDIA_BASE_URL = "https://api.meraki.in/api/v1"
UNITED_STATES_FED_BASE_URL = "https://api.gov-meraki.com/api/v1"
+# --- Transport ---
# Maximum number of seconds for each API call
SINGLE_REQUEST_TIMEOUT = 60
@@ -21,10 +36,105 @@
# Proxy server and port, if needed, for HTTPS
REQUESTS_PROXY = ""
+
+# =============================================================================
+# IDENTITY & ATTESTATION
+# =============================================================================
+
+# --- SDK Caller ---
+# Optional identifier for API usage tracking; can also be set as an environment variable MERAKI_PYTHON_SDK_CALLER
+# It's good practice to use this to identify your application using the format:
+# CamelCasedApplicationName/OptionalVersionNumber CamelCasedVendorName
+# Please note:
+# 1. Application name precedes vendor name in all cases.
+# 2. If your application or vendor name normally contains spaces or special casing, you should omit them in favor of
+# normal CamelCasing here.
+# 3. The slash and version number are optional. Leave both out if you like.
+# 4. The slash is a forward slash, '/' -- not a backslash.
+# 5. Don't use the 'Meraki' or 'Cisco' names in your application name here. Maybe in general? I'm a config file, not a
+# lawyer.
+# Example 1: if your application is named 'Mambo', version number is 5.0, and your vendor/company name is Vega, then
+# you would use, at minimum: 'Mambo Vega'. Optionally: 'Mambo/5.0 Vega'.
+# Example 2: if your application is named 'Sunshine Rainbows', and company name is 'hunter2 for Life', and if you
+# don't want to report version number, then you would use, at minimum: 'SunshineRainbows hunter2ForLife'
+# The choice is yours as long as you follow the format. You should **not** include other information in this string.
+# If you are an official ecosystem partner, this is required.
+# For more guidance, please refer to https://developer.cisco.com/meraki/api-v1/user-agents-overview/
+MERAKI_PYTHON_SDK_CALLER = ""
+
+# --- Legacy ---
+# Legacy partner identifier for API usage tracking; can also be set as an environment variable BE_GEO_ID
+# This is no longer used. Please use MERAKI_PYTHON_SDK_CALLER instead.
+BE_GEO_ID = ""
+
+
+# =============================================================================
+# REQUEST HANDLING
+# =============================================================================
+
+# --- Concurrency ---
+# Maximum concurrent connections for the async HTTP client (httpx.Limits(max_connections=N)).
+# This is a local resource constraint (open sockets), NOT a rate limit. It controls how many
+# requests can be in-flight simultaneously. For rate limiting, see Smart Limiting below.
+AIO_MAXIMUM_CONCURRENT_REQUESTS = 90
+
+# --- Smart Limiting ---
+# Proactive per-org rate limiting via token buckets. Unlike AIO_MAXIMUM_CONCURRENT_REQUESTS
+# (which caps how many requests are in-flight at once), smart limiting caps how many requests
+# per second are sent to each organization, preventing 429s before they happen.
+# The SDK parses request URLs to determine which org a request targets, using a cache of
+# network -> org and device serial -> org mappings gathered via getOrganizationInventoryDevices()
+# and getOrganizationNetworks().
+
+# Enable per-org rate limiting? When False, the SDK relies solely on 429 retry logic.
+# If you disable this feature, you will produce more 429 errors, which in turn wastes API budget
+# and unnecessarily interferes with other applications interacting with your organization(s).
+SMART_FLOW_ENABLED = True
+
+# Maximum requests per second per organization. Meraki's default org-level limit is 10 req/s.
+# The default setting is 9, which helps reserve a minimum budget for other applications. You
+# can further reduce this if you are working in an organization with lots of other applications.
+SMART_FLOW_ORG_RATE = 9
+
+# Maximum requests per second across all organizations (source IP limit).
+# Meraki enforces a global 100 req/s limit per source IP, independent of per-org limits.
+# All requests deduct from this budget; per-org buckets provide additional throttling.
+SMART_FLOW_GLOBAL_RATE = 100
+
+# Path to the rate limit mapping cache file. The cache persists network -> org and
+# serial -> org mappings across sessions so subsequent runs skip the eager load API calls
+# if the cache is fresh. Set to empty string to disable persistence.
+# Default: ~/.meraki/.cache/rate_limit_cache.json (platform-agnostic)
+SMART_FLOW_CACHE_PATH = str(Path.home() / ".meraki" / ".cache" / "rate_limit_cache.json")
+
+# How long (in seconds) before the disk cache is considered stale and re-fetched.
+# Default is 604800 (7 days). Set to None to never expire.
+# Organizations with frequent cross-org device or network movement may consider
+# reducing this value to better match their real-world use and improve the effectiveness.
+SMART_FLOW_CACHE_TTL = 604800.0
+
+# How org/network/device mappings are loaded. Options: "lazy", "eager".
+# "lazy" (default): mappings are collected passively as API calls are made.
+# "eager": all mappings are fetched at session init via getOrganizations().
+# Costs more API calls at startup for large deployments, but reduces cache misses during operation.
+# You may notice a brief delay as the cache is created, which indicates either
+# that your environment did not previously have a cache, or the previous cache had expired.
+SMART_FLOW_CACHE_MODE = "lazy"
+
+# Log smart flow activity (bucket creation, rate adjustments, learned mappings, cache events)
+# to the standard session log. Disable this if you don't want to see smart_flow log messages
+# in your logs.
+SMART_FLOW_LOGGING = True
+
+
+# --- Retry Behavior ---
# Retry if 429 rate limit error encountered?
# Please note, setting to False means your application will not retry upon a 429. Not intended for production apps.
WAIT_ON_RATE_LIMIT = True
+# Retry up to this many times when encountering 429s or other server-side errors
+MAXIMUM_RETRIES = 5
+
# Nginx 429 retry wait time
NGINX_429_RETRY_WAIT_TIME = 60
@@ -40,9 +150,16 @@
# Other 4XX error retry wait time
RETRY_4XX_ERROR_WAIT_TIME = 60
-# Retry up to this many times when encountering 429s or other server-side errors
-MAXIMUM_RETRIES = 2
+# --- Pagination ---
+# Use iterator for pages. May offer improved performance in some instances.
+USE_ITERATOR_FOR_GET_PAGES = False
+
+# =============================================================================
+# LOGGING & OBSERVABILITY
+# =============================================================================
+
+# --- File Logging ---
# Create an output log file?
OUTPUT_LOG = True
@@ -52,9 +169,11 @@
# Log file name appended with date and timestamp
LOG_FILE_PREFIX = "meraki_api_"
+# --- Console ---
# Print output logging to console?
PRINT_TO_CONSOLE = True
+# --- Control ---
# Disable all logging? You're on your own then!
SUPPRESS_LOGGING = False
@@ -62,38 +181,15 @@
# library's default logging handlers, formatters etc.--instead, you can inherit an external logger instance.
INHERIT_LOGGING_CONFIG = False
-# Use iterator for pages. May offer improved performance in some instances. Off by default for backwards compatibility.
-USE_ITERATOR_FOR_GET_PAGES = False
+# =============================================================================
+# DEVELOPMENT
+# =============================================================================
+
+# --- Simulation ---
# Simulate POST/PUT/DELETE calls to prevent changes?
SIMULATE_API_CALLS = False
-# Number of concurrent API requests for asynchronous class
-AIO_MAXIMUM_CONCURRENT_REQUESTS = 8
-
-# Legacy partner identifier for API usage tracking; can also be set as an environment variable BE_GEO_ID
-# This is no longer used. Please use MERAKI_PYTHON_SDK_CALLER instead.
-BE_GEO_ID = ""
-
-# Optional identifier for API usage tracking; can also be set as an environment variable MERAKI_PYTHON_SDK_CALLER
-# It's good practice to use this to identify your application using the format:
-# CamelCasedApplicationName/OptionalVersionNumber CamelCasedVendorName
-# Please note:
-# 1. Application name precedes vendor name in all cases.
-# 2. If your application or vendor name normally contains spaces or special casing, you should omit them in favor of
-# normal CamelCasing here.
-# 3. The slash and version number are optional. Leave both out if you like.
-# 4. The slash is a forward slash, '/' -- not a backslash.
-# 5. Don't use the 'Meraki' or 'Cisco' names in your application name here. Maybe in general? I'm a config file, not a
-# lawyer.
-# Example 1: if your application is named 'Mambo', version number is 5.0, and your vendor/company name is Vega, then
-# you would use, at minimum: 'Mambo Vega'. Optionally: 'Mambo/5.0 Vega'.
-# Example 2: if your application is named 'Sunshine Rainbows', and company name is 'hunter2 for Life', and if you
-# don't want to report version number, then you would use, at minimum: 'SunshineRainbows hunter2ForLife'
-# The choice is yours as long as you follow the format. You should **not** include other information in this string.
-# If you are an official ecosystem partner, this is required.
-# For more guidance, please refer to https://developer.cisco.com/meraki/api-v1/user-agents-overview/
-MERAKI_PYTHON_SDK_CALLER = ""
-
+# --- Validation ---
# Log a warning when unrecognized kwargs are passed to API methods?
VALIDATE_KWARGS = False
diff --git a/meraki/encoding.py b/meraki/encoding.py
new file mode 100644
index 00000000..13a376e1
--- /dev/null
+++ b/meraki/encoding.py
@@ -0,0 +1,70 @@
+"""Meraki-specific parameter encoding using only stdlib.
+
+This module provides encode_meraki_params(), a pure function replacement for
+the monkey-patched requests._encode_params in rest_session.py. Uses only
+urllib.parse (no requests dependency). See HTTP-04.
+"""
+
+from urllib.parse import urlencode
+
+
+def encode_meraki_params(data):
+ """Encode parameters for Meraki API requests.
+
+ Supports:
+ - str/bytes: passthrough
+ - file-like (has .read): passthrough
+ - dict: URL encode with array-of-objects support
+ - list of 2-tuples: URL encode with array-of-objects support
+ - other: passthrough
+
+ Array-of-objects encoding (Meraki-specific):
+ {"param[]": [{"key1": "val1"}]} -> "param%5B%5Dkey1=val1"
+
+ Args:
+ data: Parameters to encode. Dict, list of tuples, str, bytes,
+ file-like object, or any other type (passthrough).
+
+ Returns:
+ URL-encoded string for dict/list inputs, original value for passthrough types.
+ """
+ if isinstance(data, (str, bytes)):
+ return data
+ elif hasattr(data, "read"):
+ return data
+ elif hasattr(data, "__iter__"):
+ result = []
+
+ # Convert to key-val list (stdlib replacement for requests.utils.to_key_val_list)
+ if hasattr(data, "items"):
+ items = list(data.items())
+ else:
+ items = list(data)
+
+ for k, vs in items:
+ # Normalize scalar to list
+ if isinstance(vs, str) or not hasattr(vs, "__iter__"):
+ vs = [vs]
+
+ for v in vs:
+ if v is not None and not isinstance(v, dict):
+ # Simple key-value pair
+ result.append(
+ (
+ k.encode("utf-8") if isinstance(k, str) else k,
+ v.encode("utf-8") if isinstance(v, str) else v,
+ )
+ )
+ elif v is not None:
+ # Array-of-objects: concatenate dict keys to param name
+ for k_inner, v_inner in v.items():
+ result.append(
+ (
+ (k + k_inner).encode("utf-8") if isinstance(k, str) else k_inner,
+ v_inner.encode("utf-8") if isinstance(v_inner, str) else v_inner,
+ )
+ )
+
+ return urlencode(result, doseq=True)
+ else:
+ return data
diff --git a/meraki/exceptions.py b/meraki/exceptions.py
index 3b2a3cce..84a5b824 100644
--- a/meraki/exceptions.py
+++ b/meraki/exceptions.py
@@ -39,7 +39,9 @@ def __init__(self, metadata, response):
self.tag = metadata["tags"][0]
self.operation = metadata["operation"]
self.status = self.response.status_code if self.response is not None and self.response.status_code else None
- self.reason = self.response.reason if self.response is not None and self.response.reason else None
+ self.reason = (
+ self.response.reason_phrase if self.response is not None and hasattr(self.response, "reason_phrase") else None
+ )
try:
self.message = self.response.json() if self.response is not None and self.response.json() else None
except ValueError:
@@ -53,20 +55,41 @@ def __repr__(self):
# To catch exceptions while making AIO API calls
-class AsyncAPIError(Exception):
- def __init__(self, metadata, response, message):
- self.response = response
- self.tag = metadata["tags"][0]
- self.operation = metadata["operation"]
- self.status = response.status if response is not None and response.status else None
- self.reason = response.reason if response is not None and response.reason else None
- self.message = message
- if isinstance(self.message, str):
- self.message = self.message.strip()
- if self.status == 404 and self.reason == "Not Found":
- self.message += "please wait a minute if the key or org was just newly created."
+class AsyncAPIError(APIError):
+ """Deprecated: Use APIError for both sync and async exceptions.
+
+ This exception is deprecated as of version 4.0. Catch APIError instead,
+ which now handles both synchronous and asynchronous errors.
+
+ Existing code using ``except AsyncAPIError:`` will continue to work
+ because AsyncAPIError is now a subclass of APIError.
+ """
+
+ def __init__(self, metadata, response, message=None):
+ import warnings
+
+ warnings.warn(
+ "AsyncAPIError is deprecated. Catch APIError instead, which now handles both sync and async errors.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
- super().__init__(f"{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}")
+ if message is not None:
+ # Old 3-arg form: replicate original AsyncAPIError logic
+ self.response = response
+ self.tag = metadata["tags"][0]
+ self.operation = metadata["operation"]
+ self.status = response.status_code if response is not None and hasattr(response, "status_code") else None
+ self.reason = response.reason_phrase if response is not None and hasattr(response, "reason_phrase") else None
+ self.message = message
+ if isinstance(self.message, str):
+ self.message = self.message.strip()
+ if self.status == 404 and self.reason == "Not Found":
+ self.message += "please wait a minute if the key or org was just newly created."
+ Exception.__init__(self, f"{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}")
+ else:
+ # New 2-arg form: delegate to APIError
+ super().__init__(metadata, response)
def __repr__(self):
return f"{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}"
diff --git a/meraki/rest_session.py b/meraki/rest_session.py
deleted file mode 100644
index 0832410e..00000000
--- a/meraki/rest_session.py
+++ /dev/null
@@ -1,613 +0,0 @@
-import random
-import urllib.parse
-from datetime import datetime, timezone
-import json
-import time
-
-import requests
-from requests.utils import to_key_val_list
-from requests.compat import basestring, urlencode
-
-from meraki._version import __version__
-from meraki.common import (
- check_python_version,
- iterator_for_get_pages_bool,
- reject_v0_base_url,
- use_iterator_for_get_pages_setter,
- validate_base_url,
- validate_user_agent,
-)
-from meraki.config import (
- ACTION_BATCH_RETRY_WAIT_TIME,
- BE_GEO_ID,
- CERTIFICATE_PATH,
- DEFAULT_BASE_URL,
- MAXIMUM_RETRIES,
- MERAKI_PYTHON_SDK_CALLER,
- NETWORK_DELETE_RETRY_WAIT_TIME,
- NGINX_429_RETRY_WAIT_TIME,
- REQUESTS_PROXY,
- RETRY_4XX_ERROR,
- RETRY_4XX_ERROR_WAIT_TIME,
- SIMULATE_API_CALLS,
- SINGLE_REQUEST_TIMEOUT,
- USE_ITERATOR_FOR_GET_PAGES,
- WAIT_ON_RATE_LIMIT,
-)
-from meraki.exceptions import APIError, APIResponseError, SessionInputError
-from meraki.response_handler import handle_3xx
-
-
-def encode_params(_, data):
- """Encode parameters in a piece of data.
-
- Will successfully encode parameters when passed as a dict or a list of
- 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
- if parameters are supplied as a dict.
-
- MERAKI OVERRIDE:
- By default, when parameters are supplied as a dict, only the object keys
- are encoded.
-
- Ex. {"param": [{"key_1":"value_1"}, {"key_2":"value_2"}]} => ?param[]=key_1¶m[]=key_2
-
- Now when parameters are supplied as a dict, dict keys will be appended to
- parameter names. This adds support for the "array of objects" query parameter type.
-
- Ex. {"param": [{"key_1":"value_1"}, {"key_2":"value_2"}]} => ?param[]key_1=value_1¶m[]key_2=value_2
- """
- if isinstance(data, (str, bytes)):
- return data
- elif hasattr(data, "read"):
- return data
- elif hasattr(data, "__iter__"):
- result = []
- # Get each query parameter key value pair
- for k, vs in to_key_val_list(data):
- """
- Turn value into list/iterable if it is not already.
- Ex. {"param": "value"} => {"param": ["value"]}
- """
- if isinstance(vs, basestring) or not hasattr(vs, "__iter__"):
- vs = [vs]
- for v in vs:
- # List params
- if v is not None and not isinstance(v, dict):
- """
- Add a query parameter key-value pair for each value to the list of results.
- Ex. {"param": ["value_1", "value_2"]} => [(param, value_1), (param, value_2)]
- """
- result.append(
- (
- k.encode("utf-8") if isinstance(k, str) else k,
- v.encode("utf-8") if isinstance(v, str) else v,
- )
- )
- # Dict params
- else:
- """
- Append each dict key to the parameter name.
- Add a query parameter key-value pair for each value to the list of results.
- {"param": [{"key_1": "value_1"}, {"key_2": "value_2"}]} => [(param + key_1, value1), (param + key_2, value2)]
- """
- for k_1, v_1 in v.items():
- result.append(
- (
- (k + k_1).encode("utf-8") if isinstance(k, str) else k_1,
- (v + v_1).encode("utf-8") if isinstance(v, str) else v_1,
- )
- )
- # Return URL encoded string
- return urlencode(result, doseq=True)
- else:
- return data
-
-
-# Monkey patch the _encode_params from the requests library with the encode_params function above
-requests.models.RequestEncodingMixin._encode_params = encode_params
-
-
-def user_agent_extended(be_geo_id, caller):
- # Generate the extended portion of the User-Agent
- user_agent = dict()
-
- if caller:
- user_agent["caller"] = caller
- elif be_geo_id:
- user_agent["caller"] = be_geo_id
- else:
- user_agent["caller"] = "unidentified"
-
- caller_string = f"Caller/({user_agent['caller']})"
-
- return caller_string
-
-
-# Main module interface
-class RestSession(object):
- def __init__(
- self,
- logger,
- api_key,
- base_url=DEFAULT_BASE_URL,
- single_request_timeout=SINGLE_REQUEST_TIMEOUT,
- certificate_path=CERTIFICATE_PATH,
- requests_proxy=REQUESTS_PROXY,
- wait_on_rate_limit=WAIT_ON_RATE_LIMIT,
- nginx_429_retry_wait_time=NGINX_429_RETRY_WAIT_TIME,
- action_batch_retry_wait_time=ACTION_BATCH_RETRY_WAIT_TIME,
- network_delete_retry_wait_time=NETWORK_DELETE_RETRY_WAIT_TIME,
- retry_4xx_error=RETRY_4XX_ERROR,
- retry_4xx_error_wait_time=RETRY_4XX_ERROR_WAIT_TIME,
- maximum_retries=MAXIMUM_RETRIES,
- simulate=SIMULATE_API_CALLS,
- be_geo_id=BE_GEO_ID,
- caller=MERAKI_PYTHON_SDK_CALLER,
- use_iterator_for_get_pages=USE_ITERATOR_FOR_GET_PAGES,
- validate_kwargs=False,
- ):
- super(RestSession, self).__init__()
-
- # Initialize attributes and properties
- self._version = __version__
- self._api_key = str(api_key)
- self._base_url = str(base_url)
- self._single_request_timeout = single_request_timeout
- self._certificate_path = certificate_path
- self._requests_proxy = requests_proxy
- self._wait_on_rate_limit = wait_on_rate_limit
- self._nginx_429_retry_wait_time = nginx_429_retry_wait_time
- self._action_batch_retry_wait_time = action_batch_retry_wait_time
- self._network_delete_retry_wait_time = network_delete_retry_wait_time
- self._retry_4xx_error = retry_4xx_error
- self._retry_4xx_error_wait_time = retry_4xx_error_wait_time
- self._maximum_retries = maximum_retries
- self._simulate = simulate
- self._be_geo_id = be_geo_id
- self._caller = caller
- self.use_iterator_for_get_pages = use_iterator_for_get_pages
- self._validate_kwargs = validate_kwargs
-
- # Initialize a new `requests` session
- self._req_session = requests.session()
- self._req_session.encoding = "utf-8"
-
- # Check the Python version
- check_python_version()
-
- # Check base URL
- reject_v0_base_url(self)
-
- # Update the headers for the session
- self._req_session.headers = {
- "Authorization": "Bearer " + self._api_key,
- "Content-Type": "application/json",
- "User-Agent": f"python-meraki/{self._version} " + validate_user_agent(self._be_geo_id, self._caller),
- }
-
- # Log API calls
- self._logger = logger
- self._parameters = {"version": self._version}
- self._parameters.update(locals())
- self._parameters.pop("self")
- self._parameters.pop("logger")
- self._parameters.pop("__class__")
- self._parameters["api_key"] = "*" * 36 + self._api_key[-4:]
- if self._logger:
- self._logger.info(f"Meraki dashboard API session initialized with these parameters: {self._parameters}")
-
- @property
- def use_iterator_for_get_pages(self):
- return iterator_for_get_pages_bool(self)
-
- @use_iterator_for_get_pages.setter
- def use_iterator_for_get_pages(self, value):
- use_iterator_for_get_pages_setter(self, value)
-
- def request(self, metadata, method, url, **kwargs):
- # Metadata on endpoint
- tag = metadata["tags"][0]
- operation = metadata["operation"]
-
- # Update request kwargs with session defaults
- self.prepare_request(kwargs)
-
- # Ensure proper base URL
- abs_url = validate_base_url(self, url)
-
- # Set the maximum number of retries
- retries = self._maximum_retries
-
- # Option to simulate non-safe API calls without actually sending them
- if self._logger:
- self._logger.debug(metadata)
- if self._simulate and method != "GET":
- if self._logger:
- self._logger.info(f"{tag}, {operation} - SIMULATED")
- return None
- else:
- response = None
- while retries > 0:
- # Make the HTTP request to the API endpoint
- try:
- if response:
- response.close()
- if self._logger:
- self._logger.info(f"{method} {abs_url}")
- response = self._req_session.request(method, abs_url, allow_redirects=False, **kwargs)
- reason = response.reason if response.reason else ""
- status = response.status_code
- except requests.exceptions.RequestException as e:
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {e}, retrying in 1 second")
- time.sleep(1)
- retries -= 1
- if retries == 0:
- if e.response and e.response.status_code:
- raise APIError(
- metadata,
- APIResponseError(e.__class__.__name__, e.response.status_code, str(e)),
- )
- else:
- raise APIError(
- metadata,
- APIResponseError(e.__class__.__name__, 503, str(e)),
- )
- else:
- continue
-
- match status:
- # Handle 3xx redirects automatically
- case status if 300 <= status < 400:
- abs_url = handle_3xx(self, response)
- # Handle 2xx success
- case status if 200 <= status < 300:
- if "page" in metadata:
- counter = metadata["page"]
- if self._logger:
- self._logger.info(f"{tag}, {operation}; page {counter} - {status} {reason}")
- else:
- if self._logger:
- self._logger.info(f"{tag}, {operation} - {status} {reason}")
- # For non-empty response to GET, ensure valid JSON
- try:
- if method == "GET" and response.content.strip():
- response.json()
- return response
- except json.decoder.JSONDecodeError as e:
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {e}, retrying in 1 second")
- time.sleep(1)
- retries -= 1
- if retries == 0:
- raise APIError(metadata, response)
- else:
- continue
- # Handle rate limiting
- case 429:
- # Retry if 429 retries are enabled and there are retries left
- if self._wait_on_rate_limit and retries > 0:
- if "Retry-After" in response.headers:
- wait = int(response.headers["Retry-After"])
- else:
- attempt = self._maximum_retries - retries
- wait = min(
- (2**attempt) * (1 + random.random()),
- self._nginx_429_retry_wait_time,
- )
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
- time.sleep(wait)
- retries -= 1
- if retries == 0:
- raise APIError(metadata, response)
- # We're either out of retries or the client told us not to retry
- else:
- raise APIError(metadata, response)
- # Handle 5xx errors
- case status if 500 <= status:
- request_id = response.headers.get("X-Request-Id") or "none"
- if self._logger:
- self._logger.warning(
- f"{tag}, {operation} - {status} {reason} (X-Request-Id: {request_id}), retrying in 1 second"
- )
- time.sleep(1)
- retries -= 1
- if retries == 0:
- if self._logger:
- self._logger.error(
- f"{tag}, {operation} - {status} {reason} failed after retries. "
- f"Provide this X-Request-Id to Meraki for log lookup: {request_id}"
- )
- raise APIError(metadata, response)
- # Handle other 4xx errors
- case status if status != 429 and 400 <= status < 500:
- retries = self.handle_4xx_errors(metadata, operation, reason, response, retries, status, tag)
-
- return response
-
- def prepare_request(self, kwargs):
- if self._certificate_path:
- kwargs.setdefault("verify", self._certificate_path)
- if self._requests_proxy:
- kwargs.setdefault("proxies", {"https": self._requests_proxy})
- kwargs.setdefault("timeout", self._single_request_timeout)
-
- def handle_4xx_errors(self, metadata, operation, reason, response, retries, status, tag):
- try:
- message = response.json()
- message_is_dict = True
- except ValueError:
- message = response.content[:100]
- message_is_dict = False
-
- # Check specifically for concurrency errors
- network_delete_concurrency_error_text = "concurrent"
- action_batch_concurrency_error_text = "executing batches"
-
- # First, we check for network deletion concurrency errors
- if operation == "deleteNetwork" and response.status_code == 400:
- # message['errors'][0] is the first error, and it contains helpful text
- # here we use it to confirm that the 400 error is related to concurrent requests
- if network_delete_concurrency_error_text in message["errors"][0]:
- wait = random.randint(30, self._network_delete_retry_wait_time)
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
- time.sleep(wait)
- retries -= 1
- if retries == 0:
- raise APIError(metadata, response)
-
- # Next, we check for action batch concurrency errors
- # message['errors'][0] is the first error, and it contains helpful text
- # here we use it to confirm that the 400 error is related to concurrent requests
- elif message_is_dict and "errors" in message.keys() and action_batch_concurrency_error_text in message["errors"][0]:
- wait = self._action_batch_retry_wait_time
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
- time.sleep(wait)
- retries -= 1
- if retries == 0:
- raise APIError(metadata, response)
-
- # Then we check if the user asked to retry other 4xx errors, based on their session config
- elif self._retry_4xx_error:
- wait = random.randint(1, self._retry_4xx_error_wait_time)
- if self._logger:
- self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
- time.sleep(wait)
- retries -= 1
- if retries == 0:
- raise APIError(metadata, response)
-
- # All other client-side errors will raise an error
- else:
- if self._logger:
- self._logger.error(f"{tag}, {operation} - {status} {reason}, {message}")
- raise APIError(metadata, response)
- return retries
-
- def get(self, metadata, url, params=None):
- metadata["method"] = "GET"
- metadata["url"] = url
- metadata["params"] = params
- response = self.request(metadata, "GET", url, params=params)
- ret = None
- if response:
- if response.content.strip():
- ret = response.json()
- response.close()
- return ret
-
- def _get_pages_iterator(
- self,
- metadata,
- url,
- params=None,
- total_pages=-1,
- direction="next",
- event_log_end_time=None,
- ):
- if isinstance(total_pages, str) and total_pages.lower() == "all":
- total_pages = -1
- elif isinstance(total_pages, str) and total_pages.isnumeric():
- total_pages = int(total_pages)
- elif not isinstance(total_pages, int):
- raise SessionInputError(
- "total_pages",
- total_pages,
- "total_pages must be either an integer or 'all' as a string (remember to add the quotation marks).",
- None,
- )
- metadata["page"] = 1
-
- response = self.request(metadata, "GET", url, params=params)
-
- # Get additional pages if more than one requested
- while total_pages != 0:
- results = response.json()
- links = response.links
-
- # GET the subsequent page
- if direction == "next" and "next" in links:
- # Prevent getNetworkEvents from infinite loop as time goes forward
- if metadata["operation"] == "getNetworkEvents":
- starting_after = urllib.parse.unquote(str(links["next"]["url"]).split("startingAfter=")[1])
- delta = datetime.now(timezone.utc) - datetime.fromisoformat(starting_after)
- # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
- if delta.total_seconds() < 300:
- break
- # Or if the next page is past the specified window's end time
- elif event_log_end_time and starting_after > event_log_end_time:
- break
-
- metadata["page"] += 1
- nextlink = links["next"]["url"]
- elif direction == "prev" and "prev" in links:
- # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
- if metadata["operation"] == "getNetworkEvents":
- ending_before = urllib.parse.unquote(str(links["prev"]["url"]).split("endingBefore=")[1])
- # Break out of loop if endingBefore returned from prev link is before 2014
- if ending_before < "2014-01-01":
- break
-
- metadata["page"] += 1
- nextlink = links["prev"]["url"]
- else:
- total_pages = 1
-
- response.close()
-
- return_items = []
- # Just prepare the list
- if isinstance(results, list):
- return_items = results
- elif isinstance(results, dict) and "items" in results:
- return_items = results["items"]
- # For event log endpoint
- elif isinstance(results, dict):
- if direction == "next":
- return_items = results["events"][::-1]
- else:
- return_items = results["events"]
-
- for item in return_items:
- yield item
-
- total_pages = total_pages - 1
-
- if total_pages != 0:
- response = self.request(metadata, "GET", nextlink)
-
- def _get_pages_legacy(
- self,
- metadata,
- url,
- params=None,
- total_pages=-1,
- direction="next",
- event_log_end_time=None,
- ):
- if isinstance(total_pages, str) and total_pages.lower() == "all":
- total_pages = -1
- elif isinstance(total_pages, str) and total_pages.isnumeric():
- total_pages = int(total_pages)
- elif not isinstance(total_pages, int):
- raise SessionInputError(
- "total_pages",
- total_pages,
- "total_pages must be either an integer or 'all' as a string (remember to add the quotation marks).",
- None,
- )
-
- metadata["page"] = 1
-
- response = self.request(metadata, "GET", url, params=params)
-
- # Handle GETs that produce 204 No Content responses, e.g. getOrganizationClientSearch
- if response.status_code == 204:
- results = None
- else:
- results = response.json()
-
- # For event log endpoint when using 'next' direction, so results/events are sorted chronologically
- if isinstance(results, dict) and metadata["operation"] == "getNetworkEvents" and direction == "next":
- results["events"] = results["events"][::-1]
-
- # Get additional pages if more than one requested
- while total_pages != 1:
- links = response.links
- response.close()
- response = None
-
- # GET the subsequent page
- if direction == "next" and "next" in links:
- # Prevent getNetworkEvents from infinite loop as time goes forward
- if metadata["operation"] == "getNetworkEvents":
- starting_after = urllib.parse.unquote(links["next"]["url"].split("startingAfter=")[1])
- delta = datetime.now(timezone.utc) - datetime.fromisoformat(starting_after)
- # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
- if delta.total_seconds() < 300:
- break
- # Or if next page is past the specified window's end time
- elif event_log_end_time and starting_after > event_log_end_time:
- break
-
- metadata["page"] += 1
- response = self.request(metadata, "GET", links["next"]["url"])
- elif direction == "prev" and "prev" in links:
- # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
- if metadata["operation"] == "getNetworkEvents":
- ending_before = urllib.parse.unquote(links["prev"]["url"].split("endingBefore=")[1])
- # Break out of loop if endingBefore returned from prev link is before 2014
- if ending_before < "2014-01-01":
- break
-
- metadata["page"] += 1
- response = self.request(metadata, "GET", links["prev"]["url"])
- else:
- break
-
- # Append that page's results, depending on the endpoint
- if isinstance(results, list):
- results.extend(response.json())
- elif isinstance(results, dict) and "items" in results:
- results["items"].extend(response.json()["items"])
- if "meta" in results:
- results["meta"]["counts"]["items"]["remaining"] = response.json()["meta"]["counts"]["items"]["remaining"]
- # For event log endpoint
- elif isinstance(results, dict):
- try:
- start = response.json()["pageStartAt"]
- except KeyError:
- if self._logger:
- self._logger.warning(f"pageStartAt missing from response: {response.headers}")
- end = response.json()["pageEndAt"]
- events = response.json()["events"]
- if direction == "next":
- events = events[::-1]
- if start < results["pageStartAt"]:
- results["pageStartAt"] = start
- if end > results["pageEndAt"]:
- results["pageEndAt"] = end
- results["events"].extend(events)
-
- total_pages -= 1
-
- if response:
- response.close()
-
- return results
-
- def post(self, metadata, url, json=None):
- metadata["method"] = "POST"
- metadata["url"] = url
- metadata["json"] = json
- response = self.request(metadata, "POST", url, json=json)
- ret = None
- if response:
- if response.content.strip():
- ret = response.json()
- response.close()
- return ret
-
- def put(self, metadata, url, json=None):
- metadata["method"] = "PUT"
- metadata["url"] = url
- metadata["json"] = json
- response = self.request(metadata, "PUT", url, json=json)
- ret = None
- if response:
- if response.content.strip():
- ret = response.json()
- response.close()
- return ret
-
- def delete(self, metadata, url, params=None):
- metadata["method"] = "DELETE"
- metadata["url"] = url
- metadata["params"] = params
- response = self.request(metadata, "DELETE", url, params=params)
- if response:
- response.close()
- return None
diff --git a/meraki/session/__init__.py b/meraki/session/__init__.py
new file mode 100644
index 00000000..be173387
--- /dev/null
+++ b/meraki/session/__init__.py
@@ -0,0 +1,7 @@
+"""Session implementations for Meraki Dashboard API."""
+
+from meraki.session.base import SessionBase
+from meraki.session.sync import RestSession
+from meraki.session.async_ import AsyncRestSession
+
+__all__ = ["SessionBase", "RestSession", "AsyncRestSession"]
diff --git a/meraki/session/async_.py b/meraki/session/async_.py
new file mode 100644
index 00000000..90829fca
--- /dev/null
+++ b/meraki/session/async_.py
@@ -0,0 +1,689 @@
+"""Asynchronous REST session for Meraki Dashboard API."""
+
+from __future__ import annotations
+
+import asyncio
+import json
+import random
+import urllib.parse
+from datetime import datetime, timezone
+from typing import Any, Dict, Optional
+
+import httpx
+
+from meraki.common import validate_base_url, validate_user_agent
+from meraki.config import AIO_MAXIMUM_CONCURRENT_REQUESTS
+from meraki.exceptions import APIError, SessionInputError
+from meraki.smart_flow import AsyncOrgRateLimiter
+from meraki.session.base import SessionBase, apply_meraki_param_encoding
+
+
+class AsyncRestSession(SessionBase):
+ """Asynchronous session using httpx.AsyncClient.
+
+ Inherits config storage from SessionBase.
+ Overrides request() as async with await on _send_request/_sleep.
+ Uses httpx.Limits for concurrency control (replaces asyncio.Semaphore per D-02).
+ """
+
+ def __init__(
+ self,
+ logger,
+ api_key,
+ maximum_concurrent_requests: int = AIO_MAXIMUM_CONCURRENT_REQUESTS,
+ **kwargs: Any,
+ ) -> None:
+ super().__init__(logger, api_key, **kwargs)
+
+ # Build headers dict
+ headers = self._build_headers()
+ # Async user-agent prefix
+ headers["User-Agent"] = f"python-meraki/aio-{self._version} " + validate_user_agent(self._be_geo_id, self._caller)
+
+ # Build client config (per D-02: Limits replaces Semaphore, per D-06: proxy passthrough)
+ client_kwargs: Dict[str, Any] = {
+ "timeout": self._single_request_timeout,
+ "limits": httpx.Limits(max_connections=maximum_concurrent_requests),
+ "headers": headers,
+ }
+ if self._certificate_path:
+ client_kwargs["verify"] = self._certificate_path
+ if self._requests_proxy:
+ client_kwargs["proxy"] = self._requests_proxy
+
+ # Persistent async client with connection pooling
+ self._client = httpx.AsyncClient(**client_kwargs)
+
+ # Per-org smart flow (opt-in)
+ if self._smart_flow_enabled:
+ self._smart_flow = AsyncOrgRateLimiter(
+ rate=self._smart_flow_org_rate,
+ capacity=int(self._smart_flow_org_rate),
+ global_rate=self._smart_flow_global_rate,
+ cache_path=self._smart_flow_cache_path or None,
+ cache_ttl=self._smart_flow_cache_ttl,
+ logger=self._logger if self._smart_flow_logging else None,
+ )
+ self._smart_flow.set_resolver(self._resolve_org_for_limiter)
+ self._smart_flow.set_hydrator(self._hydrate_org_for_limiter)
+
+ # Trigger the property setter to bind the correct get_pages implementation
+ self.use_iterator_for_get_pages = self._use_iterator_for_get_pages
+
+ @property
+ def use_iterator_for_get_pages(self):
+ return self._use_iterator_for_get_pages
+
+ @use_iterator_for_get_pages.setter
+ def use_iterator_for_get_pages(self, value):
+ if value:
+ self.get_pages = self._get_pages_iterator
+ else:
+ self.get_pages = self._get_pages_legacy
+ self._use_iterator_for_get_pages = value
+
+ # ------------------------------------------------------------------
+ # Abstract method implementations
+ # ------------------------------------------------------------------
+
+ async def _send_request(self, method: str, url: str, **kwargs: Any) -> httpx.Response:
+ """Send HTTP request via httpx.AsyncClient (pool limits enforce concurrency per D-02)."""
+ # Pre-encode Meraki array-of-objects params; httpx mishandles them.
+ url = apply_meraki_param_encoding(url, kwargs)
+ response = await self._client.request(method, url, follow_redirects=False, **kwargs)
+ return response
+
+ async def _sleep(self, seconds: float) -> None:
+ """Async sleep for retry delays."""
+ await asyncio.sleep(seconds)
+
+ def _transport_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
+ """No-op: httpx config handled at client initialization level."""
+ return kwargs
+
+ # ------------------------------------------------------------------
+ # Smart flow resolver
+ # ------------------------------------------------------------------
+
+ async def _acquire_global_bucket(self) -> None:
+ """Gate internal hydration/resolution traffic on the global bucket.
+
+ These internal GETs bypass self.request() to avoid resolver reentrancy,
+ but must still account against the global (source IP) bucket they help
+ populate. Defensive: no-op if smart flow or the bucket is unavailable.
+ """
+ if not self._smart_flow:
+ return
+ bucket = getattr(self._smart_flow, "_global_bucket", None)
+ if bucket is not None:
+ await bucket.acquire()
+
+ async def _resolve_org_for_limiter(self, id_type: str, identifier: str) -> Optional[str]:
+ """Resolve a network/device ID to its org by calling the API directly."""
+ if id_type == "network":
+ endpoint = f"{self._base_url}/networks/{identifier}"
+ else:
+ endpoint = f"{self._base_url}/devices/{identifier}"
+ try:
+ await self._acquire_global_bucket()
+ response = await self._client.request("GET", endpoint, follow_redirects=True)
+ if response.status_code == 200:
+ data = response.json()
+ return data.get("organizationId")
+ except Exception:
+ pass
+ return None
+
+ async def _hydrate_org_for_limiter(self, org_id: str) -> None:
+ """Fetch all networks and devices for an org and register them with the limiter."""
+ networks = await self._fetch_all_pages(f"{self._base_url}/organizations/{org_id}/networks?perPage=1000")
+ for net in networks:
+ if "id" in net:
+ self._smart_flow.register_network(net["id"], org_id)
+
+ devices = await self._fetch_all_pages(f"{self._base_url}/organizations/{org_id}/inventoryDevices?perPage=1000")
+ for dev in devices:
+ if "serial" in dev:
+ self._smart_flow.register_device(dev["serial"], org_id)
+
+ async def _fetch_all_pages(self, url: str) -> list:
+ """Paginate through a Meraki list endpoint using Link headers."""
+ results = []
+ while url:
+ await self._acquire_global_bucket()
+ response = await self._client.request("GET", url, follow_redirects=True)
+ if response.status_code != 200:
+ break
+ page = response.json()
+ if isinstance(page, list):
+ results.extend(page)
+ next_link = response.links.get("next", {}).get("url")
+ url = next_link if next_link else None
+ return results
+
+ # ------------------------------------------------------------------
+ # Async request override (awaits abstract methods)
+ # ------------------------------------------------------------------
+
+ async def request(self, metadata: Dict[str, Any], method: str, url: str, **kwargs: Any) -> Optional[httpx.Response]:
+ """Execute an API request with retry loop and status dispatch (async version).
+
+ Mirrors SessionBase.request() but awaits _send_request and _sleep.
+ """
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+
+ # Prepare transport-specific kwargs
+ kwargs = self._transport_kwargs(kwargs)
+
+ # aiohttp manipulates URLs as instances of yarl.URL
+ if not isinstance(url, str):
+ url = str(url)
+
+ # Resolve absolute URL
+ abs_url = validate_base_url(self, url)
+
+ # Simulate non-GET calls
+ if self._logger:
+ self._logger.debug(metadata)
+ if self._simulate and method != "GET":
+ if self._logger:
+ self._logger.info(f"{tag}, {operation} - SIMULATED")
+ return None
+
+ retries = self._maximum_retries
+ response: Optional[httpx.Response] = None
+
+ while retries > 0:
+ # Per-org rate limiting (proactive throttle before sending)
+ if self._smart_flow:
+ await self._smart_flow.acquire(abs_url)
+
+ # Attempt the request
+ try:
+ if response:
+ await response.aclose()
+ if self._logger:
+ self._logger.info(f"{method} {abs_url}")
+ response = await self._send_request(method, abs_url, **kwargs)
+ except httpx.HTTPError as e:
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {e}, retrying in 1 second")
+ await self._sleep(1)
+ retries -= 1
+ if retries == 0:
+ raise APIError(
+ metadata,
+ type(
+ "FakeResponse",
+ (),
+ {"status_code": 503, "reason_phrase": str(e), "json": lambda self: {}, "content": b""},
+ )(),
+ )
+ continue
+
+ status = response.status_code
+ reason = response.reason_phrase if response.reason_phrase else ""
+
+ # Dispatch by status code
+ if 300 <= status < 400:
+ abs_url = self._handle_redirect_async(response)
+ elif 200 <= status < 300:
+ if self._smart_flow:
+ self._smart_flow.on_success(abs_url)
+ # _handle_success_async returns (response, parsed_body); parsed_body
+ # is the decoded GET body (or None) so we don't parse JSON twice.
+ result, parsed_body = await self._handle_success_async(response, metadata, method)
+ if result is None:
+ # JSON decode failure, retry
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ await self._sleep(1)
+ continue
+ if self._smart_flow and method == "GET" and parsed_body is not None:
+ try:
+ self._smart_flow.learn_from_response(abs_url, parsed_body)
+ except (ValueError, AttributeError):
+ pass
+ return result
+ elif status == 429:
+ if self._smart_flow:
+ self._smart_flow.on_rate_limited(abs_url)
+ wait = self._handle_rate_limit_async(response, metadata, retries)
+ await self._sleep(wait)
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ elif status >= 500:
+ request_id = response.headers.get("X-Request-Id") or "none"
+ if self._logger:
+ self._logger.warning(
+ f"{tag}, {operation} - {status} {reason} (X-Request-Id: {request_id}), retrying in 1 second"
+ )
+ await self._sleep(1)
+ retries -= 1
+ if retries == 0:
+ if self._logger:
+ self._logger.error(
+ f"{tag}, {operation} - {status} {reason} failed after retries. "
+ f"Provide this X-Request-Id to Meraki for log lookup: {request_id}"
+ )
+ raise APIError(metadata, response)
+ elif 400 <= status < 500:
+ retries = await self._handle_client_error_async(response, metadata, retries)
+
+ return response
+
+ # ------------------------------------------------------------------
+ # Async status handlers
+ # ------------------------------------------------------------------
+
+ async def _handle_success_async(
+ self,
+ response: Any,
+ metadata: Dict[str, Any],
+ method: str,
+ ) -> tuple[Optional[Any], Optional[Any]]:
+ """Handle 2xx responses (async).
+
+ Returns (response, parsed_body). parsed_body is the decoded GET JSON body
+ (or None for non-GET / empty bodies), parsed once here so callers do not
+ re-parse. On JSON decode failure returns (None, None) to signal a retry.
+ """
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if response.reason_phrase else ""
+ status = response.status_code
+
+ if "page" in metadata:
+ counter = metadata["page"]
+ if self._logger:
+ self._logger.info(f"{tag}, {operation}; page {counter} - {status} {reason}")
+ else:
+ if self._logger:
+ self._logger.info(f"{tag}, {operation} - {status} {reason}")
+
+ # For non-empty GET responses, validate (and capture) the JSON once.
+ try:
+ if method == "GET" and response.content.strip():
+ return response, response.json()
+ return response, None
+ except (json.decoder.JSONDecodeError, ValueError):
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - JSON decode error, retrying in 1 second")
+ return None, None
+
+ def _handle_redirect_async(self, response: Any) -> str:
+ """Handle 3xx redirects for aiohttp responses."""
+ abs_url = str(response.headers["Location"])
+ substring = "meraki.com/api/v"
+ if substring not in abs_url:
+ substring = "meraki.cn/api/v"
+ if substring in abs_url:
+ self._base_url = abs_url[: abs_url.find(substring) + len(substring) + 1]
+ return abs_url
+
+ def _handle_rate_limit_async(
+ self,
+ response: Any,
+ metadata: Dict[str, Any],
+ retries: int,
+ ) -> float:
+ """Handle 429 rate limiting (async). Returns seconds to wait."""
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if response.reason_phrase else ""
+ status = response.status_code
+
+ if not self._wait_on_rate_limit or retries <= 0:
+ raise APIError(metadata, response)
+
+ if "Retry-After" in response.headers:
+ wait = int(response.headers["Retry-After"])
+ else:
+ attempt = self._maximum_retries - retries
+ wait = min(
+ (2**attempt) * (1 + random.random()),
+ self._nginx_429_retry_wait_time,
+ )
+
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
+ return wait
+
+ async def _handle_client_error_async(
+ self,
+ response: Any,
+ metadata: Dict[str, Any],
+ retries: int,
+ ) -> int:
+ """Handle 4xx client errors (async). Returns updated retry count."""
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if response.reason_phrase else ""
+ status = response.status_code
+
+ # Parse response body
+ try:
+ message = response.json()
+ message_is_dict = isinstance(message, dict)
+ except (json.decoder.JSONDecodeError, ValueError):
+ message_is_dict = False
+ try:
+ message = response.text[:100]
+ except Exception:
+ message = None
+
+ # Network delete concurrency error
+ if (
+ metadata.get("operation") == "deleteNetwork"
+ and status == 400
+ and message_is_dict
+ and "errors" in message
+ and "concurrent" in str(message["errors"][0])
+ ):
+ wait = random.randint(30, self._network_delete_retry_wait_time)
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
+ await self._sleep(wait)
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ return retries
+
+ # Action batch concurrency error
+ if message_is_dict and "errors" in message and "executing batches" in str(message["errors"][0]).lower():
+ wait = self._action_batch_retry_wait_time
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
+ await self._sleep(wait)
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ return retries
+
+ # Retry other 4xx if configured
+ if self._retry_4xx_error:
+ wait = random.randint(1, self._retry_4xx_error_wait_time)
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
+ await self._sleep(wait)
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ return retries
+
+ # Non-retryable client error
+ if self._logger:
+ self._logger.error(f"{tag}, {operation} - {status} {reason}, {message}")
+ raise APIError(metadata, response)
+
+ # ------------------------------------------------------------------
+ # Convenience HTTP methods
+ # ------------------------------------------------------------------
+
+ async def get(self, metadata, url, params=None):
+ metadata["method"] = "GET"
+ metadata["url"] = url
+ metadata["params"] = params
+ response = await self.request(metadata, "GET", url, params=params)
+ if response:
+ if response.content.strip():
+ return response.json()
+ return None
+
+ async def get_pages(self, metadata, url, params=None, total_pages=-1, direction="next", event_log_end_time=None):
+ pass
+
+ async def _download_page(self, request):
+ response = await request
+ # Guard against 204 No Content pages (empty body -> no JSON to parse).
+ if response.status_code == 204:
+ result = None
+ else:
+ result = response.json()
+ return response, result
+
+ async def _get_pages_iterator(
+ self,
+ metadata,
+ url,
+ params=None,
+ total_pages=-1,
+ direction="next",
+ event_log_end_time=None,
+ ):
+ if isinstance(total_pages, str) and total_pages.lower() == "all":
+ total_pages = -1
+ elif isinstance(total_pages, str) and total_pages.isnumeric():
+ total_pages = int(total_pages)
+ elif not isinstance(total_pages, int):
+ raise SessionInputError(
+ "total_pages",
+ total_pages,
+ "total_pages must be either an integer or 'all' as a string (remember to add the quotation marks).",
+ None,
+ )
+ metadata["page"] = 1
+
+ request_task = asyncio.create_task(self._download_page(self.request(metadata, "GET", url, params=params)))
+
+ # Wrap in try/finally so an in-flight prefetch task is cancelled if the
+ # consumer breaks early (avoids an orphaned request and "Task pending" warning).
+ try:
+ # Get additional pages if more than one requested
+ while total_pages != 0:
+ response, results = await request_task
+
+ # Guard against 204 No Content pages (empty body -> stop cleanly).
+ if response.status_code == 204:
+ await response.aclose()
+ return
+
+ links = response.links
+
+ # GET the subsequent page
+ if direction == "next" and "next" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes forward
+ if metadata["operation"] == "getNetworkEvents":
+ starting_after = urllib.parse.unquote(str(links["next"]["url"]).split("startingAfter=")[1])
+ delta = datetime.now(timezone.utc) - datetime.fromisoformat(starting_after)
+ # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
+ if delta.total_seconds() < 300:
+ break
+ # Or if next page is past the specified window's end time
+ elif event_log_end_time and starting_after > event_log_end_time:
+ break
+
+ metadata["page"] += 1
+ nextlink = links["next"]["url"]
+ elif direction == "prev" and "prev" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
+ if metadata["operation"] == "getNetworkEvents":
+ ending_before = urllib.parse.unquote(str(links["prev"]["url"]).split("endingBefore=")[1])
+ # Break out of loop if endingBefore returned from prev link is before 2014
+ if ending_before < "2014-01-01":
+ break
+
+ metadata["page"] += 1
+ nextlink = links["prev"]["url"]
+ else:
+ total_pages = 1
+
+ await response.aclose()
+
+ total_pages = total_pages - 1
+
+ if total_pages != 0:
+ request_task = asyncio.create_task(self._download_page(self.request(metadata, "GET", nextlink)))
+
+ return_items = []
+ # just prepare the list
+ if isinstance(results, list):
+ return_items = results
+ elif isinstance(results, dict) and "items" in results:
+ return_items = results["items"]
+ # For event log endpoint
+ elif isinstance(results, dict):
+ if direction == "next":
+ return_items = results["events"][::-1]
+ else:
+ return_items = results["events"]
+
+ for item in return_items:
+ yield item
+ finally:
+ # Cancel and drain any still-pending prefetch (e.g. consumer broke early).
+ if request_task is not None and not request_task.done():
+ request_task.cancel()
+ try:
+ await request_task
+ except asyncio.CancelledError:
+ pass
+ except Exception:
+ pass
+ elif request_task is not None and request_task.cancelled() is False:
+ # Task completed: close its response to release the connection.
+ try:
+ resolved_response, _ = request_task.result()
+ await resolved_response.aclose()
+ except Exception:
+ pass
+
+ async def _get_pages_legacy(
+ self,
+ metadata,
+ url,
+ params=None,
+ total_pages=-1,
+ direction="next",
+ event_log_end_time=None,
+ ):
+ if isinstance(total_pages, str) and total_pages.lower() == "all":
+ total_pages = -1
+ elif isinstance(total_pages, str) and total_pages.isnumeric():
+ total_pages = int(total_pages)
+ elif not isinstance(total_pages, int):
+ raise SessionInputError(
+ "total_pages",
+ total_pages,
+ "total_pages must be either an integer or 'all' as a string (remember to add the quotation marks).",
+ None,
+ )
+ metadata["page"] = 1
+
+ response = await self.request(metadata, "GET", url, params=params)
+
+ if response.status_code == 204:
+ results = None
+ else:
+ results = response.json()
+
+ # For event log endpoint when using 'next' direction
+ if isinstance(results, dict) and metadata["operation"] == "getNetworkEvents" and direction == "next":
+ results["events"] = results["events"][::-1]
+
+ links = response.links
+ await response.aclose()
+
+ # Get additional pages if more than one requested
+ while total_pages != 1:
+ # GET the subsequent page
+ if direction == "next" and "next" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes forward
+ if metadata["operation"] == "getNetworkEvents":
+ starting_after = urllib.parse.unquote(str(links["next"]["url"]).split("startingAfter=")[1])
+ delta = datetime.now(timezone.utc) - datetime.fromisoformat(starting_after)
+ if delta.total_seconds() < 300:
+ break
+ elif event_log_end_time and starting_after > event_log_end_time:
+ break
+
+ metadata["page"] += 1
+ nextlink = links["next"]["url"]
+ elif direction == "prev" and "prev" in links:
+ if metadata["operation"] == "getNetworkEvents":
+ ending_before = urllib.parse.unquote(str(links["prev"]["url"]).split("endingBefore=")[1])
+ if ending_before < "2014-01-01":
+ break
+
+ metadata["page"] += 1
+ nextlink = links["prev"]["url"]
+ else:
+ break
+
+ response = await self.request(metadata, "GET", nextlink)
+ links = response.links
+ if isinstance(results, list):
+ results.extend(response.json())
+ elif isinstance(results, dict) and "items" in results:
+ json_response = response.json()
+ results["items"].extend(json_response["items"])
+ if "meta" in results:
+ results["meta"]["counts"]["items"]["remaining"] = json_response["meta"]["counts"]["items"]["remaining"]
+ # For event log endpoint
+ elif isinstance(results, dict):
+ json_response = response.json()
+ start = json_response["pageStartAt"]
+ end = json_response["pageEndAt"]
+ events = json_response["events"]
+ if direction == "next":
+ events = events[::-1]
+ if start < results["pageStartAt"]:
+ results["pageStartAt"] = start
+ if end > results["pageEndAt"]:
+ results["pageEndAt"] = end
+ results["events"].extend(events)
+
+ await response.aclose()
+ total_pages = total_pages - 1
+
+ return results
+
+ async def post(self, metadata, url, json=None):
+ metadata["method"] = "POST"
+ metadata["url"] = url
+ metadata["json"] = json
+ response = await self.request(metadata, "POST", url, json=json)
+ if response:
+ if response.content.strip():
+ return response.json()
+ return None
+
+ async def put(self, metadata, url, json=None):
+ metadata["method"] = "PUT"
+ metadata["url"] = url
+ metadata["json"] = json
+ response = await self.request(metadata, "PUT", url, json=json)
+ if response:
+ if response.content.strip():
+ return response.json()
+ return None
+
+ async def patch(self, metadata, url, json=None):
+ metadata["method"] = "PATCH"
+ metadata["url"] = url
+ metadata["json"] = json
+ response = await self.request(metadata, "PATCH", url, json=json)
+ if response:
+ if response.content.strip():
+ return response.json()
+ return None
+
+ async def delete(self, metadata, url, params=None):
+ metadata["method"] = "DELETE"
+ metadata["url"] = url
+ metadata["params"] = params
+ await self.request(metadata, "DELETE", url, params=params)
+ return None
+
+ async def close(self):
+ """Close the underlying httpx.AsyncClient and release connections."""
+ await self._client.aclose()
+
+ async def __aenter__(self):
+ return self
+
+ async def __aexit__(self, *args):
+ await self.close()
diff --git a/meraki/session/base.py b/meraki/session/base.py
new file mode 100644
index 00000000..d4d5249b
--- /dev/null
+++ b/meraki/session/base.py
@@ -0,0 +1,513 @@
+"""Abstract base class for sync and async Meraki API sessions."""
+
+from __future__ import annotations
+
+import json
+import random
+from abc import ABC, abstractmethod
+from typing import Any, Dict, Optional
+
+from meraki._version import __version__
+from meraki.common import (
+ check_python_version,
+ reject_v0_base_url,
+ validate_base_url,
+ validate_meraki_app_value,
+ validate_user_agent,
+)
+from meraki.config import (
+ ACTION_BATCH_RETRY_WAIT_TIME,
+ BE_GEO_ID,
+ CERTIFICATE_PATH,
+ DEFAULT_BASE_URL,
+ MAXIMUM_RETRIES,
+ MERAKI_APP_BEARER_TOKEN,
+ MERAKI_APP_ID,
+ MERAKI_PYTHON_SDK_CALLER,
+ NETWORK_DELETE_RETRY_WAIT_TIME,
+ NGINX_429_RETRY_WAIT_TIME,
+ SMART_FLOW_ENABLED,
+ SMART_FLOW_CACHE_PATH,
+ SMART_FLOW_CACHE_TTL,
+ SMART_FLOW_CACHE_MODE,
+ SMART_FLOW_GLOBAL_RATE,
+ SMART_FLOW_LOGGING,
+ SMART_FLOW_ORG_RATE,
+ REQUESTS_PROXY,
+ RETRY_4XX_ERROR,
+ RETRY_4XX_ERROR_WAIT_TIME,
+ SIMULATE_API_CALLS,
+ SINGLE_REQUEST_TIMEOUT,
+ USE_ITERATOR_FOR_GET_PAGES,
+ WAIT_ON_RATE_LIMIT,
+)
+import httpx
+
+from meraki.exceptions import APIError, APIResponseError
+from meraki.response_handler import handle_3xx
+
+
+def params_need_meraki_encoding(params: Any) -> bool:
+ """Return True if params is a dict containing list-of-dict values.
+
+ Meraki's array-of-objects query encoding (param[]k1=v1¶m[]k2=v2) is only
+ needed for this shape. Scalars and scalar lists (e.g. networkIds[]=a&b) are
+ encoded correctly by httpx and must be left untouched.
+ """
+ if not isinstance(params, dict):
+ return False
+ for value in params.values():
+ if isinstance(value, (list, tuple)):
+ if any(isinstance(item, dict) for item in value):
+ return True
+ return False
+
+
+def apply_meraki_param_encoding(url: str, kwargs: Dict[str, Any]) -> str:
+ """Pre-encode list-of-dict params via encode_meraki_params and fold into URL.
+
+ When params contains array-of-objects values, httpx stringifies them
+ incorrectly. We build the query string ourselves, append it to the URL, and
+ drop params so httpx does not re-encode. Scalar / scalar-list params are left
+ for httpx to handle as before.
+ """
+ from meraki.encoding import encode_meraki_params
+
+ params = kwargs.get("params")
+ if not params_need_meraki_encoding(params):
+ return url
+
+ query = encode_meraki_params(params)
+ kwargs["params"] = None
+ if not query:
+ return url
+ separator = "&" if "?" in url else "?"
+ return f"{url}{separator}{query}"
+
+
+class SessionBase(ABC):
+ """Abstract base class providing config storage, URL resolution, retry loop, and status dispatch.
+
+ Subclasses must implement:
+ _send_request: perform the actual HTTP call
+ _sleep: pause execution (sync or async)
+ _transport_kwargs: prepare transport-specific request kwargs
+ """
+
+ def __init__(
+ self,
+ logger: Any,
+ api_key: str,
+ meraki_app_id: str = MERAKI_APP_ID,
+ meraki_app_bearer_token: str = MERAKI_APP_BEARER_TOKEN,
+ base_url: str = DEFAULT_BASE_URL,
+ single_request_timeout: int = SINGLE_REQUEST_TIMEOUT,
+ certificate_path: str = CERTIFICATE_PATH,
+ requests_proxy: str = REQUESTS_PROXY,
+ wait_on_rate_limit: bool = WAIT_ON_RATE_LIMIT,
+ nginx_429_retry_wait_time: int = NGINX_429_RETRY_WAIT_TIME,
+ action_batch_retry_wait_time: int = ACTION_BATCH_RETRY_WAIT_TIME,
+ network_delete_retry_wait_time: int = NETWORK_DELETE_RETRY_WAIT_TIME,
+ retry_4xx_error: bool = RETRY_4XX_ERROR,
+ retry_4xx_error_wait_time: int = RETRY_4XX_ERROR_WAIT_TIME,
+ maximum_retries: int = MAXIMUM_RETRIES,
+ simulate: bool = SIMULATE_API_CALLS,
+ be_geo_id: str = BE_GEO_ID,
+ caller: str = MERAKI_PYTHON_SDK_CALLER,
+ use_iterator_for_get_pages: bool = USE_ITERATOR_FOR_GET_PAGES,
+ validate_kwargs: bool = False,
+ smart_flow_enabled: bool = SMART_FLOW_ENABLED,
+ smart_flow_org_rate: float = SMART_FLOW_ORG_RATE,
+ smart_flow_global_rate: float = SMART_FLOW_GLOBAL_RATE,
+ smart_flow_cache_mode: str = SMART_FLOW_CACHE_MODE,
+ smart_flow_cache_path: str = SMART_FLOW_CACHE_PATH,
+ smart_flow_cache_ttl: Optional[float] = SMART_FLOW_CACHE_TTL,
+ smart_flow_logging: bool = SMART_FLOW_LOGGING,
+ ) -> None:
+ super().__init__()
+
+ # Store config attributes
+ self._version = __version__
+ self._api_key = str(api_key)
+ validate_meraki_app_value("meraki_app_id", meraki_app_id)
+ validate_meraki_app_value("meraki_app_bearer_token", meraki_app_bearer_token)
+ self._meraki_app_id = meraki_app_id
+ self._meraki_app_bearer_token = meraki_app_bearer_token
+ self._base_url = str(base_url)
+ self._single_request_timeout = single_request_timeout
+ self._certificate_path = certificate_path
+ self._requests_proxy = requests_proxy
+ self._wait_on_rate_limit = wait_on_rate_limit
+ self._nginx_429_retry_wait_time = nginx_429_retry_wait_time
+ self._action_batch_retry_wait_time = action_batch_retry_wait_time
+ self._network_delete_retry_wait_time = network_delete_retry_wait_time
+ self._retry_4xx_error = retry_4xx_error
+ self._retry_4xx_error_wait_time = retry_4xx_error_wait_time
+ self._maximum_retries = maximum_retries
+ self._simulate = simulate
+ self._be_geo_id = be_geo_id
+ self._caller = caller
+ self._use_iterator_for_get_pages = use_iterator_for_get_pages
+ self._validate_kwargs = validate_kwargs
+ self._smart_flow_enabled = smart_flow_enabled
+ self._smart_flow_org_rate = smart_flow_org_rate
+ self._smart_flow_global_rate = smart_flow_global_rate
+ self._smart_flow_cache_mode = smart_flow_cache_mode
+ self._smart_flow_cache_path = smart_flow_cache_path
+ self._smart_flow_cache_ttl = smart_flow_cache_ttl
+ self._smart_flow_logging = smart_flow_logging
+
+ # Check Python version
+ check_python_version()
+
+ # Reject v0 base URL
+ reject_v0_base_url(self)
+
+ # Logger and masked parameters for logging
+ self._logger = logger
+ self._parameters: Dict[str, Any] = {"version": self._version}
+ self._parameters["api_key"] = "*" * 36 + self._api_key[-4:]
+ if self._meraki_app_bearer_token:
+ self._parameters["meraki_app_bearer_token"] = "*" * 36 + str(self._meraki_app_bearer_token)[-4:]
+ self._parameters["base_url"] = self._base_url
+ self._parameters["single_request_timeout"] = self._single_request_timeout
+ self._parameters["certificate_path"] = self._certificate_path
+ self._parameters["requests_proxy"] = self._requests_proxy
+ self._parameters["wait_on_rate_limit"] = self._wait_on_rate_limit
+ self._parameters["nginx_429_retry_wait_time"] = self._nginx_429_retry_wait_time
+ self._parameters["action_batch_retry_wait_time"] = self._action_batch_retry_wait_time
+ self._parameters["network_delete_retry_wait_time"] = self._network_delete_retry_wait_time
+ self._parameters["retry_4xx_error"] = self._retry_4xx_error
+ self._parameters["retry_4xx_error_wait_time"] = self._retry_4xx_error_wait_time
+ self._parameters["maximum_retries"] = self._maximum_retries
+ self._parameters["simulate"] = self._simulate
+ self._parameters["be_geo_id"] = self._be_geo_id
+ self._parameters["caller"] = self._caller
+ self._parameters["use_iterator_for_get_pages"] = self._use_iterator_for_get_pages
+ self._parameters["smart_flow"] = self._smart_flow_enabled
+
+ # Smart flow limiter is initialized to None here; subclasses create the
+ # appropriate sync or async variant when smart_flow is enabled.
+ self._smart_flow = None
+
+ if self._logger:
+ self._logger.info(f"Meraki dashboard API session initialized with these parameters: {self._parameters}")
+
+ # ------------------------------------------------------------------
+ # Abstract methods (subclass contract)
+ # ------------------------------------------------------------------
+
+ @abstractmethod
+ def _send_request(self, method: str, url: str, **kwargs: Any) -> "httpx.Response":
+ """Send the HTTP request. Implemented by sync/async subclasses."""
+ ...
+
+ @abstractmethod
+ def _sleep(self, seconds: float) -> None:
+ """Sleep for the given duration. Sync uses time.sleep, async uses asyncio.sleep."""
+ ...
+
+ @abstractmethod
+ def _transport_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
+ """Prepare transport-specific kwargs (verify, proxy, timeout, etc.)."""
+ ...
+
+ # ------------------------------------------------------------------
+ # Template method: request
+ # ------------------------------------------------------------------
+
+ def request(self, metadata: Dict[str, Any], method: str, url: str, **kwargs: Any) -> Optional["httpx.Response"]:
+ """Execute an API request with retry loop and status dispatch.
+
+ Args:
+ metadata: Endpoint metadata (tags, operation, optional page counter).
+ method: HTTP method (GET, POST, PUT, DELETE).
+ url: Endpoint URL (relative or absolute).
+ **kwargs: Additional request kwargs (json, params, etc.).
+
+ Returns:
+ httpx.Response on success, or None if simulated.
+ """
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+
+ # Prepare transport-specific kwargs
+ kwargs = self._transport_kwargs(kwargs)
+
+ # Resolve absolute URL
+ abs_url = validate_base_url(self, url)
+
+ # Simulate non-GET calls
+ if self._logger:
+ self._logger.debug(metadata)
+ if self._simulate and method != "GET":
+ if self._logger:
+ self._logger.info(f"{tag}, {operation} - SIMULATED")
+ return None
+
+ retries = self._maximum_retries
+ response: Optional["httpx.Response"] = None
+
+ while retries > 0:
+ # Per-org rate limiting (proactive throttle before sending)
+ if self._smart_flow:
+ self._smart_flow.acquire(abs_url)
+
+ # Attempt the request
+ try:
+ if self._logger:
+ self._logger.info(f"{method} {abs_url}")
+ response = self._send_request(method, abs_url, **kwargs)
+ except httpx.HTTPError as e:
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {e}, retrying in 1 second")
+ self._sleep(1)
+ retries -= 1
+ if retries == 0:
+ raise APIError(
+ metadata,
+ APIResponseError(e.__class__.__name__, 503, str(e)),
+ )
+ continue
+
+ status = response.status_code
+
+ # Dispatch by status code
+ if 300 <= status < 400:
+ abs_url = self._handle_redirect(response)
+ elif 200 <= status < 300:
+ if self._smart_flow:
+ self._smart_flow.on_success(abs_url)
+ result = self._handle_success(response, metadata, method, retries)
+ if result is None:
+ # JSON decode failure, retry
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ self._sleep(1)
+ continue
+ if self._smart_flow and method == "GET" and result.content.strip():
+ try:
+ self._smart_flow.learn_from_response(abs_url, result.json())
+ except (ValueError, AttributeError):
+ pass
+ return result
+ elif status == 429:
+ if self._smart_flow:
+ self._smart_flow.on_rate_limited(abs_url)
+ wait = self._handle_rate_limit(response, metadata, retries)
+ self._sleep(wait)
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ elif status >= 500:
+ self._handle_server_error(response, metadata)
+ self._sleep(1)
+ retries -= 1
+ if retries == 0:
+ self._log_server_error_exhausted(response, metadata)
+ raise APIError(metadata, response)
+ elif 400 <= status < 500:
+ retries = self._handle_client_error(response, metadata, retries)
+
+ return response
+
+ # ------------------------------------------------------------------
+ # Status handlers (each kept under cyclomatic complexity 10)
+ # ------------------------------------------------------------------
+
+ def _handle_success(
+ self,
+ response: "httpx.Response",
+ metadata: Dict[str, Any],
+ method: str,
+ retries: int,
+ ) -> Optional["httpx.Response"]:
+ """Handle 2xx responses. Returns response or None if JSON validation fails."""
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if hasattr(response, "reason_phrase") else ""
+ status = response.status_code
+
+ if "page" in metadata:
+ counter = metadata["page"]
+ if self._logger:
+ self._logger.info(f"{tag}, {operation}; page {counter} - {status} {reason}")
+ else:
+ if self._logger:
+ self._logger.info(f"{tag}, {operation} - {status} {reason}")
+
+ # For non-empty GET responses, validate JSON
+ try:
+ if method == "GET" and response.content.strip():
+ response.json()
+ return response
+ except (json.decoder.JSONDecodeError, ValueError):
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - JSON decode error, retrying in 1 second")
+ return None
+
+ def _handle_redirect(self, response: "httpx.Response") -> str:
+ """Handle 3xx redirects. Returns the new absolute URL."""
+ return handle_3xx(self, response)
+
+ def _handle_rate_limit(
+ self,
+ response: "httpx.Response",
+ metadata: Dict[str, Any],
+ retries: int,
+ ) -> float:
+ """Handle 429 rate limiting. Returns seconds to wait.
+
+ Raises APIError if rate limit retries disabled or retries exhausted.
+ """
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if hasattr(response, "reason_phrase") else ""
+ status = response.status_code
+
+ if not self._wait_on_rate_limit or retries <= 0:
+ raise APIError(metadata, response)
+
+ if "Retry-After" in response.headers:
+ wait = int(response.headers["Retry-After"])
+ else:
+ attempt = self._maximum_retries - retries
+ wait = min(
+ (2**attempt) * (1 + random.random()),
+ self._nginx_429_retry_wait_time,
+ )
+
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
+ return wait
+
+ def _handle_server_error(self, response: "httpx.Response", metadata: Dict[str, Any]) -> None:
+ """Handle 5xx server errors. Logs warning (with Meraki X-Request-Id) before retry."""
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if hasattr(response, "reason_phrase") else ""
+ status = response.status_code
+ request_id = response.headers.get("X-Request-Id") or "none"
+
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason} (X-Request-Id: {request_id}), retrying in 1 second")
+
+ def _log_server_error_exhausted(self, response: "httpx.Response", metadata: Dict[str, Any]) -> None:
+ """Log at error level once 5xx retries are exhausted, surfacing the X-Request-Id for Meraki log lookup."""
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if hasattr(response, "reason_phrase") else ""
+ status = response.status_code
+ request_id = response.headers.get("X-Request-Id") or "none"
+
+ if self._logger:
+ self._logger.error(
+ f"{tag}, {operation} - {status} {reason} failed after retries. "
+ f"Provide this X-Request-Id to Meraki for log lookup: {request_id}"
+ )
+
+ def _handle_client_error(
+ self,
+ response: "httpx.Response",
+ metadata: Dict[str, Any],
+ retries: int,
+ ) -> int:
+ """Handle 4xx client errors. Returns updated retry count.
+
+ Raises APIError if error is not retryable or retries exhausted.
+ """
+ # Parse response body
+ try:
+ message = response.json()
+ except (ValueError, json.decoder.JSONDecodeError):
+ message = response.content[:100]
+
+ # Determine wait time based on error type
+ wait = self._classify_client_error_wait(metadata, response, message)
+
+ if wait is not None:
+ return self._retry_with_wait(wait, metadata, response, retries)
+
+ # Non-retryable client error
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if hasattr(response, "reason_phrase") else ""
+ status = response.status_code
+ if self._logger:
+ self._logger.error(f"{tag}, {operation} - {status} {reason}, {message}")
+ raise APIError(metadata, response)
+
+ # ------------------------------------------------------------------
+ # Helper methods
+ # ------------------------------------------------------------------
+
+ def _classify_client_error_wait(
+ self,
+ metadata: Dict[str, Any],
+ response: "httpx.Response",
+ message: Any,
+ ) -> Optional[float]:
+ """Determine retry wait time for a 4xx error, or None if non-retryable."""
+ if self._is_network_delete_concurrency(metadata, response, message):
+ return float(random.randint(30, self._network_delete_retry_wait_time))
+ if self._is_action_batch_concurrency(message):
+ return float(self._action_batch_retry_wait_time)
+ if self._retry_4xx_error:
+ return float(random.randint(1, self._retry_4xx_error_wait_time))
+ return None
+
+ def _retry_with_wait(
+ self,
+ wait: float,
+ metadata: Dict[str, Any],
+ response: "httpx.Response",
+ retries: int,
+ ) -> int:
+ """Log, sleep, decrement retries; raise APIError if exhausted."""
+ tag = metadata["tags"][0]
+ operation = metadata["operation"]
+ reason = response.reason_phrase if hasattr(response, "reason_phrase") else ""
+ status = response.status_code
+
+ if self._logger:
+ self._logger.warning(f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds")
+ self._sleep(wait)
+ retries -= 1
+ if retries == 0:
+ raise APIError(metadata, response)
+ return retries
+
+ def _is_network_delete_concurrency(
+ self,
+ metadata: Dict[str, Any],
+ response: "httpx.Response",
+ message: Any,
+ ) -> bool:
+ """Check if error is a network delete concurrency conflict."""
+ if metadata.get("operation") != "deleteNetwork":
+ return False
+ if response.status_code != 400:
+ return False
+ if isinstance(message, dict) and "errors" in message:
+ return "concurrent" in str(message["errors"][0])
+ return False
+
+ def _is_action_batch_concurrency(self, message: Any) -> bool:
+ """Check if error is an action batch concurrency conflict."""
+ if isinstance(message, dict) and "errors" in message:
+ return "executing batches" in str(message["errors"][0]).lower()
+ return False
+
+ def _build_headers(self) -> Dict[str, str]:
+ """Build standard request headers."""
+ headers = {
+ "Authorization": "Bearer " + self._api_key,
+ "Content-Type": "application/json",
+ "User-Agent": f"python-meraki/{self._version} " + validate_user_agent(self._be_geo_id, self._caller),
+ }
+ if self._meraki_app_id:
+ headers["X-MerakiApp"] = self._meraki_app_id
+ if self._meraki_app_bearer_token:
+ headers["X-MerakiApp-Authorization"] = "Bearer " + self._meraki_app_bearer_token
+ return headers
diff --git a/meraki/session/sync.py b/meraki/session/sync.py
new file mode 100644
index 00000000..b8eb5d27
--- /dev/null
+++ b/meraki/session/sync.py
@@ -0,0 +1,405 @@
+"""Synchronous REST session for Meraki Dashboard API."""
+
+from __future__ import annotations
+
+import time
+import urllib.parse
+from datetime import datetime, timezone
+from typing import Any, Dict, Optional
+
+import httpx
+
+from meraki.common import (
+ iterator_for_get_pages_bool,
+ use_iterator_for_get_pages_setter,
+)
+from meraki.exceptions import SessionInputError
+from meraki.smart_flow import OrgRateLimiter
+from meraki.session.base import SessionBase, apply_meraki_param_encoding
+
+
+class RestSession(SessionBase):
+ """Synchronous session using httpx.Client.
+
+ Inherits config, retry loop, and status dispatch from SessionBase.
+ Implements transport-specific sleep and request methods.
+ """
+
+ def __init__(self, logger, api_key, **kwargs: Any) -> None:
+ super().__init__(logger, api_key, **kwargs)
+
+ # Build client config from session config (per D-06: requests_proxy -> proxy kwarg)
+ client_kwargs: Dict[str, Any] = {
+ "timeout": self._single_request_timeout,
+ }
+ if self._certificate_path:
+ client_kwargs["verify"] = self._certificate_path
+ if self._requests_proxy:
+ client_kwargs["proxy"] = self._requests_proxy
+
+ # Persistent httpx client with connection pooling
+ self._client = httpx.Client(**client_kwargs)
+ self._client.headers.update(self._build_headers())
+
+ # Per-org smart flow (opt-in)
+ if self._smart_flow_enabled:
+ self._smart_flow = OrgRateLimiter(
+ rate=self._smart_flow_org_rate,
+ capacity=int(self._smart_flow_org_rate),
+ global_rate=self._smart_flow_global_rate,
+ cache_path=self._smart_flow_cache_path or None,
+ cache_ttl=self._smart_flow_cache_ttl,
+ logger=self._logger if self._smart_flow_logging else None,
+ )
+ self._smart_flow.set_resolver(self._resolve_org_for_limiter)
+ self._smart_flow.set_hydrator(self._hydrate_org_for_limiter)
+
+ def close(self):
+ """Close the underlying httpx.Client and release connections."""
+ self._client.close()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ @property
+ def use_iterator_for_get_pages(self):
+ return iterator_for_get_pages_bool(self)
+
+ @use_iterator_for_get_pages.setter
+ def use_iterator_for_get_pages(self, value):
+ use_iterator_for_get_pages_setter(self, value)
+
+ def _send_request(self, method: str, url: str, **kwargs: Any) -> httpx.Response:
+ """Send HTTP request via persistent httpx.Client."""
+ # Pre-encode Meraki array-of-objects params; httpx mishandles them.
+ url = apply_meraki_param_encoding(url, kwargs)
+ response = self._client.request(method, url, follow_redirects=False, **kwargs)
+ return response
+
+ def _sleep(self, seconds: float) -> None:
+ """Blocking sleep for retry delays."""
+ time.sleep(seconds)
+
+ def _transport_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
+ """No-op: httpx config handled at client initialization level."""
+ return kwargs
+
+ # ------------------------------------------------------------------
+ # Smart flow resolver
+ # ------------------------------------------------------------------
+
+ def _acquire_global_bucket(self) -> None:
+ """Gate internal hydration/resolution traffic on the global bucket.
+
+ These internal GETs bypass self.request() to avoid resolver reentrancy,
+ but must still account against the global (source IP) bucket they help
+ populate. Defensive: no-op if smart flow or the bucket is unavailable.
+ """
+ if not self._smart_flow:
+ return
+ bucket = getattr(self._smart_flow, "_global_bucket", None)
+ if bucket is not None:
+ bucket.acquire()
+
+ def _resolve_org_for_limiter(self, id_type: str, identifier: str) -> Optional[str]:
+ """Resolve a network/device ID to its org by calling the API directly."""
+ if id_type == "network":
+ endpoint = f"{self._base_url}/networks/{identifier}"
+ else:
+ endpoint = f"{self._base_url}/devices/{identifier}"
+ try:
+ self._acquire_global_bucket()
+ response = self._client.request("GET", endpoint, follow_redirects=True)
+ if response.status_code == 200:
+ data = response.json()
+ return data.get("organizationId")
+ except Exception:
+ pass
+ return None
+
+ def _hydrate_org_for_limiter(self, org_id: str) -> None:
+ """Fetch all networks and devices for an org and register them with the limiter."""
+ networks = self._fetch_all_pages(f"{self._base_url}/organizations/{org_id}/networks?perPage=1000")
+ for net in networks:
+ if "id" in net:
+ self._smart_flow.register_network(net["id"], org_id)
+
+ devices = self._fetch_all_pages(f"{self._base_url}/organizations/{org_id}/inventoryDevices?perPage=1000")
+ for dev in devices:
+ if "serial" in dev:
+ self._smart_flow.register_device(dev["serial"], org_id)
+
+ def _fetch_all_pages(self, url: str) -> list:
+ """Paginate through a Meraki list endpoint using Link headers."""
+ results = []
+ while url:
+ self._acquire_global_bucket()
+ response = self._client.request("GET", url, follow_redirects=True)
+ if response.status_code != 200:
+ break
+ page = response.json()
+ if isinstance(page, list):
+ results.extend(page)
+ next_link = response.links.get("next", {}).get("url")
+ url = next_link if next_link else None
+ return results
+
+ # ------------------------------------------------------------------
+ # Convenience HTTP methods
+ # ------------------------------------------------------------------
+
+ def get(self, metadata, url, params=None):
+ metadata["method"] = "GET"
+ metadata["url"] = url
+ metadata["params"] = params
+ response = self.request(metadata, "GET", url, params=params)
+ ret = None
+ if response:
+ if response.content.strip():
+ ret = response.json()
+ response.close()
+ return ret
+
+ def post(self, metadata, url, json=None):
+ metadata["method"] = "POST"
+ metadata["url"] = url
+ metadata["json"] = json
+ response = self.request(metadata, "POST", url, json=json)
+ ret = None
+ if response:
+ if response.content.strip():
+ ret = response.json()
+ response.close()
+ return ret
+
+ def put(self, metadata, url, json=None):
+ metadata["method"] = "PUT"
+ metadata["url"] = url
+ metadata["json"] = json
+ response = self.request(metadata, "PUT", url, json=json)
+ ret = None
+ if response:
+ if response.content.strip():
+ ret = response.json()
+ response.close()
+ return ret
+
+ def patch(self, metadata, url, json=None):
+ metadata["method"] = "PATCH"
+ metadata["url"] = url
+ metadata["json"] = json
+ response = self.request(metadata, "PATCH", url, json=json)
+ ret = None
+ if response:
+ if response.content.strip():
+ ret = response.json()
+ response.close()
+ return ret
+
+ def delete(self, metadata, url, params=None):
+ metadata["method"] = "DELETE"
+ metadata["url"] = url
+ metadata["params"] = params
+ response = self.request(metadata, "DELETE", url, params=params)
+ if response:
+ response.close()
+ return None
+
+ # ------------------------------------------------------------------
+ # Pagination
+ # ------------------------------------------------------------------
+
+ def get_pages(self, metadata, url, params=None, total_pages=-1, direction="next", event_log_end_time=None):
+ """Dispatch to iterator or legacy pagination based on config."""
+ if self._use_iterator_for_get_pages:
+ return self._get_pages_iterator(metadata, url, params, total_pages, direction, event_log_end_time)
+ return self._get_pages_legacy(metadata, url, params, total_pages, direction, event_log_end_time)
+
+ def _get_pages_iterator(
+ self,
+ metadata,
+ url,
+ params=None,
+ total_pages=-1,
+ direction="next",
+ event_log_end_time=None,
+ ):
+ if isinstance(total_pages, str) and total_pages.lower() == "all":
+ total_pages = -1
+ elif isinstance(total_pages, str) and total_pages.isnumeric():
+ total_pages = int(total_pages)
+ elif not isinstance(total_pages, int):
+ raise SessionInputError(
+ "total_pages",
+ total_pages,
+ "total_pages must be either an integer or 'all' as a string (remember to add the quotation marks).",
+ None,
+ )
+ metadata["page"] = 1
+
+ response = self.request(metadata, "GET", url, params=params)
+
+ # Get additional pages if more than one requested
+ while total_pages != 0:
+ # Guard against 204 No Content pages (empty body -> stop cleanly),
+ # matching the legacy paginator's behavior.
+ if response.status_code == 204:
+ response.close()
+ return
+ results = response.json()
+ links = response.links
+
+ # GET the subsequent page
+ if direction == "next" and "next" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes forward
+ if metadata["operation"] == "getNetworkEvents":
+ starting_after = urllib.parse.unquote(str(links["next"]["url"]).split("startingAfter=")[1])
+ delta = datetime.now(timezone.utc) - datetime.fromisoformat(starting_after)
+ # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
+ if delta.total_seconds() < 300:
+ break
+ # Or if the next page is past the specified window's end time
+ elif event_log_end_time and starting_after > event_log_end_time:
+ break
+
+ metadata["page"] += 1
+ nextlink = links["next"]["url"]
+ elif direction == "prev" and "prev" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
+ if metadata["operation"] == "getNetworkEvents":
+ ending_before = urllib.parse.unquote(str(links["prev"]["url"]).split("endingBefore=")[1])
+ # Break out of loop if endingBefore returned from prev link is before 2014
+ if ending_before < "2014-01-01":
+ break
+
+ metadata["page"] += 1
+ nextlink = links["prev"]["url"]
+ else:
+ total_pages = 1
+
+ response.close()
+
+ return_items = []
+ # Just prepare the list
+ if isinstance(results, list):
+ return_items = results
+ elif isinstance(results, dict) and "items" in results:
+ return_items = results["items"]
+ # For event log endpoint
+ elif isinstance(results, dict):
+ if direction == "next":
+ return_items = results["events"][::-1]
+ else:
+ return_items = results["events"]
+
+ for item in return_items:
+ yield item
+
+ total_pages = total_pages - 1
+
+ if total_pages != 0:
+ response = self.request(metadata, "GET", nextlink)
+
+ def _get_pages_legacy(
+ self,
+ metadata,
+ url,
+ params=None,
+ total_pages=-1,
+ direction="next",
+ event_log_end_time=None,
+ ):
+ if isinstance(total_pages, str) and total_pages.lower() == "all":
+ total_pages = -1
+ elif isinstance(total_pages, str) and total_pages.isnumeric():
+ total_pages = int(total_pages)
+ elif not isinstance(total_pages, int):
+ raise SessionInputError(
+ "total_pages",
+ total_pages,
+ "total_pages must be either an integer or 'all' as a string (remember to add the quotation marks).",
+ None,
+ )
+
+ metadata["page"] = 1
+
+ response = self.request(metadata, "GET", url, params=params)
+
+ # Handle GETs that produce 204 No Content responses
+ if response.status_code == 204:
+ results = None
+ else:
+ results = response.json()
+
+ # For event log endpoint when using 'next' direction, so results/events are sorted chronologically
+ if isinstance(results, dict) and metadata["operation"] == "getNetworkEvents" and direction == "next":
+ results["events"] = results["events"][::-1]
+
+ # Get additional pages if more than one requested
+ while total_pages != 1:
+ links = response.links
+ response.close()
+ response = None
+
+ # GET the subsequent page
+ if direction == "next" and "next" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes forward
+ if metadata["operation"] == "getNetworkEvents":
+ starting_after = urllib.parse.unquote(links["next"]["url"].split("startingAfter=")[1])
+ delta = datetime.now(timezone.utc) - datetime.fromisoformat(starting_after)
+ # Break out of loop if startingAfter returned from next link is within 5 minutes of current time
+ if delta.total_seconds() < 300:
+ break
+ # Or if next page is past the specified window's end time
+ elif event_log_end_time and starting_after > event_log_end_time:
+ break
+
+ metadata["page"] += 1
+ response = self.request(metadata, "GET", links["next"]["url"])
+ elif direction == "prev" and "prev" in links:
+ # Prevent getNetworkEvents from infinite loop as time goes backward (to epoch 0)
+ if metadata["operation"] == "getNetworkEvents":
+ ending_before = urllib.parse.unquote(links["prev"]["url"].split("endingBefore=")[1])
+ # Break out of loop if endingBefore returned from prev link is before 2014
+ if ending_before < "2014-01-01":
+ break
+
+ metadata["page"] += 1
+ response = self.request(metadata, "GET", links["prev"]["url"])
+ else:
+ break
+
+ # Append that page's results, depending on the endpoint
+ if isinstance(results, list):
+ results.extend(response.json())
+ elif isinstance(results, dict) and "items" in results:
+ results["items"].extend(response.json()["items"])
+ if "meta" in results:
+ results["meta"]["counts"]["items"]["remaining"] = response.json()["meta"]["counts"]["items"]["remaining"]
+ # For event log endpoint
+ elif isinstance(results, dict):
+ try:
+ start = response.json()["pageStartAt"]
+ except KeyError:
+ if self._logger:
+ self._logger.warning(f"pageStartAt missing from response: {response.headers}")
+ start = results["pageStartAt"] # fallback: keep existing value
+ end = response.json()["pageEndAt"]
+ events = response.json()["events"]
+ if direction == "next":
+ events = events[::-1]
+ if start < results["pageStartAt"]:
+ results["pageStartAt"] = start
+ if end > results["pageEndAt"]:
+ results["pageEndAt"] = end
+ results["events"].extend(events)
+
+ total_pages -= 1
+
+ if response:
+ response.close()
+
+ return results
diff --git a/meraki/smart_flow.py b/meraki/smart_flow.py
new file mode 100644
index 00000000..56ad5f13
--- /dev/null
+++ b/meraki/smart_flow.py
@@ -0,0 +1,754 @@
+"""Per-org token bucket rate limiter for Meraki Dashboard API (smart flow).
+
+The Meraki API enforces rate limits per organization (default 10 req/s). This module
+provides proactive rate limiting that prevents 429 errors before they happen by
+tracking request rates per org and throttling when approaching the limit.
+
+Key concepts:
+- URL patterns are parsed to extract org/network/device identifiers
+- A lazy cache maps network IDs and device serials to their parent org ID
+- Each org gets its own token bucket, refilling at the configured rate
+- Unknown identifiers route through a conservative shared bucket until resolved
+"""
+
+from __future__ import annotations
+
+import asyncio
+import re
+import threading
+import time
+from datetime import datetime, timezone
+from pathlib import Path
+from typing import Any, Callable, Coroutine, Dict, Optional, Set
+
+import json
+
+
+# URL patterns for extracting resource identifiers
+_ORG_PATTERN = re.compile(r"/organizations/([^/]+)")
+_NETWORK_PATTERN = re.compile(r"/networks/([^/]+)")
+_DEVICE_PATTERN = re.compile(r"/devices/([^/]+)")
+
+
+def _parse_saved_at(value: Any) -> Optional[float]:
+ """Parse ISO 8601Z saved_at timestamp to epoch seconds."""
+ if not isinstance(value, str):
+ return None
+ try:
+ dt = datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
+ return dt.timestamp()
+ except ValueError:
+ return None
+
+
+class TokenBucket:
+ """Thread-safe token bucket for synchronous rate limiting."""
+
+ def __init__(self, rate: float, capacity: int):
+ self._rate = rate
+ self._capacity = capacity
+ self._tokens = float(capacity)
+ self._last = time.monotonic()
+ self._lock = threading.Lock()
+
+ @property
+ def rate(self) -> float:
+ return self._rate
+
+ @rate.setter
+ def rate(self, value: float) -> None:
+ self._rate = max(0.5, value)
+
+ def acquire(self) -> None:
+ # Reserve the token (read-modify-write) under the lock, then sleep
+ # outside it so concurrent callers don't serialize behind one sleeper.
+ with self._lock:
+ now = time.monotonic()
+ # Refill, then deduct this request unconditionally. Tokens may go
+ # negative: that deficit IS the reservation, so concurrent callers
+ # each compute their own wait against the accumulated deficit rather
+ # than all colliding on the same instant.
+ elapsed = now - self._last
+ self._tokens = min(self._capacity, self._tokens + elapsed * self._rate)
+ self._last = now
+ self._tokens -= 1.0
+
+ wait = -self._tokens / self._rate if self._tokens < 0 else 0.0
+
+ if wait > 0.0:
+ time.sleep(wait)
+
+
+class AsyncTokenBucket:
+ """Async token bucket for asynchronous rate limiting."""
+
+ def __init__(self, rate: float, capacity: int):
+ self._rate = rate
+ self._capacity = capacity
+ self._tokens = float(capacity)
+ self._last: Optional[float] = None
+ self._lock = asyncio.Lock()
+
+ @property
+ def rate(self) -> float:
+ return self._rate
+
+ @rate.setter
+ def rate(self, value: float) -> None:
+ self._rate = max(0.5, value)
+
+ async def acquire(self) -> None:
+ # Reserve the token under the lock, then await the sleep OUTSIDE the
+ # lock so concurrent coroutines on the same bucket aren't serialized
+ # behind a single sleeper (preserving burst/parallelism).
+ loop = asyncio.get_event_loop()
+ async with self._lock:
+ now = loop.time()
+ if self._last is None:
+ self._last = now
+
+ # Refill, then deduct this request unconditionally. Tokens may go
+ # negative: that deficit IS the reservation, so concurrent callers
+ # each compute their own wait against the accumulated deficit rather
+ # than all colliding on the same instant.
+ elapsed = now - self._last
+ self._tokens = min(self._capacity, self._tokens + elapsed * self._rate)
+ self._last = now
+ self._tokens -= 1.0
+
+ wait = -self._tokens / self._rate if self._tokens < 0 else 0.0
+
+ if wait > 0.0:
+ await asyncio.sleep(wait)
+
+
+class OrgRateLimiter:
+ """Per-org rate limiter with URL-based routing and org resolution cache.
+
+ Maintains a token bucket per organization and a shared "unknown" bucket for
+ requests whose org cannot yet be determined. The cache maps network IDs and
+ device serials to org IDs, populated eagerly at init or lazily from responses.
+ """
+
+ def __init__(
+ self,
+ rate: float = 10.0,
+ capacity: int = 10,
+ global_rate: float = 100.0,
+ cache_path: Optional[str] = None,
+ cache_ttl: Optional[float] = 604800.0,
+ logger: Any = None,
+ ):
+ self._rate = rate
+ self._capacity = capacity
+ self._global_rate = global_rate
+ self._logger = logger
+ self._cache_path = Path(cache_path) if cache_path else None
+ self._cache_ttl = cache_ttl
+
+ # org_id -> bucket
+ self._org_buckets: Dict[str, TokenBucket] = {}
+ # network_id -> org_id, serial -> org_id
+ self._network_to_org: Dict[str, str] = {}
+ self._serial_to_org: Dict[str, str] = {}
+ # Global bucket: source IP limit shared by all requests
+ self._global_bucket = TokenBucket(rate=global_rate, capacity=int(global_rate))
+
+ self._cache_fresh = False
+ self._dirty = 0
+ self._pending_lookups: Set[str] = set()
+ self._hydrated_orgs: Set[str] = set()
+ self._resolver: Optional[Callable[[str, str], Optional[str]]] = None
+ self._hydrator: Optional[Callable[[str], None]] = None
+ self._load_cache()
+
+ def set_resolver(self, resolver: Callable[[str, str], Optional[str]]) -> None:
+ """Set a callback to resolve unknown network/device IDs to org IDs.
+
+ The callback receives (id_type, identifier) where id_type is "network" or "device",
+ and should return the org_id or None.
+ """
+ self._resolver = resolver
+
+ def set_hydrator(self, hydrator: Callable[[str], None]) -> None:
+ """Set a callback to bulk-populate all networks/devices for an org.
+
+ Called once per org after first resolution. The callback should call
+ register_network/register_device for each mapping discovered.
+ """
+ self._hydrator = hydrator
+
+ @property
+ def cache_fresh(self) -> bool:
+ return self._cache_fresh
+
+ def _log(self, msg: str) -> None:
+ if self._logger:
+ self._logger.debug(f"smart_flow, {msg}")
+
+ def _maybe_flush(self) -> None:
+ if self._dirty >= 50:
+ self.save_cache()
+ self._dirty = 0
+
+ def _get_or_create_bucket(self, org_id: str) -> TokenBucket:
+ if org_id not in self._org_buckets:
+ self._org_buckets[org_id] = TokenBucket(self._rate, self._capacity)
+ self._log(f"new bucket for org {org_id} at {self._rate} req/s")
+ return self._org_buckets[org_id]
+
+ def resolve_org(self, url: str) -> Optional[str]:
+ """Extract org ID from URL, using cache for network/device lookups."""
+ m = _ORG_PATTERN.search(url)
+ if m:
+ return m.group(1)
+
+ m = _NETWORK_PATTERN.search(url)
+ if m:
+ return self._network_to_org.get(m.group(1))
+
+ m = _DEVICE_PATTERN.search(url)
+ if m:
+ return self._serial_to_org.get(m.group(1))
+
+ return None
+
+ def acquire(self, url: str) -> None:
+ """Block until tokens are available from both global and per-org buckets."""
+ self._global_bucket.acquire()
+
+ org_id = self.resolve_org(url)
+ if org_id:
+ self._get_or_create_bucket(org_id).acquire()
+ else:
+ self._resolve_inline(url)
+ org_id = self.resolve_org(url)
+ if org_id:
+ self._get_or_create_bucket(org_id).acquire()
+
+ def _resolve_inline(self, url: str) -> None:
+ """Attempt a synchronous lookup for an unresolved network/device ID."""
+ if not self._resolver:
+ return
+
+ m = _NETWORK_PATTERN.search(url)
+ if m:
+ identifier, id_type = m.group(1), "network"
+ else:
+ m = _DEVICE_PATTERN.search(url)
+ if m:
+ identifier, id_type = m.group(1), "device"
+ else:
+ return
+
+ if identifier in self._pending_lookups:
+ return
+ self._pending_lookups.add(identifier)
+ try:
+ org_id = self._resolver(id_type, identifier)
+ if org_id:
+ if id_type == "network":
+ self._network_to_org[identifier] = org_id
+ else:
+ self._serial_to_org[identifier] = org_id
+ self._get_or_create_bucket(org_id)
+ self._dirty += 1
+ self._log(f"resolved {id_type} {identifier} -> org {org_id}")
+ if self._hydrator and org_id not in self._hydrated_orgs:
+ self._hydrated_orgs.add(org_id)
+ self._log(f"hydrating org {org_id}")
+ self._hydrator(org_id)
+ self._log(
+ f"hydrated org {org_id} "
+ f"({len(self._network_to_org)} networks, {len(self._serial_to_org)} devices total)"
+ )
+ self._maybe_flush()
+ except Exception:
+ pass
+ finally:
+ self._pending_lookups.discard(identifier)
+
+ def on_rate_limited(self, url: str) -> None:
+ """Tighten the appropriate bucket (multiplicative decrease)."""
+ org_id = self.resolve_org(url)
+ if org_id and org_id in self._org_buckets:
+ bucket = self._org_buckets[org_id]
+ bucket.rate = bucket.rate * 0.7
+ self._log(f"rate limited org {org_id}, decreased to {bucket.rate:.1f} req/s")
+ elif self._is_unresolved_scoped_url(url):
+ # URL targets a specific network/device whose org isn't resolved
+ # yet. Penalizing the global bucket would punish every other org for
+ # one org's 429, so skip and let background resolution catch up.
+ self._log("rate limited on unresolved network/device url, skipping global penalty")
+ else:
+ self._global_bucket.rate = self._global_bucket.rate * 0.7
+ self._log(f"rate limited (global), decreased to {self._global_bucket.rate:.1f} req/s")
+
+ @staticmethod
+ def _is_unresolved_scoped_url(url: str) -> bool:
+ """True if the URL has a network/device component but no explicit org.
+
+ These are the URLs whose org we can't yet attribute the 429 to; the
+ offending org is specific (just unknown), so the global bucket must not
+ be punished on its behalf. An explicit /organizations/ URL is NOT
+ considered unresolved (it names its org directly).
+ """
+ if OrgRateLimiter._org_id_from_url(url):
+ return False
+ return bool(OrgRateLimiter._network_id_from_url(url) or OrgRateLimiter._serial_from_url(url))
+
+ def on_success(self, url: str) -> None:
+ """Slowly widen buckets back toward configured rates (additive increase)."""
+ org_id = self.resolve_org(url)
+ if org_id and org_id in self._org_buckets:
+ bucket = self._org_buckets[org_id]
+ if bucket.rate < self._rate:
+ bucket.rate = min(self._rate, bucket.rate + 0.2)
+ if self._global_bucket.rate < self._global_rate:
+ self._global_bucket.rate = min(self._global_rate, self._global_bucket.rate + 0.5)
+
+ def register_org(self, org_id: str) -> None:
+ """Ensure a bucket exists for this org."""
+ self._get_or_create_bucket(org_id)
+
+ def register_network(self, network_id: str, org_id: str) -> None:
+ """Cache a network -> org mapping."""
+ self._network_to_org[network_id] = org_id
+
+ def register_device(self, serial: str, org_id: str) -> None:
+ """Cache a serial -> org mapping."""
+ self._serial_to_org[serial] = org_id
+
+ def learn_from_response(self, url: str, body: Any) -> None:
+ """Extract org/network/device mappings from a URL and response body."""
+ org_id = self._org_id_from_url(url)
+ if not org_id:
+ org_id = self._org_id_from_body(body)
+ if not org_id:
+ return
+
+ self._get_or_create_bucket(org_id)
+ changed_networks = 0
+ changed_devices = 0
+
+ network_id = self._network_id_from_url(url)
+ if network_id and self._network_to_org.get(network_id) != org_id:
+ self._network_to_org[network_id] = org_id
+ changed_networks += 1
+
+ serial = self._serial_from_url(url)
+ if serial and self._serial_to_org.get(serial) != org_id:
+ self._serial_to_org[serial] = org_id
+ changed_devices += 1
+
+ if isinstance(body, dict):
+ n, d = self._learn_from_body(body, org_id)
+ changed_networks += n
+ changed_devices += d
+
+ total = changed_networks + changed_devices
+ if total:
+ self._dirty += total
+ if self._logger:
+ self._log(
+ f"learned {total} new mapping{'s' if total != 1 else ''} "
+ f"({changed_networks} network{'s' if changed_networks != 1 else ''}, "
+ f"{changed_devices} device{'s' if changed_devices != 1 else ''}) "
+ f"from {url}"
+ )
+ self._maybe_flush()
+
+ def _learn_from_body(self, body: dict, org_id: str) -> tuple:
+ """Returns (changed_networks, changed_devices) counts."""
+ changed_networks = 0
+ changed_devices = 0
+ if "networkId" in body and self._network_to_org.get(body["networkId"]) != org_id:
+ self._network_to_org[body["networkId"]] = org_id
+ changed_networks += 1
+ if "serial" in body and self._serial_to_org.get(body["serial"]) != org_id:
+ self._serial_to_org[body["serial"]] = org_id
+ changed_devices += 1
+ net = body.get("network")
+ if isinstance(net, dict) and "id" in net:
+ if self._network_to_org.get(net["id"]) != org_id:
+ self._network_to_org[net["id"]] = org_id
+ changed_networks += 1
+ return changed_networks, changed_devices
+
+ @staticmethod
+ def _org_id_from_url(url: str) -> Optional[str]:
+ m = _ORG_PATTERN.search(url)
+ return m.group(1) if m else None
+
+ @staticmethod
+ def _network_id_from_url(url: str) -> Optional[str]:
+ m = _NETWORK_PATTERN.search(url)
+ return m.group(1) if m else None
+
+ @staticmethod
+ def _serial_from_url(url: str) -> Optional[str]:
+ m = _DEVICE_PATTERN.search(url)
+ return m.group(1) if m else None
+
+ @staticmethod
+ def _org_id_from_body(body: Any) -> Optional[str]:
+ if not isinstance(body, dict):
+ return None
+ if "organizationId" in body:
+ return body["organizationId"]
+ org = body.get("organization")
+ if isinstance(org, dict) and "id" in org:
+ return org["id"]
+ return None
+
+ def save_cache(self) -> None:
+ """Persist the mapping cache to disk with a timestamp."""
+ if not self._cache_path:
+ return
+ self._cache_path.parent.mkdir(parents=True, exist_ok=True)
+ data = {
+ "saved_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
+ "networks": [{"id": net_id, "organization": {"id": org_id}} for net_id, org_id in self._network_to_org.items()],
+ "devices": [{"serial": serial, "organization": {"id": org_id}} for serial, org_id in self._serial_to_org.items()],
+ }
+ self._cache_path.write_text(json.dumps(data), encoding="utf-8")
+ n = len(self._network_to_org) + len(self._serial_to_org)
+ self._log(f"saved cache ({n} mappings) to {self._cache_path}")
+
+ def _load_cache(self) -> None:
+ """Load mapping cache from disk if it exists and hasn't expired."""
+ if not self._cache_path or not self._cache_path.exists():
+ return
+ try:
+ data = json.loads(self._cache_path.read_text(encoding="utf-8"))
+ if self._cache_ttl is not None:
+ saved_at = data.get("saved_at")
+ if saved_at is None:
+ self._log("cache expired, will rebuild")
+ return
+ saved_ts = _parse_saved_at(saved_at)
+ if saved_ts is None or (time.time() - saved_ts) > self._cache_ttl:
+ self._log("cache expired, will rebuild")
+ return
+ for net in data.get("networks", []):
+ self._network_to_org[net["id"]] = net["organization"]["id"]
+ for dev in data.get("devices", []):
+ self._serial_to_org[dev["serial"]] = dev["organization"]["id"]
+ self._cache_fresh = True
+ n = len(self._network_to_org) + len(self._serial_to_org)
+ self._log(f"loaded cache ({n} mappings) from {self._cache_path}")
+ except (json.JSONDecodeError, OSError, KeyError):
+ pass
+
+
+class AsyncOrgRateLimiter:
+ """Async per-org rate limiter with URL-based routing and org resolution cache.
+
+ Same strategy as OrgRateLimiter but uses AsyncTokenBucket for non-blocking waits.
+ """
+
+ def __init__(
+ self,
+ rate: float = 10.0,
+ capacity: int = 10,
+ global_rate: float = 100.0,
+ cache_path: Optional[str] = None,
+ cache_ttl: Optional[float] = 604800.0,
+ logger: Any = None,
+ ):
+ self._rate = rate
+ self._capacity = capacity
+ self._global_rate = global_rate
+ self._logger = logger
+ self._cache_path = Path(cache_path) if cache_path else None
+ self._cache_ttl = cache_ttl
+
+ self._org_buckets: Dict[str, AsyncTokenBucket] = {}
+ self._network_to_org: Dict[str, str] = {}
+ self._serial_to_org: Dict[str, str] = {}
+ self._global_bucket = AsyncTokenBucket(rate=global_rate, capacity=int(global_rate))
+
+ self._cache_fresh = False
+ self._dirty = 0
+ self._flush_task: Optional[asyncio.Task] = None
+ # Hold strong refs to in-flight background tasks; the event loop only
+ # keeps weak refs, so without this they can be GC'd mid-flight.
+ self._bg_tasks: Set[asyncio.Task] = set()
+ self._pending_lookups: Set[str] = set()
+ self._hydrated_orgs: Set[str] = set()
+ self._resolver: Optional[Callable[[str, str], Coroutine[Any, Any, Optional[str]]]] = None
+ self._hydrator: Optional[Callable[[str], Coroutine[Any, Any, None]]] = None
+ self._load_cache()
+
+ def set_resolver(self, resolver: Callable[[str, str], Coroutine[Any, Any, Optional[str]]]) -> None:
+ """Set a callback to resolve unknown network/device IDs to org IDs.
+
+ The callback receives (id_type, identifier) where id_type is "network" or "device",
+ and should return the org_id or None.
+ """
+ self._resolver = resolver
+
+ def set_hydrator(self, hydrator: Callable[[str], Coroutine[Any, Any, None]]) -> None:
+ """Set a callback to bulk-populate all networks/devices for an org.
+
+ Called once per org after first resolution. The callback should call
+ register_network/register_device for each mapping discovered.
+ """
+ self._hydrator = hydrator
+
+ @property
+ def cache_fresh(self) -> bool:
+ return self._cache_fresh
+
+ def _log(self, msg: str) -> None:
+ if self._logger:
+ self._logger.debug(f"smart_flow, {msg}")
+
+ def _maybe_flush(self) -> None:
+ if self._dirty >= 50 and (self._flush_task is None or self._flush_task.done()):
+ pending = self._dirty
+ self._flush_task = asyncio.ensure_future(self.save_cache())
+ self._flush_task.add_done_callback(lambda t: self._on_flush_done(t, pending))
+
+ def _on_flush_done(self, task: asyncio.Task, pending: int) -> None:
+ # Only zero the dirty counter if the save actually succeeded; otherwise
+ # the unsaved mappings would be silently lost.
+ exc = task.exception()
+ if exc is not None:
+ self._log(f"cache flush failed, retaining {pending} dirty mappings: {exc!r}")
+ return
+ # Subtract what we flushed rather than hard-zeroing, in case more
+ # mappings were learned while the save was in flight.
+ self._dirty = max(0, self._dirty - pending)
+
+ def _get_or_create_bucket(self, org_id: str) -> AsyncTokenBucket:
+ if org_id not in self._org_buckets:
+ self._org_buckets[org_id] = AsyncTokenBucket(self._rate, self._capacity)
+ self._log(f"new bucket for org {org_id} at {self._rate} req/s")
+ return self._org_buckets[org_id]
+
+ def resolve_org(self, url: str) -> Optional[str]:
+ """Extract org ID from URL, using cache for network/device lookups."""
+ m = _ORG_PATTERN.search(url)
+ if m:
+ return m.group(1)
+
+ m = _NETWORK_PATTERN.search(url)
+ if m:
+ return self._network_to_org.get(m.group(1))
+
+ m = _DEVICE_PATTERN.search(url)
+ if m:
+ return self._serial_to_org.get(m.group(1))
+
+ return None
+
+ async def acquire(self, url: str) -> None:
+ """Await until tokens from both global and per-org buckets are available."""
+ await self._global_bucket.acquire()
+
+ org_id = self.resolve_org(url)
+ if org_id:
+ await self._get_or_create_bucket(org_id).acquire()
+ else:
+ self._trigger_background_resolve(url)
+
+ def _trigger_background_resolve(self, url: str) -> None:
+ """Fire a one-shot background lookup for an unresolved network/device ID."""
+ if not self._resolver:
+ return
+
+ m = _NETWORK_PATTERN.search(url)
+ if m:
+ identifier, id_type = m.group(1), "network"
+ else:
+ m = _DEVICE_PATTERN.search(url)
+ if m:
+ identifier, id_type = m.group(1), "device"
+ else:
+ return
+
+ if identifier in self._pending_lookups:
+ return
+ self._pending_lookups.add(identifier)
+ t = asyncio.ensure_future(self._resolve_and_cache(id_type, identifier))
+ self._bg_tasks.add(t)
+ t.add_done_callback(self._bg_tasks.discard)
+
+ async def _resolve_and_cache(self, id_type: str, identifier: str) -> None:
+ """Background task: call resolver, cache result, then hydrate the full org."""
+ try:
+ org_id = await self._resolver(id_type, identifier)
+ if not org_id:
+ return
+ if id_type == "network":
+ self._network_to_org[identifier] = org_id
+ else:
+ self._serial_to_org[identifier] = org_id
+ self._get_or_create_bucket(org_id)
+ self._dirty += 1
+ self._log(f"resolved {id_type} {identifier} -> org {org_id}")
+ if self._hydrator and org_id not in self._hydrated_orgs:
+ self._hydrated_orgs.add(org_id)
+ self._log(f"hydrating org {org_id}")
+ await self._hydrator(org_id)
+ self._log(
+ f"hydrated org {org_id} ({len(self._network_to_org)} networks, {len(self._serial_to_org)} devices total)"
+ )
+ self._maybe_flush()
+ except Exception as e:
+ self._log(f"background resolve of {id_type} {identifier} failed: {e!r}")
+ finally:
+ self._pending_lookups.discard(identifier)
+
+ def on_rate_limited(self, url: str) -> None:
+ """Tighten the appropriate bucket (multiplicative decrease)."""
+ org_id = self.resolve_org(url)
+ if org_id and org_id in self._org_buckets:
+ bucket = self._org_buckets[org_id]
+ bucket.rate = bucket.rate * 0.7
+ self._log(f"rate limited org {org_id}, decreased to {bucket.rate:.1f} req/s")
+ elif OrgRateLimiter._is_unresolved_scoped_url(url):
+ # URL targets a specific network/device whose org isn't resolved
+ # yet. Penalizing the global bucket would punish every other org for
+ # one org's 429, so skip and let background resolution catch up.
+ self._log("rate limited on unresolved network/device url, skipping global penalty")
+ else:
+ self._global_bucket.rate = self._global_bucket.rate * 0.7
+ self._log(f"rate limited (global), decreased to {self._global_bucket.rate:.1f} req/s")
+
+ def on_success(self, url: str) -> None:
+ """Slowly widen buckets back toward configured rates (additive increase)."""
+ org_id = self.resolve_org(url)
+ if org_id and org_id in self._org_buckets:
+ bucket = self._org_buckets[org_id]
+ if bucket.rate < self._rate:
+ bucket.rate = min(self._rate, bucket.rate + 0.2)
+ if self._global_bucket.rate < self._global_rate:
+ self._global_bucket.rate = min(self._global_rate, self._global_bucket.rate + 0.5)
+
+ async def shutdown(self) -> None:
+ """Gracefully drain background work and persist the cache.
+
+ Awaits/cancels all in-flight resolve tasks, awaits any pending flush,
+ then does a final save. Idempotent and safe to call when there is no
+ outstanding work (e.g. from an __aexit__ handler).
+ """
+ if self._bg_tasks:
+ await asyncio.gather(*list(self._bg_tasks), return_exceptions=True)
+ if self._flush_task is not None and not self._flush_task.done():
+ try:
+ await self._flush_task
+ except Exception as e:
+ self._log(f"flush task errored during shutdown: {e!r}")
+ await self.save_cache()
+
+ def register_org(self, org_id: str) -> None:
+ """Ensure a bucket exists for this org."""
+ self._get_or_create_bucket(org_id)
+
+ def register_network(self, network_id: str, org_id: str) -> None:
+ """Cache a network -> org mapping."""
+ self._network_to_org[network_id] = org_id
+
+ def register_device(self, serial: str, org_id: str) -> None:
+ """Cache a serial -> org mapping."""
+ self._serial_to_org[serial] = org_id
+
+ def learn_from_response(self, url: str, body: Any) -> None:
+ """Extract org/network/device mappings from a URL and response body."""
+ org_id = OrgRateLimiter._org_id_from_url(url)
+ if not org_id:
+ org_id = OrgRateLimiter._org_id_from_body(body)
+ if not org_id:
+ return
+
+ self._get_or_create_bucket(org_id)
+ changed_networks = 0
+ changed_devices = 0
+
+ network_id = OrgRateLimiter._network_id_from_url(url)
+ if network_id and self._network_to_org.get(network_id) != org_id:
+ self._network_to_org[network_id] = org_id
+ changed_networks += 1
+
+ serial = OrgRateLimiter._serial_from_url(url)
+ if serial and self._serial_to_org.get(serial) != org_id:
+ self._serial_to_org[serial] = org_id
+ changed_devices += 1
+
+ if isinstance(body, dict):
+ if "networkId" in body and self._network_to_org.get(body["networkId"]) != org_id:
+ self._network_to_org[body["networkId"]] = org_id
+ changed_networks += 1
+ if "serial" in body and self._serial_to_org.get(body["serial"]) != org_id:
+ self._serial_to_org[body["serial"]] = org_id
+ changed_devices += 1
+ net = body.get("network")
+ if isinstance(net, dict) and "id" in net:
+ if self._network_to_org.get(net["id"]) != org_id:
+ self._network_to_org[net["id"]] = org_id
+ changed_networks += 1
+
+ total = changed_networks + changed_devices
+ if total:
+ self._dirty += total
+ if self._logger:
+ self._log(
+ f"learned {total} new mapping{'s' if total != 1 else ''} "
+ f"({changed_networks} network{'s' if changed_networks != 1 else ''}, "
+ f"{changed_devices} device{'s' if changed_devices != 1 else ''}) "
+ f"from {url}"
+ )
+ self._maybe_flush()
+
+ async def save_cache(self) -> None:
+ """Persist the mapping cache to disk in a background thread."""
+ if not self._cache_path:
+ return
+ path = self._cache_path
+ data = json.dumps(
+ {
+ "saved_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
+ "networks": [
+ {"id": net_id, "organization": {"id": org_id}} for net_id, org_id in self._network_to_org.items()
+ ],
+ "devices": [
+ {"serial": serial, "organization": {"id": org_id}} for serial, org_id in self._serial_to_org.items()
+ ],
+ }
+ )
+ loop = asyncio.get_event_loop()
+ await loop.run_in_executor(None, self._write_cache, path, data)
+ n = len(self._network_to_org) + len(self._serial_to_org)
+ self._log(f"saved cache ({n} mappings) to {path}")
+
+ @staticmethod
+ def _write_cache(path: Path, data: str) -> None:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(data, encoding="utf-8")
+
+ def _load_cache(self) -> None:
+ """Load mapping cache from disk if it exists and hasn't expired."""
+ if not self._cache_path or not self._cache_path.exists():
+ return
+ try:
+ data = json.loads(self._cache_path.read_text(encoding="utf-8"))
+ if self._cache_ttl is not None:
+ saved_at = data.get("saved_at")
+ if saved_at is None:
+ self._log("cache expired, will rebuild")
+ return
+ saved_ts = _parse_saved_at(saved_at)
+ if saved_ts is None or (time.time() - saved_ts) > self._cache_ttl:
+ self._log("cache expired, will rebuild")
+ return
+ for net in data.get("networks", []):
+ self._network_to_org[net["id"]] = net["organization"]["id"]
+ for dev in data.get("devices", []):
+ self._serial_to_org[dev["serial"]] = dev["organization"]["id"]
+ self._cache_fresh = True
+ n = len(self._network_to_org) + len(self._serial_to_org)
+ self._log(f"loaded cache ({n} mappings) from {self._cache_path}")
+ except (json.JSONDecodeError, OSError, KeyError):
+ pass
diff --git a/pyproject.toml b/pyproject.toml
index 5f5f5a1c..c95e54db 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "meraki"
-version = "3.3.0"
+version = "4.3.0b1"
description = "Cisco Meraki Dashboard API library"
authors = [
{name = "Cisco Meraki", email = "api-feedback@meraki.net"}
@@ -14,8 +14,7 @@ classifiers = [
"Programming Language :: Python :: 3",
]
dependencies = [
- "requests>=2.33.1,<3",
- "aiohttp>=3.13.5,<4",
+ "httpx>=0.28,<1",
]
[project.urls]
@@ -37,13 +36,15 @@ dev = [
"pytest>=8.3.5,<10",
"pytest-asyncio>=1.0,<2",
"pytest-cov>=7.1.0,<8",
- "responses>=0.25,<1",
- "flake8>=7.0,<8",
+ "respx>=0.23.1,<1",
+ "pytest-benchmark>=2.0.0",
"pre-commit>=4.6.0",
"ruff>=0.15.12",
+ "pytest-json-report>=1.5.0",
+ "hypothesis>=6.122.0,<7",
"towncrier>=24.8.0",
]
-generator = ["jinja2==3.1.6"]
+generator = ["jinja2==3.1.6", "httpx>=0.28,<1"]
[tool.uv]
default-groups = ["dev"]
@@ -53,7 +54,7 @@ line-length = 127
[tool.pytest.ini_options]
testpaths = ["tests/unit"]
-norecursedirs = ["tests/generator"]
+norecursedirs = ["tests/generator", ".hypothesis"]
asyncio_mode = "auto"
[tool.coverage.run]
diff --git a/scripts/seed-networks.py b/scripts/seed-networks.py
deleted file mode 100644
index e7e135c8..00000000
--- a/scripts/seed-networks.py
+++ /dev/null
@@ -1,56 +0,0 @@
-"""Seed each test org with 10 networks so integration tests that assume
-pre-existing networks (e.g. test_org_wide_workflows.py) don't fail on
-an empty org. Idempotent; skips networks that already exist by name.
-
-Usage: TEST_MERAKI_DASHBOARD_API_KEY=... python scripts/seed-networks.py
-"""
-
-import asyncio
-import os
-import sys
-
-import meraki.aio
-
-
-async def main():
- api_key = os.environ.get("TEST_MERAKI_DASHBOARD_API_KEY")
- if not api_key:
- print("ERROR: TEST_MERAKI_DASHBOARD_API_KEY is not set")
- sys.exit(1)
-
- async with meraki.aio.AsyncDashboardAPI(api_key, suppress_logging=True) as dashboard:
- orgs = await dashboard.organizations.getOrganizations()
- print(f"Found {len(orgs)} orgs")
-
- async def seed_org(org):
- org_id = org["id"]
- org_name = org["name"]
-
- networks = await dashboard.organizations.getOrganizationNetworks(org_id, total_pages="all")
- existing_names = {n["name"] for n in networks}
- print(f"\n{org_name} ({org_id}): {len(networks)} existing networks")
-
- tasks = []
- for i in range(10):
- name = f"Seed Network {i:02d}"
- if name in existing_names:
- print(f" Skipped {name} (already exists)")
- continue
- tasks.append(create_network(dashboard, org_id, name))
-
- for result in await asyncio.gather(*tasks):
- print(f" Created {result}")
-
- async def create_network(dashboard, org_id, name):
- await dashboard.organizations.createOrganizationNetwork(
- org_id, name=name, productTypes=["appliance", "wireless", "sensor", "cellularGateway"]
- )
- return name
-
- await asyncio.gather(*(seed_org(org) for org in orgs))
-
- print("\nDone")
-
-
-if __name__ == "__main__":
- asyncio.run(main())
diff --git a/tests/benchmarks/__init__.py b/tests/benchmarks/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/benchmarks/conftest.py b/tests/benchmarks/conftest.py
new file mode 100644
index 00000000..f8053422
--- /dev/null
+++ b/tests/benchmarks/conftest.py
@@ -0,0 +1,37 @@
+"""Benchmark test fixtures with respx-mocked HTTP responses."""
+
+import httpx
+import pytest
+import respx
+
+import meraki
+
+BASE = "https://api.meraki.com/api/v1"
+ORG_ID = "123456"
+NETWORK_ID = "N_123456"
+
+# Canned response payloads (realistic sizes)
+ORGS_RESPONSE = [{"id": ORG_ID, "name": "Test Org", "url": f"https://n1.meraki.com/o/{ORG_ID}/manage/organization/overview"}]
+NETWORKS_RESPONSE = [{"id": NETWORK_ID, "organizationId": ORG_ID, "name": "Test Net", "productTypes": ["appliance", "switch"]}]
+IDENTITY_RESPONSE = {"name": "Test User", "email": "test@example.com", "authentication": {"api": {"key": {"created": True}}}}
+
+
+@pytest.fixture
+def mock_routes():
+ """Set up respx routes for benchmark tests."""
+ with respx.mock(assert_all_mocked=True, assert_all_called=False) as rsps:
+ rsps.get(f"{BASE}/organizations").mock(return_value=httpx.Response(200, json=ORGS_RESPONSE))
+ rsps.get(f"{BASE}/organizations/{ORG_ID}/networks").mock(return_value=httpx.Response(200, json=NETWORKS_RESPONSE))
+ rsps.get(f"{BASE}/administered/identities/me").mock(return_value=httpx.Response(200, json=IDENTITY_RESPONSE))
+ yield rsps
+
+
+@pytest.fixture
+def benchmark_dashboard(mock_routes):
+ """DashboardAPI client for benchmarking (mocked HTTP)."""
+ return meraki.DashboardAPI(
+ "fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ maximum_retries=1,
+ smart_flow_enabled=False,
+ )
diff --git a/tests/benchmarks/test_latency_benchmark.py b/tests/benchmarks/test_latency_benchmark.py
new file mode 100644
index 00000000..979c670c
--- /dev/null
+++ b/tests/benchmarks/test_latency_benchmark.py
@@ -0,0 +1,27 @@
+"""Request latency benchmarks with regression thresholds.
+
+Run: pytest tests/benchmarks/test_latency_benchmark.py --benchmark-json=latency.json
+"""
+
+MAX_MEAN_LATENCY_SECONDS = 0.05
+
+
+def test_latency_get_organizations(benchmark, benchmark_dashboard):
+ """Single GET /organizations latency."""
+ result = benchmark(benchmark_dashboard.organizations.getOrganizations)
+ assert isinstance(result, list)
+ assert benchmark.stats.stats.mean < MAX_MEAN_LATENCY_SECONDS
+
+
+def test_latency_get_networks(benchmark, benchmark_dashboard):
+ """Single GET /organizations/{id}/networks latency."""
+ result = benchmark(benchmark_dashboard.organizations.getOrganizationNetworks, "123456")
+ assert isinstance(result, list)
+ assert benchmark.stats.stats.mean < MAX_MEAN_LATENCY_SECONDS
+
+
+def test_latency_get_identity(benchmark, benchmark_dashboard):
+ """Single GET /administered/identities/me latency."""
+ result = benchmark(benchmark_dashboard.administered.getAdministeredIdentitiesMe)
+ assert isinstance(result, dict)
+ assert benchmark.stats.stats.mean < MAX_MEAN_LATENCY_SECONDS
diff --git a/tests/benchmarks/test_memory_benchmark.py b/tests/benchmarks/test_memory_benchmark.py
new file mode 100644
index 00000000..3790610d
--- /dev/null
+++ b/tests/benchmarks/test_memory_benchmark.py
@@ -0,0 +1,67 @@
+"""Memory benchmarks with leak detection thresholds.
+
+Run: pytest tests/benchmarks/test_memory_benchmark.py --benchmark-json=memory.json
+"""
+
+import tracemalloc
+
+import httpx
+import pytest
+import respx
+
+import meraki
+
+BASE = "https://api.meraki.com/api/v1"
+
+MAX_SINGLE_REQUEST_BYTES = 512 * 1024
+MAX_BATCH_BYTES_PER_REQUEST = 64 * 1024
+
+
+@pytest.fixture
+def fresh_mock_routes():
+ """Fresh respx routes for memory isolation."""
+ with respx.mock(assert_all_mocked=True, assert_all_called=False) as rsps:
+ rsps.get(f"{BASE}/organizations").mock(return_value=httpx.Response(200, json=[{"id": "123456", "name": "Test Org"}]))
+ yield rsps
+
+
+@pytest.fixture
+def fresh_dashboard(fresh_mock_routes):
+ """Fresh DashboardAPI for memory measurement."""
+ return meraki.DashboardAPI(
+ "fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ maximum_retries=1,
+ )
+
+
+def test_memory_single_request(fresh_dashboard):
+ """Memory peak for a single request stays under ceiling."""
+ tracemalloc.start()
+ fresh_dashboard.organizations.getOrganizations()
+ current, peak = tracemalloc.get_traced_memory()
+ tracemalloc.stop()
+
+ assert peak < MAX_SINGLE_REQUEST_BYTES, f"Single request peak {peak} bytes exceeds {MAX_SINGLE_REQUEST_BYTES} ceiling"
+
+
+def test_memory_batch_no_leak(fresh_dashboard):
+ """Memory growth is sub-linear over 50 requests (no leak)."""
+ batch_size = 50
+ tracemalloc.start()
+ for _ in range(batch_size):
+ fresh_dashboard.organizations.getOrganizations()
+ current, peak = tracemalloc.get_traced_memory()
+ tracemalloc.stop()
+
+ per_request = current / batch_size
+ assert per_request < MAX_BATCH_BYTES_PER_REQUEST, (
+ f"Avg {per_request:.0f} bytes/request suggests memory leak (ceiling: {MAX_BATCH_BYTES_PER_REQUEST})"
+ )
+
+
+def test_connection_pool_reuse(benchmark, fresh_dashboard):
+ """Steady-state requests reuse pool (benchmark only, no threshold)."""
+ fresh_dashboard.organizations.getOrganizations()
+ result = benchmark(fresh_dashboard.organizations.getOrganizations)
+ assert result is not None
diff --git a/tests/benchmarks/test_throughput_benchmark.py b/tests/benchmarks/test_throughput_benchmark.py
new file mode 100644
index 00000000..fb09ad77
--- /dev/null
+++ b/tests/benchmarks/test_throughput_benchmark.py
@@ -0,0 +1,40 @@
+"""Throughput benchmarks: requests/second.
+
+Run: pytest tests/benchmarks/test_throughput_benchmark.py --benchmark-json=throughput.json
+"""
+
+BATCH_SIZE = 50
+MIN_RPS = 20
+
+
+def test_throughput_sequential_batch(benchmark, benchmark_dashboard):
+ """Throughput: N sequential requests."""
+
+ def batch_requests():
+ for _ in range(BATCH_SIZE):
+ benchmark_dashboard.organizations.getOrganizations()
+
+ benchmark.pedantic(batch_requests, iterations=1, rounds=5)
+ elapsed = benchmark.stats.stats.mean
+ rps = BATCH_SIZE / elapsed if elapsed > 0 else 0
+ benchmark.extra_info["effective_rps"] = rps
+ assert rps > MIN_RPS, f"RPS {rps:.0f} below minimum {MIN_RPS}"
+
+
+def test_throughput_mixed_endpoints(benchmark, benchmark_dashboard):
+ """Throughput: mixed endpoint calls."""
+
+ def mixed_requests():
+ for i in range(BATCH_SIZE):
+ if i % 3 == 0:
+ benchmark_dashboard.administered.getAdministeredIdentitiesMe()
+ elif i % 3 == 1:
+ benchmark_dashboard.organizations.getOrganizations()
+ else:
+ benchmark_dashboard.organizations.getOrganizationNetworks("123456")
+
+ benchmark.pedantic(mixed_requests, iterations=1, rounds=5)
+ elapsed = benchmark.stats.stats.mean
+ rps = BATCH_SIZE / elapsed if elapsed > 0 else 0
+ benchmark.extra_info["effective_rps"] = rps
+ assert rps > MIN_RPS, f"RPS {rps:.0f} below minimum {MIN_RPS}"
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 00000000..fe465682
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,30 @@
+"""Root test configuration: shared fixtures for all test modules."""
+
+import pytest
+
+from tests.unit.conftest import FAKE_API_KEY, make_metadata, make_mock_response
+
+
+@pytest.fixture
+def mock_response_factory():
+ """Factory for creating mock httpx.Response objects."""
+ return make_mock_response
+
+
+@pytest.fixture
+def fake_api_key():
+ return FAKE_API_KEY
+
+
+@pytest.fixture(autouse=True)
+def _clean_env(monkeypatch):
+ """Remove Meraki env vars so tests don't leak state."""
+ monkeypatch.delenv("MERAKI_DASHBOARD_API_KEY", raising=False)
+ monkeypatch.delenv("BE_GEO_ID", raising=False)
+ monkeypatch.delenv("MERAKI_PYTHON_SDK_CALLER", raising=False)
+
+
+@pytest.fixture
+def metadata_factory():
+ """Factory for endpoint metadata dicts."""
+ return make_metadata
diff --git a/tests/generator/test_generate_library_golden.py b/tests/generator/test_generate_library_golden.py
deleted file mode 100644
index 5fe1348f..00000000
--- a/tests/generator/test_generate_library_golden.py
+++ /dev/null
@@ -1,112 +0,0 @@
-"""
-Golden-file integration test for the full generate_library pipeline.
-
-To regenerate golden files after intentional changes:
- pytest --update-golden tests/generator/test_generate_library_golden.py
-"""
-
-import json
-import os
-import shutil
-from pathlib import Path
-from unittest.mock import patch, MagicMock
-
-import pytest
-
-import generate_library_oasv2 as gen
-
-FIXTURES_DIR = Path(__file__).resolve().parent / "fixtures"
-GOLDEN_DIR = Path(__file__).resolve().parent / "golden"
-GENERATOR_DIR = Path(__file__).resolve().parent.parent.parent / "generator"
-
-GOLDEN_FILES = [
- "meraki/api/networks.py",
- "meraki/aio/api/networks.py",
- "meraki/api/batch/networks.py",
-]
-
-
-@pytest.fixture
-def update_golden(request):
- return request.config.getoption("--update-golden")
-
-
-@pytest.fixture
-def synthetic_spec():
- with open(FIXTURES_DIR / "synthetic_spec.json") as f:
- return json.load(f)
-
-
-@pytest.fixture
-def output_dir(tmp_path):
- for tmpl in GENERATOR_DIR.glob("*.jinja2"):
- shutil.copy2(tmpl, tmp_path / tmpl.name)
- # Copy pyproject.toml so ruff uses project settings (e.g. line-length)
- project_root = GENERATOR_DIR.parent
- shutil.copy2(project_root / "pyproject.toml", tmp_path / "pyproject.toml")
- return tmp_path
-
-
-def _mock_requests_get(url):
- mock_response = MagicMock()
- mock_response.text = f"# placeholder for {url.split('/')[-1]}\n"
- mock_response.ok = True
- return mock_response
-
-
-def _run_generation(synthetic_spec, output_dir):
- original_cwd = os.getcwd()
- try:
- os.chdir(output_dir)
- with patch("generate_library_oasv2.requests.get", side_effect=_mock_requests_get):
- gen.generate_library(
- spec=synthetic_spec,
- version_number="0.0.0-test",
- api_version_number="v1-test",
- is_github_action=False,
- )
- finally:
- os.chdir(original_cwd)
-
-
-class TestGoldenFiles:
- def test_generate_and_compare(self, synthetic_spec, output_dir, update_golden):
- _run_generation(synthetic_spec, output_dir)
-
- for rel_path in GOLDEN_FILES:
- generated_file = output_dir / rel_path
- golden_file = GOLDEN_DIR / rel_path
-
- assert generated_file.exists(), f"Expected generated file not found: {rel_path}"
-
- generated_content = generated_file.read_text(encoding="utf-8")
-
- if update_golden:
- golden_file.parent.mkdir(parents=True, exist_ok=True)
- golden_file.write_text(generated_content, encoding="utf-8")
- else:
- assert golden_file.exists(), f"Golden file missing: {golden_file}\nRun with --update-golden to generate."
- expected_content = golden_file.read_text(encoding="utf-8")
- assert generated_content == expected_content, (
- f"Generated output differs from golden file: {rel_path}\nRun with --update-golden to update."
- )
-
- def test_no_real_http_calls(self, synthetic_spec, output_dir):
- original_cwd = os.getcwd()
- try:
- os.chdir(output_dir)
- with patch("generate_library_oasv2.requests.get", side_effect=_mock_requests_get) as mocked:
- gen.generate_library(
- spec=synthetic_spec,
- version_number="0.0.0-test",
- api_version_number="v1-test",
- is_github_action=False,
- )
- assert mocked.call_count > 0
- for call in mocked.call_args_list:
- url = call[0][0]
- from urllib.parse import urlparse
-
- assert urlparse(url).hostname == "raw.githubusercontent.com"
- finally:
- os.chdir(original_cwd)
diff --git a/tests/generator/test_generate_library_v3.py b/tests/generator/test_generate_library_v3.py
index c4ddb721..3102769f 100644
--- a/tests/generator/test_generate_library_v3.py
+++ b/tests/generator/test_generate_library_v3.py
@@ -5,7 +5,9 @@
import shutil
import sys
from pathlib import Path
-from unittest.mock import patch, MagicMock
+from unittest.mock import patch
+
+import httpx
import pytest
@@ -31,11 +33,11 @@ def output_dir(tmp_path):
return tmp_path
-def _mock_requests_get(url):
- mock_response = MagicMock()
- mock_response.text = f"# placeholder for {url.split('/')[-1]}\n"
- mock_response.ok = True
- return mock_response
+def _mock_httpx_get(url):
+ return httpx.Response(
+ 200,
+ text=f"# placeholder for {url.split('/')[-1]}\n",
+ )
def _run_v3_generation(v3_spec, output_dir):
@@ -44,7 +46,7 @@ def _run_v3_generation(v3_spec, output_dir):
original_cwd = os.getcwd()
try:
os.chdir(output_dir)
- with patch("generate_library.requests.get", side_effect=_mock_requests_get):
+ with patch("generate_library.httpx.get", side_effect=_mock_httpx_get):
gen_v3.generate_library(
spec=v3_spec,
version_number="0.0.0-test",
@@ -61,7 +63,7 @@ def _run_v3_generation_with_stubs(v3_spec, output_dir):
original_cwd = os.getcwd()
try:
os.chdir(output_dir)
- with patch("generate_library.requests.get", side_effect=_mock_requests_get):
+ with patch("generate_library.httpx.get", side_effect=_mock_httpx_get):
gen_v3.generate_library(
spec=v3_spec,
version_number="0.0.0-test",
@@ -138,11 +140,11 @@ def test_spec_fetch_uses_version_3(self):
"""GEN-05: Spec fetch includes ?version=3."""
import generate_library as gen_v3
- with patch("generate_library.requests.get") as mock_get:
- mock_response = MagicMock()
- mock_response.ok = True
- mock_response.json.return_value = {"paths": {}, "tags": [], "x-batchable-actions": []}
- mock_get.return_value = mock_response
+ with patch("generate_library.httpx.get") as mock_get:
+ mock_get.return_value = httpx.Response(
+ 200,
+ json={"paths": {}, "tags": [], "x-batchable-actions": []},
+ )
with patch.object(gen_v3, "generate_library"):
gen_v3.main(["-v", "1.0"])
@@ -155,19 +157,21 @@ def test_org_specific_fetch_uses_version_3(self):
"""GEN-05: Org-specific fetch includes ?version=3 and auth header."""
import generate_library as gen_v3
- with patch("generate_library.requests.get") as mock_get:
- mock_response = MagicMock()
- mock_response.ok = True
- mock_response.json.return_value = {"paths": {}, "tags": [], "x-batchable-actions": []}
- mock_get.return_value = mock_response
-
- with patch.object(gen_v3, "generate_library"):
- gen_v3.main(["-o", "12345", "-k", "testkey", "-v", "1.0"])
-
- args, kwargs = mock_get.call_args
- assert "12345" in args[0]
- assert kwargs.get("params") == {"version": 3}
- assert "Bearer testkey" in kwargs.get("headers", {}).get("Authorization", "")
+ with patch.dict(os.environ, {}, clear=False):
+ os.environ.pop("MERAKI_DASHBOARD_API_KEY", None)
+ with patch("generate_library.httpx.get") as mock_get:
+ mock_get.return_value = httpx.Response(
+ 200,
+ json={"paths": {}, "tags": [], "x-batchable-actions": []},
+ )
+
+ with patch.object(gen_v3, "generate_library"):
+ gen_v3.main(["-o", "12345", "-k", "testkey", "-v", "1.0"])
+
+ args, kwargs = mock_get.call_args
+ assert "12345" in args[0]
+ assert kwargs.get("params") == {"version": 3}
+ assert "Bearer testkey" in kwargs.get("headers", {}).get("Authorization", "")
class TestV3Stubs:
diff --git a/tests/generator/test_generate_stubs.py b/tests/generator/test_generate_stubs.py
index 736e7e43..555a9907 100644
--- a/tests/generator/test_generate_stubs.py
+++ b/tests/generator/test_generate_stubs.py
@@ -1,10 +1,10 @@
"""Tests for .pyi stub generation."""
+
import json
import os
import shutil
import sys
from pathlib import Path
-from unittest.mock import patch, MagicMock
import pytest
diff --git a/tests/generator/test_generator_audit.py b/tests/generator/test_generator_audit.py
new file mode 100644
index 00000000..fc07f758
--- /dev/null
+++ b/tests/generator/test_generator_audit.py
@@ -0,0 +1,196 @@
+"""
+Regression tests for GROUP A (generator) audit fixes.
+
+Covers:
+ #1 generate_snippets.py: sys.exit must use a single f-string message
+ #3 batch_function_template.jinja2: path-param quoting wraps str()
+ #16 generate_library.py: PATCH endpoints generate without NameError
+ #18 generate_library.py + templates: keyword-named params (e.g. 'from')
+ are remapped from their safe signature name back to the original.
+
+Hermetic: no network. The generator package uses bare `import common`, so the
+generator directory is placed on sys.path. parse logic is exercised with small
+in-memory spec dicts.
+"""
+
+import io
+import os
+import sys
+
+import jinja2
+import pytest
+
+# Repo layout: /generator/*.py and /tests/unit/this_file
+REPO_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+GENERATOR_DIR = os.path.join(REPO_ROOT, "generator")
+
+if GENERATOR_DIR not in sys.path:
+ sys.path.insert(0, GENERATOR_DIR)
+
+import generate_library # noqa: E402
+from parser_v3 import clear_cache # noqa: E402
+
+
+TEMPLATE_DIR = GENERATOR_DIR + os.sep # trailing sep so f"{template_dir}name" resolves
+
+
+def _jinja_env():
+ import json
+
+ env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True)
+ env.filters["to_double_quote_list"] = lambda lst: json.dumps(lst)
+ return env
+
+
+# ---------------------------------------------------------------------------
+# #1 generate_snippets.py: sys.exit f-string diagnostic
+# ---------------------------------------------------------------------------
+def test_snippets_sys_exit_uses_fstring_message():
+ src_path = os.path.join(GENERATOR_DIR, "generate_snippets.py")
+ with open(src_path, encoding="utf-8") as fp:
+ src = fp.read()
+
+ # The buggy form passed two positional args to sys.exit (TypeError).
+ assert "sys.exit(p, values)" not in src
+ # The fixed form is a single f-string argument.
+ assert 'sys.exit(f"Unhandled param type for {p}: {values}")' in src
+
+
+# ---------------------------------------------------------------------------
+# #3 batch_function_template.jinja2: str() around path param before quote
+# ---------------------------------------------------------------------------
+def test_batch_template_path_param_wraps_str():
+ env = _jinja_env()
+ with open(os.path.join(GENERATOR_DIR, "batch_function_template.jinja2"), encoding="utf-8") as fp:
+ template = env.from_string(fp.read())
+
+ rendered = template.render(
+ operation="createDeviceThing",
+ function_definition=", serial: str",
+ description="desc",
+ doc_url="http://example",
+ descriptions=[],
+ kwarg_line="",
+ all_params=[],
+ assert_blocks=[],
+ tags=["devices"],
+ resource="/devices/{serial}/things",
+ query_params={},
+ array_params={},
+ body_params={},
+ path_params={"serial": {"type": "string", "in": "path"}},
+ call_line="return action",
+ batch_operation="create",
+ renamed_params={},
+ )
+
+ # A non-string (int) path param would TypeError without str() wrapping.
+ assert 'urllib.parse.quote(str(serial), safe="")' in rendered
+ assert 'urllib.parse.quote(serial, safe="")' not in rendered
+
+
+# ---------------------------------------------------------------------------
+# #16 generate_library.py: PATCH endpoint generates a patch call_line
+# ---------------------------------------------------------------------------
+def _patch_spec():
+ return {
+ "paths": {
+ "/things/{thingId}": {
+ "patch": {
+ "operationId": "updateThing",
+ "tags": ["organizations"],
+ "summary": "Update a thing",
+ "parameters": [
+ {
+ "name": "thingId",
+ "in": "path",
+ "required": True,
+ "schema": {"type": "string"},
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {"name": {"type": "string", "description": "n"}},
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+
+def test_patch_endpoint_generates_without_nameerror():
+ clear_cache()
+ spec = _patch_spec()
+ section = {"/things/{thingId}": {"patch": spec["paths"]["/things/{thingId}"]["patch"]}}
+
+ output = io.StringIO()
+ async_output = io.StringIO()
+
+ # Would raise NameError (unbound call_line) before fix #16.
+ generate_library.generate_standard_and_async_functions(_jinja_env(), TEMPLATE_DIR, section, output, async_output, spec)
+
+ rendered = output.getvalue()
+ assert "def updateThing(self" in rendered
+ # patch mirrors put/post: dispatches to self._session.patch with the payload.
+ assert "self._session.patch(metadata, resource, payload)" in rendered
+
+
+# ---------------------------------------------------------------------------
+# #18 keyword param 'from' is remapped from safe name 'from_' back to 'from'
+# ---------------------------------------------------------------------------
+def _keyword_param_spec():
+ return {
+ "paths": {
+ "/networks/{networkId}/events": {
+ "get": {
+ "operationId": "getNetworkThings",
+ "tags": ["networks"],
+ "summary": "Get things",
+ "parameters": [
+ {
+ "name": "networkId",
+ "in": "path",
+ "required": True,
+ "schema": {"type": "string"},
+ },
+ {
+ "name": "from",
+ "in": "query",
+ "required": True,
+ "schema": {"type": "string", "description": "start"},
+ },
+ ],
+ }
+ }
+ }
+ }
+
+
+def test_keyword_param_remapped_in_generated_function():
+ clear_cache()
+ spec = _keyword_param_spec()
+ path = "/networks/{networkId}/events"
+ section = {path: {"get": spec["paths"][path]["get"]}}
+
+ output = io.StringIO()
+ async_output = io.StringIO()
+
+ generate_library.generate_standard_and_async_functions(_jinja_env(), TEMPLATE_DIR, section, output, async_output, spec)
+
+ rendered = output.getvalue()
+ # 'from' is a Python keyword -> signature uses 'from_'
+ assert "from_: str" in rendered
+ # remap loop restores the original key so the value reaches the request
+ assert 'kwargs["from"] = kwargs.pop("from_")' in rendered
+ # 'from' must still be the query param key used to build params
+ assert '"from"' in rendered
+
+
+if __name__ == "__main__":
+ sys.exit(pytest.main([__file__, "-q"]))
diff --git a/tests/generator/test_golden_v3_output.py b/tests/generator/test_golden_v3_output.py
index 68cefd8b..1dfb8f75 100644
--- a/tests/generator/test_golden_v3_output.py
+++ b/tests/generator/test_golden_v3_output.py
@@ -6,7 +6,9 @@
import shutil
import sys
from pathlib import Path
-from unittest.mock import patch, MagicMock
+from unittest.mock import patch
+
+import httpx
import pytest
@@ -41,12 +43,12 @@ def _generate_fresh_output(spec, output_dir):
os.chdir(output_dir)
def mock_get(url):
- m = MagicMock()
- m.text = f"# placeholder for {url.split('/')[-1]}\n"
- m.ok = True
- return m
+ return httpx.Response(
+ 200,
+ text=f"# placeholder for {url.split('/')[-1]}\n",
+ )
- with patch("generate_library.requests.get", side_effect=mock_get):
+ with patch("generate_library.httpx.get", side_effect=mock_get):
gen_v3.generate_library(spec, "0.0.0-golden", "v1", False)
sync = (output_dir / "meraki/api/networks.py").read_text()
diff --git a/tests/generator/test_pure_functions.py b/tests/generator/test_pure_functions.py
index 71e7fd9f..9b849f1e 100644
--- a/tests/generator/test_pure_functions.py
+++ b/tests/generator/test_pure_functions.py
@@ -1,6 +1,6 @@
import pytest
-import generate_library_oasv2 as gen
+import common as gen
class TestDocsUrl:
@@ -182,163 +182,3 @@ def test_enum_captured(self):
False,
)
assert result["sortOrder"]["enum"] == ["asc", "desc"]
-
-
-class TestParseParams:
- def test_none_parameters(self):
- assert gen.parse_params("someOp", None) == {}
-
- def test_empty_list(self):
- assert gen.parse_params("someOp", []) == {}
-
- def test_path_param(self):
- params = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- }
- ]
- result = gen.parse_params("someOp", params)
- assert "networkId" in result
- assert result["networkId"]["required"] is True
-
-
-class TestParseGetParams:
- def test_with_pagination(self):
- parameters = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- },
- {
- "name": "perPage",
- "in": "query",
- "type": "integer",
- "required": False,
- "description": "Per page",
- },
- {
- "name": "startingAfter",
- "in": "query",
- "type": "string",
- "required": False,
- "description": "Starting after",
- },
- ]
- array_params, call_line, path_params, query_params = gen.parse_get_params("getNetworkClients", parameters)
- assert "get_pages" in call_line
- assert "networkId" in path_params
- assert "perPage" in query_params
-
- def test_without_query_params(self):
- parameters = [
- {
- "name": "serial",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Serial",
- },
- ]
- array_params, call_line, path_params, query_params = gen.parse_get_params("getDevice", parameters)
- assert call_line == "return self._session.get(metadata, resource)"
-
- def test_network_events_pagination(self):
- parameters = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- },
- {
- "name": "perPage",
- "in": "query",
- "type": "integer",
- "required": False,
- "description": "Per page",
- },
- ]
- _, call_line, _, _ = gen.parse_get_params("getNetworkEvents", parameters)
- assert "event_log_end_time" in call_line
-
-
-class TestParsePostAndPutParams:
- def test_post_with_body(self):
- parameters = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- },
- {
- "name": "createBody",
- "in": "body",
- "schema": {
- "properties": {"name": {"type": "string", "description": "Name"}},
- },
- },
- ]
- body_params, call_line, path_params = gen.parse_post_and_put_params("post", "createNetwork", parameters)
- assert "post" in call_line
- assert "payload" in call_line
- assert "name" in body_params
-
- def test_put_without_body(self):
- parameters = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- },
- ]
- body_params, call_line, path_params = gen.parse_post_and_put_params("put", "updateThing", parameters)
- assert "payload" not in call_line
-
-
-class TestParseDeleteParams:
- def test_simple_delete(self):
- parameters = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- },
- ]
- call_line, path_params, query_params = gen.parse_delete_params("deleteNetwork", parameters)
- assert call_line == "return self._session.delete(metadata, resource)"
- assert "networkId" in path_params
-
- def test_delete_with_query_params(self):
- parameters = [
- {
- "name": "networkId",
- "in": "path",
- "type": "string",
- "required": True,
- "description": "Network ID",
- },
- {
- "name": "force",
- "in": "query",
- "type": "boolean",
- "required": False,
- "description": "Force delete",
- },
- ]
- call_line, path_params, query_params = gen.parse_delete_params("deleteNetwork", parameters)
- assert "params" in call_line
- assert "force" in query_params
diff --git a/tests/integration/baseline/README.md b/tests/integration/baseline/README.md
new file mode 100644
index 00000000..7c4d3aa9
--- /dev/null
+++ b/tests/integration/baseline/README.md
@@ -0,0 +1,29 @@
+# Integration Test Baseline
+
+Machine-readable pass/fail snapshot of all integration tests captured before the httpx migration (v4.0 Phase 8).
+
+## Purpose
+
+Phase 13 uses `report.json` as the regression gate. The rule (D-07): **same or better**. No new failures allowed after migration; new passes are OK.
+
+## How it was captured
+
+```bash
+pytest tests/integration/ \
+ --apikey="$MERAKI_DASHBOARD_API_KEY" \
+ --o="$MERAKI_ORG_ID" \
+ -v \
+ --json-report \
+ --json-report-file=tests/integration/baseline/report.json \
+ --json-report-indent=2 \
+ --json-report-omit=collectors,log,streams
+```
+
+## Schema
+
+See pytest-json-report docs. Key fields per test: `nodeid`, `outcome`, `call.duration`.
+
+## Regression comparison (Phase 13)
+
+For each test in baseline where `outcome == "passed"`, Phase 13 must also pass.
+Tests that failed in baseline are "known failures" and do not block.
diff --git a/tests/integration/baseline/report.json b/tests/integration/baseline/report.json
new file mode 100644
index 00000000..9a9fde0f
--- /dev/null
+++ b/tests/integration/baseline/report.json
@@ -0,0 +1,1068 @@
+{
+ "created": 1777681221.1439042,
+ "duration": 115.48956537246704,
+ "exitcode": 0,
+ "root": "C:\\Users\\jkuchta\\Work\\_Repos\\meraki\\dashboard-api-python",
+ "environment": {},
+ "summary": {
+ "passed": 32,
+ "total": 32,
+ "collected": 32
+ },
+ "collectors": [
+ {
+ "nodeid": "",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration",
+ "type": "Dir"
+ }
+ ]
+ },
+ {
+ "nodeid": "tests/integration/baseline",
+ "outcome": "passed",
+ "result": []
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_administered_identities_me",
+ "type": "Coroutine",
+ "lineno": 43
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_organizations",
+ "type": "Coroutine",
+ "lineno": 50
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_organization",
+ "type": "Coroutine",
+ "lineno": 56
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_create_network",
+ "type": "Coroutine",
+ "lineno": 62
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_networks",
+ "type": "Coroutine",
+ "lineno": 67
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_update_network",
+ "type": "Coroutine",
+ "lineno": 73
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_create_organization_policy_objects",
+ "type": "Coroutine",
+ "lineno": 84
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_organization_policy_objects",
+ "type": "Coroutine",
+ "lineno": 107
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_network_appliance_l3_firewall_rules",
+ "type": "Coroutine",
+ "lineno": 113
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_update_network_appliance_vlan_settings",
+ "type": "Coroutine",
+ "lineno": 119
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_create_network_appliance_vlan",
+ "type": "Coroutine",
+ "lineno": 125
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_update_l3_firewall_rules",
+ "type": "Coroutine",
+ "lineno": 144
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_delete_policy_objects",
+ "type": "Coroutine",
+ "lineno": 183
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_delete_network",
+ "type": "Coroutine",
+ "lineno": 200
+ }
+ ]
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_administered_identities_me",
+ "type": "Function",
+ "lineno": 46
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_organizations",
+ "type": "Function",
+ "lineno": 53
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_organization",
+ "type": "Function",
+ "lineno": 59
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_create_network",
+ "type": "Function",
+ "lineno": 65
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_networks",
+ "type": "Function",
+ "lineno": 70
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_update_network",
+ "type": "Function",
+ "lineno": 76
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_create_organization_policy_objects",
+ "type": "Function",
+ "lineno": 88
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_organization_policy_objects",
+ "type": "Function",
+ "lineno": 111
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_network_appliance_l3_firewall_rules",
+ "type": "Function",
+ "lineno": 117
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_update_network_appliance_vlan_settings",
+ "type": "Function",
+ "lineno": 123
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_create_network_appliance_vlan",
+ "type": "Function",
+ "lineno": 129
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_update_l3_firewall_rules",
+ "type": "Function",
+ "lineno": 148
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_delete_policy_objects",
+ "type": "Function",
+ "lineno": 187
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_delete_network",
+ "type": "Function",
+ "lineno": 207
+ }
+ ]
+ },
+ {
+ "nodeid": "tests/integration/test_iterator_async.py",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration/test_iterator_async.py::test_iterator_async_full_lifecycle",
+ "type": "Coroutine",
+ "lineno": 29
+ }
+ ]
+ },
+ {
+ "nodeid": "tests/integration/test_iterator_sync.py",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration/test_iterator_sync.py::test_iterator_sync_full_lifecycle",
+ "type": "Function",
+ "lineno": 25
+ }
+ ]
+ },
+ {
+ "nodeid": "tests/integration/test_org_wide_workflows.py",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration/test_org_wide_workflows.py::test_sync_org_wide_clients_workflow",
+ "type": "Function",
+ "lineno": 8
+ },
+ {
+ "nodeid": "tests/integration/test_org_wide_workflows.py::test_async_org_wide_clients_workflow",
+ "type": "Coroutine",
+ "lineno": 31
+ }
+ ]
+ },
+ {
+ "nodeid": "tests/integration",
+ "outcome": "passed",
+ "result": [
+ {
+ "nodeid": "tests/integration/baseline",
+ "type": "Dir"
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py",
+ "type": "Module"
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py",
+ "type": "Module"
+ },
+ {
+ "nodeid": "tests/integration/test_iterator_async.py",
+ "type": "Module"
+ },
+ {
+ "nodeid": "tests/integration/test_iterator_sync.py",
+ "type": "Module"
+ },
+ {
+ "nodeid": "tests/integration/test_org_wide_workflows.py",
+ "type": "Module"
+ }
+ ]
+ }
+ ],
+ "tests": [
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_administered_identities_me",
+ "lineno": 46,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_administered_identities_me",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0010485999991942663,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.7933835000003455,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00014060000103199854,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_organizations",
+ "lineno": 53,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_organizations",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001731000011204742,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.46288840000124765,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00014340000052470714,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_organization",
+ "lineno": 59,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_organization",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00026960000104736537,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.29764999999679276,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0001370999998471234,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_create_network",
+ "lineno": 65,
+ "outcome": "passed",
+ "keywords": [
+ "test_create_network",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 3.396638100002747,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.00013219999891589396,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00012569999671541154,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_networks",
+ "lineno": 70,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_networks",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00013870000111637637,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.28337069999906817,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013720000060857274,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_update_network",
+ "lineno": 76,
+ "outcome": "passed",
+ "keywords": [
+ "test_update_network",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001995999991777353,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.8609858999989228,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013269999908516183,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_create_organization_policy_objects",
+ "lineno": 88,
+ "outcome": "passed",
+ "keywords": [
+ "test_create_organization_policy_objects",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.000229199999012053,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 1.1937579000004916,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00017239999942830764,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_organization_policy_objects",
+ "lineno": 111,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_organization_policy_objects",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00024359999952139333,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.5413779999980761,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.000134599999000784,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_get_network_appliance_l3_firewall_rules",
+ "lineno": 117,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_network_appliance_l3_firewall_rules",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00015999999959603883,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.5264481999984127,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013760000001639128,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_update_network_appliance_vlan_settings",
+ "lineno": 123,
+ "outcome": "passed",
+ "keywords": [
+ "test_update_network_appliance_vlan_settings",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00015310000162571669,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.5576407999978983,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013490000128513202,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_create_network_appliance_vlan",
+ "lineno": 129,
+ "outcome": "passed",
+ "keywords": [
+ "test_create_network_appliance_vlan",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001491999973950442,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 1.5098424999996496,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013490000128513202,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_update_l3_firewall_rules",
+ "lineno": 148,
+ "outcome": "passed",
+ "keywords": [
+ "test_update_l3_firewall_rules",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00014770000052521937,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.9906009999976959,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00012829999832320027,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_delete_policy_objects",
+ "lineno": 187,
+ "outcome": "passed",
+ "keywords": [
+ "test_delete_policy_objects",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00014250000094762072,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 2.2484381000031135,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00019489999976940453,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_sync.py::test_delete_network",
+ "lineno": 207,
+ "outcome": "passed",
+ "keywords": [
+ "test_delete_network",
+ "test_client_crud_lifecycle_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001919999995152466,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 13.989967000001343,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013349999790079892,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_administered_identities_me",
+ "lineno": 43,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_administered_identities_me",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.002668099998118123,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.47884870000052615,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013730000137002207,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_organizations",
+ "lineno": 50,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_organizations",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00017490000027464703,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.2649894999995013,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0001354000014543999,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_organization",
+ "lineno": 56,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_organization",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00022680000256514177,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.2856160000010277,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00011770000128308311,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_create_network",
+ "lineno": 62,
+ "outcome": "passed",
+ "keywords": [
+ "test_create_network",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 3.051430600000458,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.00020430000222404487,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0001145999995060265,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_networks",
+ "lineno": 67,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_networks",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00015210000128718093,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.2914024999990943,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0001396000006934628,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_update_network",
+ "lineno": 73,
+ "outcome": "passed",
+ "keywords": [
+ "test_update_network",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00021579999884124845,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.8056949999991048,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00014290000035543926,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_create_organization_policy_objects",
+ "lineno": 84,
+ "outcome": "passed",
+ "keywords": [
+ "test_create_organization_policy_objects",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00023490000239689834,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.5688245999990613,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00012700000297627412,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_organization_policy_objects",
+ "lineno": 107,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_organization_policy_objects",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00017690000095171854,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.2803993999987142,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0001430000011168886,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_get_network_appliance_l3_firewall_rules",
+ "lineno": 113,
+ "outcome": "passed",
+ "keywords": [
+ "test_get_network_appliance_l3_firewall_rules",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00022739999985788018,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.30385259999820846,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0002696999981708359,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_update_network_appliance_vlan_settings",
+ "lineno": 119,
+ "outcome": "passed",
+ "keywords": [
+ "test_update_network_appliance_vlan_settings",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00022909999825060368,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.41092959999878076,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00011660000018309802,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_create_network_appliance_vlan",
+ "lineno": 125,
+ "outcome": "passed",
+ "keywords": [
+ "test_create_network_appliance_vlan",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00021700000070268288,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 1.2798312999984773,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0001354000014543999,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_update_l3_firewall_rules",
+ "lineno": 144,
+ "outcome": "passed",
+ "keywords": [
+ "test_update_l3_firewall_rules",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001785000022209715,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.7769468000005872,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00010830000246642157,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_delete_policy_objects",
+ "lineno": 183,
+ "outcome": "passed",
+ "keywords": [
+ "test_delete_policy_objects",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0003133000027446542,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 1.5033273000008194,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00012889999925391749,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_client_crud_lifecycle_async.py::test_delete_network",
+ "lineno": 200,
+ "outcome": "passed",
+ "keywords": [
+ "test_delete_network",
+ "test_client_crud_lifecycle_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.00017279999883612618,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 9.322395800001686,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00013279999984661117,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_org_wide_workflows.py::test_sync_org_wide_clients_workflow",
+ "lineno": 8,
+ "outcome": "passed",
+ "keywords": [
+ "test_sync_org_wide_clients_workflow",
+ "test_org_wide_workflows.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001756999990902841,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 0.839036400000623,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00014450000162469223,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_org_wide_workflows.py::test_async_org_wide_clients_workflow",
+ "lineno": 31,
+ "outcome": "passed",
+ "keywords": [
+ "test_async_org_wide_clients_workflow",
+ "asyncio",
+ "pytestmark",
+ "test_org_wide_workflows.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0008937999991758261,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 1.0785622999974294,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.0010290999998687766,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_iterator_sync.py::test_iterator_sync_full_lifecycle",
+ "lineno": 25,
+ "outcome": "passed",
+ "keywords": [
+ "test_iterator_sync_full_lifecycle",
+ "test_iterator_sync.py",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0001694999991741497,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 32.9232955999978,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.00015500000154133886,
+ "outcome": "passed"
+ }
+ },
+ {
+ "nodeid": "tests/integration/test_iterator_async.py::test_iterator_async_full_lifecycle",
+ "lineno": 29,
+ "outcome": "passed",
+ "keywords": [
+ "test_iterator_async_full_lifecycle",
+ "test_iterator_async.py",
+ "asyncio",
+ "integration",
+ "tests",
+ "dashboard-api-python",
+ ""
+ ],
+ "setup": {
+ "duration": 0.0010623999987728894,
+ "outcome": "passed"
+ },
+ "call": {
+ "duration": 33.057837699998345,
+ "outcome": "passed"
+ },
+ "teardown": {
+ "duration": 0.002345099997910438,
+ "outcome": "passed"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index 5ed2f058..efb553b9 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -3,9 +3,11 @@
FILE_ORDER = [
"test_client_crud_lifecycle_sync.py",
"test_client_crud_lifecycle_async.py",
+ "test_lifecycle_sync.py",
+ "test_lifecycle_async.py",
"test_org_wide_workflows.py",
- "test_pagination_iterator_policy_objects_sync.py",
- "test_pagination_iterator_policy_objects_async.py",
+ "test_iterator_sync.py",
+ "test_iterator_async.py",
]
diff --git a/tests/integration/test_client_crud_lifecycle_async.py b/tests/integration/test_client_crud_lifecycle_async.py
index f471453f..50668413 100644
--- a/tests/integration/test_client_crud_lifecycle_async.py
+++ b/tests/integration/test_client_crud_lifecycle_async.py
@@ -201,7 +201,7 @@ async def test_delete_policy_objects(dashboard, org_id, version_salt):
async def test_delete_network(dashboard, org_id, network):
import asyncio
from meraki.api.batch.networks import ActionBatchNetworks
- from meraki.exceptions import AsyncAPIError
+ from meraki.exceptions import APIError
action = ActionBatchNetworks().deleteNetwork(network["id"])
max_attempts = 5
@@ -217,7 +217,7 @@ async def test_delete_network(dashboard, org_id, network):
confirmed=False,
synchronous=False,
)
- except AsyncAPIError as e:
+ except APIError as e:
# Action batches are asynchronous: a prior attempt's batch can
# finish deleting the network after we stopped observing it. The
# network being gone is the desired end state, so a "not found"
diff --git a/tests/integration/test_lifecycle_async.py b/tests/integration/test_lifecycle_async.py
new file mode 100644
index 00000000..10aa03fc
--- /dev/null
+++ b/tests/integration/test_lifecycle_async.py
@@ -0,0 +1,190 @@
+import asyncio
+import hashlib
+import platform
+import random
+import time
+
+import pytest
+import pytest_asyncio
+
+import meraki.aio
+from meraki.api.batch.networks import ActionBatchNetworks
+
+pytestmark = pytest.mark.asyncio(loop_scope="session")
+
+
+def _salt():
+ return hashlib.md5(str(time.time()).encode()).hexdigest()[:6]
+
+
+@pytest.fixture(scope="session")
+def version_salt():
+ python_version = platform.python_version()
+ salt = str(random.randint(1, 17381738))
+ return f"{python_version} {salt}"
+
+
+@pytest_asyncio.fixture(scope="session", loop_scope="session")
+async def dashboard(api_key):
+ async with meraki.aio.AsyncDashboardAPI(
+ api_key,
+ suppress_logging=True,
+ network_delete_retry_wait_time=1000,
+ maximum_retries=1000,
+ caller="PythonSDKTest Cisco",
+ ) as dashboard:
+ yield dashboard
+
+
+@pytest_asyncio.fixture(scope="session", loop_scope="session")
+async def network(dashboard, org_id, version_salt):
+ name = f"_GitHubAction Test Lifecycle Network {version_salt}"
+ product_types = ["wireless", "appliance"]
+ network_kwargs = {
+ "tags": ["test_tag", "github", "shouldBeDeleted"],
+ "timezone": "America/Los_Angeles",
+ }
+
+ created_network = await dashboard.organizations.createOrganizationNetwork(org_id, name, product_types, **network_kwargs)
+ yield created_network
+
+ action = ActionBatchNetworks().deleteNetwork(created_network["id"])
+ for attempt in range(1, 6):
+ delay = 2**attempt
+ await asyncio.sleep(delay)
+ batch = await dashboard.organizations.createOrganizationActionBatch(
+ organizationId=org_id, actions=[action], confirmed=True, synchronous=False
+ )
+ for _ in range(10):
+ await asyncio.sleep(delay)
+ status = await dashboard.organizations.getOrganizationActionBatch(org_id, batch["id"])
+ if status["status"]["completed"]:
+ return
+ if status["status"]["failed"]:
+ break
+ if attempt == 5:
+ pytest.fail("Network cleanup action batch failed after 5 attempts")
+
+
+async def test_policy_object(dashboard, org_id):
+ salt = _salt()
+ obj = await dashboard.organizations.createOrganizationPolicyObject(
+ org_id, name=f"test-policy-object-{salt}", category="network", type="cidr", cidr="10.0.0.0/24"
+ )
+ assert isinstance(obj["id"], str)
+
+ await dashboard.organizations.updateOrganizationPolicyObject(org_id, obj["id"], name=f"test-policy-object-{salt}-r")
+ await dashboard.organizations.deleteOrganizationPolicyObject(org_id, obj["id"])
+
+
+async def test_policy_object_group(dashboard, org_id):
+ salt = _salt()
+ group = await dashboard.organizations.createOrganizationPolicyObjectsGroup(
+ org_id, name=f"test-policy-group-{salt}", category="NetworkObjectGroup"
+ )
+ assert isinstance(group["id"], str)
+
+ await dashboard.organizations.updateOrganizationPolicyObjectsGroup(org_id, group["id"], name=f"test-policy-group-{salt}-r")
+ await dashboard.organizations.deleteOrganizationPolicyObjectsGroup(org_id, group["id"])
+
+
+async def test_alerts_profile(dashboard, org_id):
+ salt = _salt()
+ profile = await dashboard.organizations.createOrganizationAlertsProfile(
+ org_id,
+ type="wanUtilization",
+ alertCondition={"duration": 60, "window": 600, "bit_rate_bps": 1000000, "interface": "wan1"},
+ recipients={"emails": ["test@example.com"]},
+ networkTags=["__all_tags__"],
+ description=f"test-alert-profile-{salt}",
+ )
+ assert isinstance(profile["id"], str)
+
+ await dashboard.organizations.updateOrganizationAlertsProfile(
+ org_id, profile["id"], description=f"test-alert-profile-{salt}-r"
+ )
+ await dashboard.organizations.deleteOrganizationAlertsProfile(org_id, profile["id"])
+
+
+async def test_group_policy(dashboard, network):
+ salt = _salt()
+ gp = await dashboard.networks.createNetworkGroupPolicy(network["id"], name=f"test-group-policy-{salt}")
+ assert "groupPolicyId" in gp
+
+ await dashboard.networks.updateNetworkGroupPolicy(network["id"], gp["groupPolicyId"], name=f"test-group-policy-{salt}-r")
+ await dashboard.networks.deleteNetworkGroupPolicy(network["id"], gp["groupPolicyId"])
+
+
+async def test_mqtt_broker(dashboard, network):
+ salt = _salt()
+ broker = await dashboard.networks.createNetworkMqttBroker(
+ network["id"], name=f"test-mqtt-broker-{salt}", host="mqtt.example.com", port=1883
+ )
+ assert isinstance(broker["id"], str)
+
+ await dashboard.networks.updateNetworkMqttBroker(network["id"], broker["id"], name=f"test-mqtt-broker-{salt}-r")
+ await dashboard.networks.deleteNetworkMqttBroker(network["id"], broker["id"])
+
+
+async def test_webhook_http_server(dashboard, network):
+ salt = _salt()
+ server = await dashboard.networks.createNetworkWebhooksHttpServer(
+ network["id"], name=f"test-webhook-server-{salt}", url="https://example.com/webhook"
+ )
+ assert isinstance(server["id"], str)
+
+ await dashboard.networks.updateNetworkWebhooksHttpServer(network["id"], server["id"], name=f"test-webhook-server-{salt}-r")
+ await dashboard.networks.deleteNetworkWebhooksHttpServer(network["id"], server["id"])
+
+
+async def test_webhook_payload_template(dashboard, network):
+ salt = _salt()
+ template = await dashboard.networks.createNetworkWebhooksPayloadTemplate(
+ network["id"],
+ name=f"test-payload-template-{salt}",
+ body='{"event": "{{alertType}}", "network": "{{networkName}}"}',
+ )
+ assert "payloadTemplateId" in template
+
+ await dashboard.networks.deleteNetworkWebhooksPayloadTemplate(network["id"], template["payloadTemplateId"])
+
+
+async def test_ssid(dashboard, network):
+ ssid = await dashboard.wireless.getNetworkWirelessSsid(network["id"], "0")
+ original_name = ssid["name"]
+
+ await dashboard.wireless.updateNetworkWirelessSsid(network["id"], "0", name="test-ssid-renamed")
+ await dashboard.wireless.updateNetworkWirelessSsid(network["id"], "0", name=original_name)
+
+
+async def test_network_settings(dashboard, network):
+ settings = await dashboard.networks.getNetworkSettings(network["id"])
+ original = settings.get("localStatusPageEnabled", True)
+
+ await dashboard.networks.updateNetworkSettings(network["id"], localStatusPageEnabled=not original)
+ await dashboard.networks.updateNetworkSettings(network["id"], localStatusPageEnabled=original)
+
+
+async def test_action_batch(dashboard, org_id, network):
+ actions = [
+ {
+ "resource": f"/networks/{network['id']}/wireless/airMarshal/rules",
+ "operation": "create",
+ "body": {"type": "block", "match": {"string": f"test-rule-{i}", "type": "bssid"}},
+ }
+ for i in range(1, 4)
+ ]
+
+ batch = await dashboard.organizations.createOrganizationActionBatch(org_id, actions, confirmed=True, synchronous=False)
+ assert isinstance(batch["id"], str)
+
+ for _ in range(30):
+ await asyncio.sleep(2)
+ status = await dashboard.organizations.getOrganizationActionBatch(org_id, batch["id"])
+ if status["status"]["completed"]:
+ assert len(status["actions"]) == 3
+ return
+ if status["status"]["failed"]:
+ pytest.fail(f"Action batch {batch['id']} failed")
+
+ pytest.fail("Action batch did not complete within timeout")
diff --git a/tests/integration/test_lifecycle_sync.py b/tests/integration/test_lifecycle_sync.py
new file mode 100644
index 00000000..3487b262
--- /dev/null
+++ b/tests/integration/test_lifecycle_sync.py
@@ -0,0 +1,183 @@
+import hashlib
+import platform
+import random
+import time
+
+import pytest
+
+import meraki
+from meraki.api.batch.networks import ActionBatchNetworks
+
+
+def _salt():
+ return hashlib.md5(str(time.time()).encode()).hexdigest()[:6]
+
+
+@pytest.fixture(scope="session")
+def version_salt():
+ python_version = platform.python_version()
+ salt = str(random.randint(1, 17381738))
+ return f"{python_version} {salt}"
+
+
+@pytest.fixture(scope="session")
+def dashboard(api_key):
+ return meraki.DashboardAPI(
+ api_key,
+ suppress_logging=True,
+ network_delete_retry_wait_time=1000,
+ maximum_retries=1000,
+ caller="PythonSDKTest Cisco",
+ )
+
+
+@pytest.fixture(scope="session")
+def network(dashboard, org_id, version_salt):
+ name = f"_GitHubAction Test Lifecycle Network {version_salt}"
+ product_types = ["wireless", "appliance"]
+ network_kwargs = {
+ "tags": ["test_tag", "github", "shouldBeDeleted"],
+ "timezone": "America/Los_Angeles",
+ }
+
+ created_network = dashboard.organizations.createOrganizationNetwork(org_id, name, product_types, **network_kwargs)
+ yield created_network
+
+ action = ActionBatchNetworks().deleteNetwork(created_network["id"])
+ for attempt in range(1, 6):
+ delay = 2**attempt
+ time.sleep(delay)
+ batch = dashboard.organizations.createOrganizationActionBatch(
+ organizationId=org_id, actions=[action], confirmed=True, synchronous=False
+ )
+ for _ in range(10):
+ time.sleep(delay)
+ status = dashboard.organizations.getOrganizationActionBatch(org_id, batch["id"])
+ if status["status"]["completed"]:
+ return
+ if status["status"]["failed"]:
+ break
+ if attempt == 5:
+ pytest.fail("Network cleanup action batch failed after 5 attempts")
+
+
+def test_policy_object(dashboard, org_id):
+ salt = _salt()
+ obj = dashboard.organizations.createOrganizationPolicyObject(
+ org_id, name=f"test-policy-object-{salt}", category="network", type="cidr", cidr="10.0.0.0/24"
+ )
+ assert isinstance(obj["id"], str)
+
+ dashboard.organizations.updateOrganizationPolicyObject(org_id, obj["id"], name=f"test-policy-object-{salt}-r")
+ dashboard.organizations.deleteOrganizationPolicyObject(org_id, obj["id"])
+
+
+def test_policy_object_group(dashboard, org_id):
+ salt = _salt()
+ group = dashboard.organizations.createOrganizationPolicyObjectsGroup(
+ org_id, name=f"test-policy-group-{salt}", category="NetworkObjectGroup"
+ )
+ assert isinstance(group["id"], str)
+
+ dashboard.organizations.updateOrganizationPolicyObjectsGroup(org_id, group["id"], name=f"test-policy-group-{salt}-r")
+ dashboard.organizations.deleteOrganizationPolicyObjectsGroup(org_id, group["id"])
+
+
+def test_alerts_profile(dashboard, org_id):
+ salt = _salt()
+ profile = dashboard.organizations.createOrganizationAlertsProfile(
+ org_id,
+ type="wanUtilization",
+ alertCondition={"duration": 60, "window": 600, "bit_rate_bps": 1000000, "interface": "wan1"},
+ recipients={"emails": ["test@example.com"]},
+ networkTags=["__all_tags__"],
+ description=f"test-alert-profile-{salt}",
+ )
+ assert isinstance(profile["id"], str)
+
+ dashboard.organizations.updateOrganizationAlertsProfile(org_id, profile["id"], description=f"test-alert-profile-{salt}-r")
+ dashboard.organizations.deleteOrganizationAlertsProfile(org_id, profile["id"])
+
+
+def test_group_policy(dashboard, network):
+ salt = _salt()
+ gp = dashboard.networks.createNetworkGroupPolicy(network["id"], name=f"test-group-policy-{salt}")
+ assert "groupPolicyId" in gp
+
+ dashboard.networks.updateNetworkGroupPolicy(network["id"], gp["groupPolicyId"], name=f"test-group-policy-{salt}-r")
+ dashboard.networks.deleteNetworkGroupPolicy(network["id"], gp["groupPolicyId"])
+
+
+def test_mqtt_broker(dashboard, network):
+ salt = _salt()
+ broker = dashboard.networks.createNetworkMqttBroker(
+ network["id"], name=f"test-mqtt-broker-{salt}", host="mqtt.example.com", port=1883
+ )
+ assert isinstance(broker["id"], str)
+
+ dashboard.networks.updateNetworkMqttBroker(network["id"], broker["id"], name=f"test-mqtt-broker-{salt}-r")
+ dashboard.networks.deleteNetworkMqttBroker(network["id"], broker["id"])
+
+
+def test_webhook_http_server(dashboard, network):
+ salt = _salt()
+ server = dashboard.networks.createNetworkWebhooksHttpServer(
+ network["id"], name=f"test-webhook-server-{salt}", url="https://example.com/webhook"
+ )
+ assert isinstance(server["id"], str)
+
+ dashboard.networks.updateNetworkWebhooksHttpServer(network["id"], server["id"], name=f"test-webhook-server-{salt}-r")
+ dashboard.networks.deleteNetworkWebhooksHttpServer(network["id"], server["id"])
+
+
+def test_webhook_payload_template(dashboard, network):
+ salt = _salt()
+ template = dashboard.networks.createNetworkWebhooksPayloadTemplate(
+ network["id"],
+ name=f"test-payload-template-{salt}",
+ body='{"event": "{{alertType}}", "network": "{{networkName}}"}',
+ )
+ assert "payloadTemplateId" in template
+
+ dashboard.networks.deleteNetworkWebhooksPayloadTemplate(network["id"], template["payloadTemplateId"])
+
+
+def test_ssid(dashboard, network):
+ ssid = dashboard.wireless.getNetworkWirelessSsid(network["id"], "0")
+ original_name = ssid["name"]
+
+ dashboard.wireless.updateNetworkWirelessSsid(network["id"], "0", name="test-ssid-renamed")
+ dashboard.wireless.updateNetworkWirelessSsid(network["id"], "0", name=original_name)
+
+
+def test_network_settings(dashboard, network):
+ settings = dashboard.networks.getNetworkSettings(network["id"])
+ original = settings.get("localStatusPageEnabled", True)
+
+ dashboard.networks.updateNetworkSettings(network["id"], localStatusPageEnabled=not original)
+ dashboard.networks.updateNetworkSettings(network["id"], localStatusPageEnabled=original)
+
+
+def test_action_batch(dashboard, org_id, network):
+ actions = [
+ {
+ "resource": f"/networks/{network['id']}/wireless/airMarshal/rules",
+ "operation": "create",
+ "body": {"type": "block", "match": {"string": f"test-rule-{i}", "type": "bssid"}},
+ }
+ for i in range(1, 4)
+ ]
+
+ batch = dashboard.organizations.createOrganizationActionBatch(org_id, actions, confirmed=True, synchronous=False)
+ assert isinstance(batch["id"], str)
+
+ for _ in range(30):
+ time.sleep(2)
+ status = dashboard.organizations.getOrganizationActionBatch(org_id, batch["id"])
+ if status["status"]["completed"]:
+ assert len(status["actions"]) == 3
+ return
+ if status["status"]["failed"]:
+ pytest.fail(f"Action batch {batch['id']} failed")
+
+ pytest.fail("Action batch did not complete within timeout")
diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py
new file mode 100644
index 00000000..316aafc8
--- /dev/null
+++ b/tests/unit/conftest.py
@@ -0,0 +1,144 @@
+"""Shared fixtures and helpers for unit tests."""
+
+import json
+from unittest.mock import AsyncMock, MagicMock, patch
+
+import httpx
+import pytest
+
+from meraki.session.sync import RestSession
+
+
+FAKE_API_KEY = "fake_api_key_1234567890123456789012345678901234567890"
+
+DEFAULT_SESSION_KWARGS = {
+ "base_url": "https://api.meraki.com/api/v1",
+ "single_request_timeout": 60,
+ "certificate_path": "",
+ "requests_proxy": "",
+ "wait_on_rate_limit": True,
+ "nginx_429_retry_wait_time": 2,
+ "action_batch_retry_wait_time": 2,
+ "network_delete_retry_wait_time": 2,
+ "retry_4xx_error": False,
+ "retry_4xx_error_wait_time": 1,
+ "maximum_retries": 3,
+ "simulate": False,
+ "be_geo_id": "",
+ "caller": "TestApp TestVendor",
+ "use_iterator_for_get_pages": False,
+}
+
+
+def make_metadata(operation="getOrganizations", tags=None, **extra):
+ meta = {"tags": tags or ["organizations"], "operation": operation}
+ meta.update(extra)
+ return meta
+
+
+def make_mock_response(
+ status_code=200,
+ json_data=None,
+ reason_phrase="OK",
+ headers=None,
+ content=None,
+ links=None,
+):
+ resp = MagicMock(spec=httpx.Response)
+ resp.status_code = status_code
+ resp.reason_phrase = reason_phrase
+ resp.headers = headers or {}
+ resp.links = links or {}
+ if content is not None:
+ resp.content = content
+ else:
+ resp.content = json.dumps(json_data if json_data is not None else {"ok": True}).encode()
+ resp.json.return_value = json_data if json_data is not None else {"ok": True}
+ resp.text = json.dumps(json_data if json_data is not None else {"ok": True})
+ resp.close = MagicMock()
+ return resp
+
+
+def make_async_mock_response(
+ status_code=200,
+ json_data=None,
+ reason_phrase="OK",
+ headers=None,
+ content=None,
+ links=None,
+):
+ resp = make_mock_response(
+ status_code=status_code,
+ json_data=json_data,
+ reason_phrase=reason_phrase,
+ headers=headers,
+ content=content,
+ links=links,
+ )
+ resp.close = MagicMock(side_effect=RuntimeError("Attempted to call sync close on an async stream."))
+ resp.aclose = AsyncMock()
+ return resp
+
+
+def make_sync_session(logger=None, **overrides):
+ kwargs = {**DEFAULT_SESSION_KWARGS, **overrides}
+ with patch("meraki.session.base.check_python_version"):
+ with patch("httpx.Client") as mock_client:
+ mock_instance = MagicMock()
+ mock_instance.headers = MagicMock(spec=dict)
+ mock_client.return_value = mock_instance
+ s = RestSession(logger=logger, api_key=FAKE_API_KEY, **kwargs)
+ if s._smart_flow:
+ s._smart_flow = MagicMock()
+ return s
+
+
+def make_async_session(logger=None, **overrides):
+ kwargs = {"maximum_concurrent_requests": 8, **DEFAULT_SESSION_KWARGS, **overrides}
+ with (
+ patch("meraki.session.base.check_python_version"),
+ patch("httpx.AsyncClient") as mock_client,
+ ):
+ mock_instance = MagicMock()
+ mock_instance.headers = {}
+ mock_instance.request = AsyncMock()
+ mock_client.return_value = mock_instance
+ from meraki.session.async_ import AsyncRestSession
+
+ s = AsyncRestSession(logger=logger, api_key=FAKE_API_KEY, **kwargs)
+ return s
+
+
+# --- Pytest fixtures wrapping the factories ---
+
+
+@pytest.fixture
+def session():
+ return make_sync_session()
+
+
+@pytest.fixture
+def session_with_logger():
+ return make_sync_session(logger=MagicMock())
+
+
+@pytest.fixture
+def async_session():
+ return make_async_session()
+
+
+@pytest.fixture
+def async_session_with_logger():
+ return make_async_session(logger=MagicMock())
+
+
+@pytest.fixture
+def async_session_with_cert(tmp_path):
+ cert_file = tmp_path / "cert.pem"
+ cert_file.write_text("FAKE CERT")
+ return make_async_session(certificate_path=str(cert_file))
+
+
+@pytest.fixture
+def async_session_with_proxy():
+ return make_async_session(requests_proxy="http://proxy:8080")
diff --git a/tests/unit/test_aio_rest_session.py b/tests/unit/test_aio_rest_session.py
index d198b50f..2db7750e 100644
--- a/tests/unit/test_aio_rest_session.py
+++ b/tests/unit/test_aio_rest_session.py
@@ -1,220 +1,27 @@
import json
from unittest.mock import AsyncMock, MagicMock, patch
-import aiohttp
+import httpx
import pytest
-from meraki.exceptions import AsyncAPIError
+from meraki.exceptions import APIError
-
-class _AwaitableValue:
- """A wrapper that makes a value both usable directly and awaitable.
-
- This is needed because the async rest session does `await response.json()`
- while APIError.__init__ calls `response.json()` synchronously.
- """
-
- def __init__(self, value):
- self._value = value
-
- def __await__(self):
- async def _resolve():
- return self._value
-
- return _resolve().__await__()
-
- def __bool__(self):
- return bool(self._value)
-
- def __getitem__(self, key):
- return self._value[key]
-
- def __contains__(self, item):
- return item in self._value
-
- def __eq__(self, other):
- if isinstance(other, _AwaitableValue):
- return self._value == other._value
- return self._value == other
-
- def __repr__(self):
- return repr(self._value)
-
- def keys(self):
- return self._value.keys()
-
- def values(self):
- return self._value.values()
-
- def items(self):
- return self._value.items()
+from tests.unit.conftest import make_metadata as _metadata, make_async_mock_response as _mock_aio_response
async def _noop_sleep(*args, **kwargs):
pass
-@pytest.fixture
-def async_session():
- with (
- patch("meraki.aio.rest_session.check_python_version"),
- patch("aiohttp.ClientSession") as mock_client,
- ):
- mock_client.return_value = MagicMock()
- from meraki.aio.rest_session import AsyncRestSession
-
- s = AsyncRestSession(
- logger=None,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- certificate_path="",
- requests_proxy="",
- wait_on_rate_limit=True,
- nginx_429_retry_wait_time=2,
- action_batch_retry_wait_time=2,
- network_delete_retry_wait_time=2,
- retry_4xx_error=False,
- retry_4xx_error_wait_time=1,
- maximum_retries=3,
- simulate=False,
- be_geo_id="",
- caller="TestApp TestVendor",
- use_iterator_for_get_pages=False,
- maximum_concurrent_requests=8,
- )
- return s
-
-
-@pytest.fixture
-def async_session_with_logger():
- with (
- patch("meraki.aio.rest_session.check_python_version"),
- patch("aiohttp.ClientSession") as mock_client,
- ):
- mock_client.return_value = MagicMock()
- from meraki.aio.rest_session import AsyncRestSession
-
- logger = MagicMock()
- s = AsyncRestSession(
- logger=logger,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- certificate_path="",
- requests_proxy="",
- wait_on_rate_limit=True,
- nginx_429_retry_wait_time=2,
- action_batch_retry_wait_time=2,
- network_delete_retry_wait_time=2,
- retry_4xx_error=False,
- retry_4xx_error_wait_time=1,
- maximum_retries=3,
- simulate=False,
- be_geo_id="",
- caller="TestApp TestVendor",
- use_iterator_for_get_pages=False,
- maximum_concurrent_requests=8,
- )
- return s
-
-
-@pytest.fixture
-def async_session_with_cert(tmp_path):
- cert_file = tmp_path / "cert.pem"
- cert_file.write_text("FAKE CERT")
- with (
- patch("meraki.aio.rest_session.check_python_version"),
- patch("aiohttp.ClientSession") as mock_client,
- patch("ssl.create_default_context") as mock_ssl,
- ):
- mock_client.return_value = MagicMock()
- mock_ctx = MagicMock()
- mock_ssl.return_value = mock_ctx
- from meraki.aio.rest_session import AsyncRestSession
-
- s = AsyncRestSession(
- logger=None,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- certificate_path=str(cert_file),
- requests_proxy="",
- wait_on_rate_limit=True,
- nginx_429_retry_wait_time=2,
- action_batch_retry_wait_time=2,
- network_delete_retry_wait_time=2,
- retry_4xx_error=False,
- retry_4xx_error_wait_time=1,
- maximum_retries=3,
- simulate=False,
- be_geo_id="",
- caller="TestApp TestVendor",
- use_iterator_for_get_pages=False,
- maximum_concurrent_requests=8,
- )
- return s
-
-
-@pytest.fixture
-def async_session_with_proxy():
- with (
- patch("meraki.aio.rest_session.check_python_version"),
- patch("aiohttp.ClientSession") as mock_client,
- ):
- mock_client.return_value = MagicMock()
- from meraki.aio.rest_session import AsyncRestSession
-
- s = AsyncRestSession(
- logger=None,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- certificate_path="",
- requests_proxy="http://proxy:8080",
- wait_on_rate_limit=True,
- nginx_429_retry_wait_time=2,
- action_batch_retry_wait_time=2,
- network_delete_retry_wait_time=2,
- retry_4xx_error=False,
- retry_4xx_error_wait_time=1,
- maximum_retries=3,
- simulate=False,
- be_geo_id="",
- caller="TestApp TestVendor",
- use_iterator_for_get_pages=False,
- maximum_concurrent_requests=8,
- )
- return s
-
-
-def _metadata(operation="getOrganizations", tags=None):
- return {"tags": tags or ["organizations"], "operation": operation}
-
-
-def _mock_aio_response(status=200, json_data=None, reason="OK", headers=None, links=None):
- resp = MagicMock()
- resp.status = status
- resp.reason = reason
- resp.headers = headers or {}
- resp.links = links or {}
- resp.json = MagicMock(return_value=_AwaitableValue(json_data if json_data is not None else {"ok": True}))
- resp.text = AsyncMock(return_value="")
- resp.release = MagicMock()
- resp.__aenter__ = AsyncMock(return_value=resp)
- resp.__aexit__ = AsyncMock(return_value=False)
- return resp
-
-
-SLEEP_PATCH = "meraki.aio.rest_session.asyncio.sleep"
+SLEEP_PATCH = "meraki.session.async_.asyncio.sleep"
# --- Init tests ---
class TestAsyncInit:
- def test_certificate_path_creates_ssl_context(self, async_session_with_cert):
- assert hasattr(async_session_with_cert, "_sslcontext")
+ def test_certificate_path_passed_to_client(self, async_session_with_cert):
+ assert async_session_with_cert._certificate_path
def test_proxy_stored(self, async_session_with_proxy):
assert async_session_with_proxy._requests_proxy == "http://proxy:8080"
@@ -239,31 +46,13 @@ def test_use_iterator_property_setter(self, async_session):
class TestAsyncRequestKwargs:
@pytest.mark.asyncio
- async def test_ssl_context_passed(self, async_session_with_cert):
- resp_200 = _mock_aio_response(200)
- async_session_with_cert._req_session.request = AsyncMock(return_value=resp_200)
+ async def test_follow_redirects_false(self, async_session):
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
- await async_session_with_cert._request(_metadata(), "GET", "/orgs")
- call_kwargs = async_session_with_cert._req_session.request.call_args[1]
- assert "ssl" in call_kwargs
-
- @pytest.mark.asyncio
- async def test_proxy_passed(self, async_session_with_proxy):
- resp_200 = _mock_aio_response(200)
- async_session_with_proxy._req_session.request = AsyncMock(return_value=resp_200)
-
- await async_session_with_proxy._request(_metadata(), "GET", "/orgs")
- call_kwargs = async_session_with_proxy._req_session.request.call_args[1]
- assert call_kwargs["proxy"] == "http://proxy:8080"
-
- @pytest.mark.asyncio
- async def test_timeout_set(self, async_session):
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(return_value=resp_200)
-
- await async_session._request(_metadata(), "GET", "/orgs")
- call_kwargs = async_session._req_session.request.call_args[1]
- assert call_kwargs["timeout"] == 60
+ await async_session.request(_metadata(), "GET", "/orgs")
+ call_kwargs = async_session._client.request.call_args[1]
+ assert call_kwargs.get("follow_redirects") is False
# --- URL handling ---
@@ -272,42 +61,42 @@ async def test_timeout_set(self, async_session):
class TestAsyncURLHandling:
@pytest.mark.asyncio
async def test_relative_url_prepends_base(self, async_session):
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
- await async_session._request(_metadata(), "GET", "/organizations")
- call_args = async_session._req_session.request.call_args[0]
+ await async_session.request(_metadata(), "GET", "/organizations")
+ call_args = async_session._client.request.call_args[0]
assert call_args[1] == "https://api.meraki.com/api/v1/organizations"
@pytest.mark.asyncio
async def test_absolute_meraki_url_not_prepended(self, async_session):
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
- await async_session._request(_metadata(), "GET", "https://n123.meraki.com/api/v1/orgs")
- call_args = async_session._req_session.request.call_args[0]
+ await async_session.request(_metadata(), "GET", "https://n123.meraki.com/api/v1/orgs")
+ call_args = async_session._client.request.call_args[0]
assert call_args[1] == "https://n123.meraki.com/api/v1/orgs"
@pytest.mark.asyncio
async def test_meraki_cn_domain_recognized(self, async_session):
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
- await async_session._request(_metadata(), "GET", "https://n123.meraki.cn/api/v1/orgs")
- call_args = async_session._req_session.request.call_args[0]
+ await async_session.request(_metadata(), "GET", "https://n123.meraki.cn/api/v1/orgs")
+ call_args = async_session._client.request.call_args[0]
assert call_args[1] == "https://n123.meraki.cn/api/v1/orgs"
@pytest.mark.asyncio
async def test_non_string_url_converted(self, async_session):
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
class FakeURL:
def __str__(self):
return "https://n1.meraki.com/api/v1/orgs"
- await async_session._request(_metadata(), "GET", FakeURL())
- call_args = async_session._req_session.request.call_args[0]
+ await async_session.request(_metadata(), "GET", FakeURL())
+ call_args = async_session._client.request.call_args[0]
assert call_args[1] == "https://n1.meraki.com/api/v1/orgs"
@@ -317,36 +106,59 @@ def __str__(self):
class TestAsyncRetry429:
@pytest.mark.asyncio
async def test_retry_on_429_with_retry_after(self, async_session):
- resp_429 = _mock_aio_response(429, reason="Too Many Requests", headers={"Retry-After": "1"})
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_429, resp_200])
+ resp_429 = _mock_aio_response(status_code=429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_429, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_retry_on_429_without_retry_after(self, async_session):
- resp_429 = _mock_aio_response(429, reason="Too Many Requests")
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_429, resp_200])
+ resp_429 = _mock_aio_response(status_code=429, reason_phrase="Too Many Requests")
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_429, resp_200])
with (
patch(SLEEP_PATCH, side_effect=_noop_sleep),
patch("random.randint", return_value=1),
):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_429_raises_after_max_retries(self, async_session):
async_session._maximum_retries = 2
- resp_429 = _mock_aio_response(429, reason="Too Many Requests", headers={"Retry-After": "1"})
- async_session._req_session.request = AsyncMock(return_value=resp_429)
+ resp_429 = _mock_aio_response(status_code=429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
+ async_session._client.request = AsyncMock(return_value=resp_429)
+
+ with patch(SLEEP_PATCH, side_effect=_noop_sleep):
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
+
+ @pytest.mark.asyncio
+ async def test_429_retry_count_matches_maximum_retries(self, async_session):
+ async_session._maximum_retries = 3
+ resp_429 = _mock_aio_response(status_code=429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
+ async_session._client.request = AsyncMock(return_value=resp_429)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
+
+ assert async_session._client.request.call_count == 3
+
+ @pytest.mark.asyncio
+ async def test_429_uses_retry_after_header_value(self, async_session):
+ resp_429 = _mock_aio_response(status_code=429, reason_phrase="Too Many Requests", headers={"Retry-After": "42"})
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_429, resp_200])
+
+ with patch(SLEEP_PATCH, side_effect=_noop_sleep) as mock_sleep:
+ await async_session.request(_metadata(), "GET", "/organizations")
+
+ mock_sleep.assert_called_once_with(42)
# --- Retry on 5xx ---
@@ -355,29 +167,39 @@ async def test_429_raises_after_max_retries(self, async_session):
class TestAsyncRetry5xx:
@pytest.mark.asyncio
async def test_retry_on_500(self, async_session):
- resp_500 = _mock_aio_response(500, reason="Internal Server Error")
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_500, resp_200])
+ resp_500 = _mock_aio_response(status_code=500, reason_phrase="Internal Server Error")
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_500, resp_200])
+
+ with patch(SLEEP_PATCH, side_effect=_noop_sleep):
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
+
+ @pytest.mark.asyncio
+ async def test_5xx_raises_after_max_retries(self, async_session):
+ async_session._maximum_retries = 2
+ resp_500 = _mock_aio_response(status_code=500, reason_phrase="Internal Server Error")
+ async_session._client.request = AsyncMock(return_value=resp_500)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
@pytest.mark.asyncio
async def test_request_id_logged_in_warning(self, async_session_with_logger):
session = async_session_with_logger
resp_500 = _mock_aio_response(
- 500,
- reason="Internal Server Error",
+ status_code=500,
+ reason_phrase="Internal Server Error",
headers={"X-Request-Id": "abc123def456"},
)
- resp_200 = _mock_aio_response(200)
- session._req_session.request = AsyncMock(side_effect=[resp_500, resp_200])
+ resp_200 = _mock_aio_response(status_code=200)
+ session._client.request = AsyncMock(side_effect=[resp_500, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await session._request(_metadata(), "GET", "/organizations")
+ result = await session.request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ assert result.status_code == 200
warning_messages = [c.args[0] for c in session._logger.warning.call_args_list]
assert any("X-Request-Id: abc123def456" in m for m in warning_messages)
@@ -386,15 +208,15 @@ async def test_request_id_logged_as_error_after_exhausting_retries(self, async_s
session = async_session_with_logger
session._maximum_retries = 2
resp_500 = _mock_aio_response(
- 500,
- reason="Internal Server Error",
+ status_code=500,
+ reason_phrase="Internal Server Error",
headers={"X-Request-Id": "deadbeef00112233"},
)
- session._req_session.request = AsyncMock(return_value=resp_500)
+ session._client.request = AsyncMock(return_value=resp_500)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await session.request(_metadata(), "GET", "/organizations")
error_messages = [c.args[0] for c in session._logger.error.call_args_list]
assert any("deadbeef00112233" in m for m in error_messages)
@@ -404,28 +226,18 @@ async def test_request_id_logged_as_error_after_exhausting_retries(self, async_s
async def test_no_request_id_logs_none(self, async_session_with_logger):
session = async_session_with_logger
session._maximum_retries = 2
- resp_500 = _mock_aio_response(500, reason="Internal Server Error", headers={})
- session._req_session.request = AsyncMock(return_value=resp_500)
+ resp_500 = _mock_aio_response(status_code=500, reason_phrase="Internal Server Error", headers={})
+ session._client.request = AsyncMock(return_value=resp_500)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await session.request(_metadata(), "GET", "/organizations")
warning_messages = [c.args[0] for c in session._logger.warning.call_args_list]
assert any("X-Request-Id: none" in m for m in warning_messages)
error_messages = [c.args[0] for c in session._logger.error.call_args_list]
assert any("log lookup: none" in m for m in error_messages)
- @pytest.mark.asyncio
- async def test_5xx_raises_after_max_retries(self, async_session):
- async_session._maximum_retries = 2
- resp_500 = _mock_aio_response(500, reason="Internal Server Error")
- async_session._req_session.request = AsyncMock(return_value=resp_500)
-
- with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
-
# --- Connection errors ---
@@ -433,21 +245,21 @@ async def test_5xx_raises_after_max_retries(self, async_session):
class TestAsyncConnectionErrors:
@pytest.mark.asyncio
async def test_retry_on_exception(self, async_session):
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[Exception("Connection refused"), resp_200])
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[httpx.ConnectError("Connection refused"), resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_exception_raises_after_max_retries(self, async_session):
async_session._maximum_retries = 2
- async_session._req_session.request = AsyncMock(side_effect=Exception("Connection refused"))
+ async_session._client.request = AsyncMock(side_effect=httpx.ConnectError("Connection refused"))
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
# --- 4xx errors ---
@@ -456,117 +268,109 @@ async def test_exception_raises_after_max_retries(self, async_session):
class TestAsync4xx:
@pytest.mark.asyncio
async def test_generic_4xx_raises(self, async_session):
- resp_400 = _mock_aio_response(400, json_data={"errors": ["bad"]}, reason="Bad Request")
- async_session._req_session.request = AsyncMock(return_value=resp_400)
+ resp_400 = _mock_aio_response(status_code=400, json_data={"errors": ["bad"]}, reason_phrase="Bad Request")
+ async_session._client.request = AsyncMock(return_value=resp_400)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
@pytest.mark.asyncio
async def test_retry_4xx_when_enabled(self, async_session):
async_session._retry_4xx_error = True
- resp_400 = _mock_aio_response(400, json_data={"errors": ["something"]}, reason="Bad Request")
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_400, resp_200])
+ resp_400 = _mock_aio_response(status_code=400, json_data={"errors": ["something"]}, reason_phrase="Bad Request")
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_400, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
with patch("random.randint", return_value=1):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_network_delete_concurrency_retries(self, async_session):
async_session._maximum_retries = 3
error_msg = {"errors": ["This may be due to concurrent requests to delete networks. Please retry."]}
- resp_400 = _mock_aio_response(400, json_data=error_msg, reason="Bad Request")
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_400, resp_200])
+ resp_400 = _mock_aio_response(status_code=400, json_data=error_msg, reason_phrase="Bad Request")
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_400, resp_200])
with (
patch(SLEEP_PATCH, side_effect=_noop_sleep),
- patch("time.sleep"),
patch("random.randint", return_value=1),
):
- result = await async_session._request(_metadata(), "GET", "/networks")
- assert result.status == 200
+ result = await async_session.request(_metadata(operation="deleteNetwork"), "GET", "/networks")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_network_delete_concurrency_exhausts_retries(self, async_session):
async_session._maximum_retries = 2
error_msg = {"errors": ["This may be due to concurrent requests to delete networks. Please retry."]}
- resp_400 = _mock_aio_response(400, json_data=error_msg, reason="Bad Request")
- async_session._req_session.request = AsyncMock(return_value=resp_400)
-
- from meraki.exceptions import APIError
+ resp_400 = _mock_aio_response(status_code=400, json_data=error_msg, reason_phrase="Bad Request")
+ async_session._client.request = AsyncMock(return_value=resp_400)
with (
patch(SLEEP_PATCH, side_effect=_noop_sleep),
- patch("time.sleep"),
patch("random.randint", return_value=1),
):
- with pytest.raises((APIError, AsyncAPIError)):
- await async_session._request(_metadata(), "GET", "/networks")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(operation="deleteNetwork"), "GET", "/networks")
@pytest.mark.asyncio
async def test_action_batch_concurrency_retries(self, async_session):
error_msg = {
"errors": ["Too many concurrently executing batches. Maximum is 5 confirmed but not yet executed batches."]
}
- resp_400 = _mock_aio_response(400, json_data=error_msg, reason="Bad Request")
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_400, resp_200])
+ resp_400 = _mock_aio_response(status_code=400, json_data=error_msg, reason_phrase="Bad Request")
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_400, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/batches")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/batches")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_4xx_non_json_response(self, async_session):
resp_400 = MagicMock()
- resp_400.status = 400
- resp_400.reason = "Bad Request"
+ resp_400.status_code = 400
+ resp_400.reason_phrase = "Bad Request"
resp_400.headers = {}
resp_400.links = {}
- resp_400.json = AsyncMock(side_effect=json.decoder.JSONDecodeError("", "", 0))
- resp_400.text = AsyncMock(return_value="Some HTML error page content")
- resp_400.release = MagicMock()
- resp_400.__aenter__ = AsyncMock(return_value=resp_400)
- resp_400.__aexit__ = AsyncMock(return_value=False)
+ resp_400.json = MagicMock(side_effect=json.decoder.JSONDecodeError("", "", 0))
+ resp_400.text = "Some HTML error page content"
+ resp_400.close = MagicMock()
- async_session._req_session.request = AsyncMock(return_value=resp_400)
+ async_session._client.request = AsyncMock(return_value=resp_400)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
@pytest.mark.asyncio
async def test_4xx_non_json_text_fails_too(self, async_session):
resp_400 = MagicMock()
- resp_400.status = 400
- resp_400.reason = "Bad Request"
+ resp_400.status_code = 400
+ resp_400.reason_phrase = "Bad Request"
resp_400.headers = {}
resp_400.links = {}
- resp_400.json = AsyncMock(side_effect=aiohttp.client_exceptions.ContentTypeError(MagicMock(), MagicMock()))
- resp_400.text = AsyncMock(side_effect=Exception("read error"))
- resp_400.release = MagicMock()
- resp_400.__aenter__ = AsyncMock(return_value=resp_400)
- resp_400.__aexit__ = AsyncMock(return_value=False)
+ resp_400.json = MagicMock(side_effect=ValueError("Invalid JSON"))
+ resp_400.text = MagicMock(side_effect=Exception("read error"))
+ resp_400.close = MagicMock()
- async_session._req_session.request = AsyncMock(return_value=resp_400)
+ async_session._client.request = AsyncMock(return_value=resp_400)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
@pytest.mark.asyncio
async def test_4xx_non_dict_json_response(self, async_session):
- resp_400 = _mock_aio_response(400, json_data="just a string", reason="Bad Request")
- async_session._req_session.request = AsyncMock(return_value=resp_400)
+ resp_400 = _mock_aio_response(status_code=400, json_data="just a string", reason_phrase="Bad Request")
+ async_session._client.request = AsyncMock(return_value=resp_400)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session.request(_metadata(), "GET", "/organizations")
# --- 3xx redirect ---
@@ -576,31 +380,31 @@ class TestAsyncRedirect:
@pytest.mark.asyncio
async def test_follows_redirect(self, async_session):
resp_301 = _mock_aio_response(
- 301,
- reason="Moved",
+ status_code=301,
+ reason_phrase="Moved",
headers={"Location": "https://n123.meraki.com/api/v1/organizations"},
)
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_301, resp_200])
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_301, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
assert async_session._base_url == "https://n123.meraki.com/api/v1"
@pytest.mark.asyncio
async def test_redirect_to_cn_domain(self, async_session):
resp_301 = _mock_aio_response(
- 301,
- reason="Moved",
+ status_code=301,
+ reason_phrase="Moved",
headers={"Location": "https://n123.meraki.cn/api/v1/organizations"},
)
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(side_effect=[resp_301, resp_200])
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(side_effect=[resp_301, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
assert "meraki.cn" in async_session._base_url
@@ -611,22 +415,22 @@ class TestAsyncSimulate:
@pytest.mark.asyncio
async def test_simulate_skips_non_get(self, async_session):
async_session._simulate = True
- result = await async_session._request(_metadata(), "POST", "/organizations")
+ result = await async_session.request(_metadata(), "POST", "/organizations")
assert result is None
@pytest.mark.asyncio
async def test_simulate_allows_get(self, async_session):
async_session._simulate = True
- resp_200 = _mock_aio_response(200)
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_simulate_with_logger(self, async_session_with_logger):
async_session_with_logger._simulate = True
- result = await async_session_with_logger._request(_metadata(), "POST", "/organizations")
+ result = await async_session_with_logger.request(_metadata(), "POST", "/organizations")
assert result is None
assert async_session_with_logger._logger.info.call_count >= 1
@@ -637,59 +441,58 @@ async def test_simulate_with_logger(self, async_session_with_logger):
class TestAsync2xxResponse:
@pytest.mark.asyncio
async def test_success_with_page_metadata(self, async_session_with_logger):
- resp_200 = _mock_aio_response(200, json_data=[{"id": 1}])
- async_session_with_logger._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
+ async_session_with_logger._client.request = AsyncMock(return_value=resp_200)
metadata = _metadata()
metadata["page"] = 3
- result = await async_session_with_logger._request(metadata, "GET", "/organizations")
- assert result.status == 200
+ result = await async_session_with_logger.request(metadata, "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_success_without_page_metadata(self, async_session_with_logger):
- resp_200 = _mock_aio_response(200, json_data=[{"id": 1}])
- async_session_with_logger._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
+ async_session_with_logger._client.request = AsyncMock(return_value=resp_200)
- result = await async_session_with_logger._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session_with_logger.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_get_retries_on_invalid_json(self, async_session):
resp_bad_json = MagicMock()
- resp_bad_json.status = 200
- resp_bad_json.reason = "OK"
+ resp_bad_json.status_code = 200
+ resp_bad_json.reason_phrase = "OK"
resp_bad_json.headers = {}
resp_bad_json.links = {}
- resp_bad_json.json = AsyncMock(side_effect=json.decoder.JSONDecodeError("", "", 0))
- resp_bad_json.release = MagicMock()
- resp_bad_json.__aenter__ = AsyncMock(return_value=resp_bad_json)
- resp_bad_json.__aexit__ = AsyncMock(return_value=False)
+ resp_bad_json.json = MagicMock(side_effect=json.decoder.JSONDecodeError("", "", 0))
+ resp_bad_json.close = MagicMock(side_effect=RuntimeError("Attempted to call an sync close on an async stream."))
+ resp_bad_json.aclose = AsyncMock()
- resp_200 = _mock_aio_response(200, json_data={"ok": True})
+ resp_200 = _mock_aio_response(status_code=200, json_data={"ok": True})
- async_session._req_session.request = AsyncMock(side_effect=[resp_bad_json, resp_200])
+ async_session._client.request = AsyncMock(side_effect=[resp_bad_json, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
@pytest.mark.asyncio
async def test_non_get_returns_without_json_validation(self, async_session):
- resp_200 = _mock_aio_response(200, json_data={"id": "abc"})
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200, json_data={"id": "abc"})
+ async_session._client.request = AsyncMock(return_value=resp_200)
- result = await async_session._request(_metadata(), "POST", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "POST", "/organizations")
+ assert result.status_code == 200
resp_200.json.assert_not_called()
@pytest.mark.asyncio
async def test_response_with_no_reason(self, async_session):
- resp_200 = _mock_aio_response(200)
+ resp_200 = _mock_aio_response(status_code=200)
resp_200.reason = None
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ async_session._client.request = AsyncMock(return_value=resp_200)
- result = await async_session._request(_metadata(), "GET", "/organizations")
- assert result.status == 200
+ result = await async_session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
# --- Logger coverage in request flow ---
@@ -698,78 +501,77 @@ async def test_response_with_no_reason(self, async_session):
class TestAsyncRequestLogging:
@pytest.mark.asyncio
async def test_logs_debug_metadata(self, async_session_with_logger):
- resp_200 = _mock_aio_response(200)
- async_session_with_logger._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session_with_logger._client.request = AsyncMock(return_value=resp_200)
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
async_session_with_logger._logger.debug.assert_called()
@pytest.mark.asyncio
async def test_logs_request_url(self, async_session_with_logger):
- resp_200 = _mock_aio_response(200)
- async_session_with_logger._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session_with_logger._client.request = AsyncMock(return_value=resp_200)
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
info_calls = [str(c) for c in async_session_with_logger._logger.info.call_args_list]
assert any("GET" in c for c in info_calls)
@pytest.mark.asyncio
async def test_logs_warning_on_connection_error(self, async_session_with_logger):
- resp_200 = _mock_aio_response(200)
- async_session_with_logger._req_session.request = AsyncMock(side_effect=[Exception("timeout"), resp_200])
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session_with_logger._client.request = AsyncMock(side_effect=[httpx.ConnectError("timeout"), resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
async_session_with_logger._logger.warning.assert_called()
@pytest.mark.asyncio
async def test_logs_warning_on_429(self, async_session_with_logger):
- resp_429 = _mock_aio_response(429, reason="Too Many Requests", headers={"Retry-After": "1"})
- resp_200 = _mock_aio_response(200)
- async_session_with_logger._req_session.request = AsyncMock(side_effect=[resp_429, resp_200])
+ resp_429 = _mock_aio_response(status_code=429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session_with_logger._client.request = AsyncMock(side_effect=[resp_429, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
async_session_with_logger._logger.warning.assert_called()
@pytest.mark.asyncio
async def test_logs_warning_on_5xx(self, async_session_with_logger):
- resp_500 = _mock_aio_response(500, reason="Server Error")
- resp_200 = _mock_aio_response(200)
- async_session_with_logger._req_session.request = AsyncMock(side_effect=[resp_500, resp_200])
+ resp_500 = _mock_aio_response(status_code=500, reason_phrase="Server Error")
+ resp_200 = _mock_aio_response(status_code=200)
+ async_session_with_logger._client.request = AsyncMock(side_effect=[resp_500, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
async_session_with_logger._logger.warning.assert_called()
@pytest.mark.asyncio
async def test_logs_error_on_4xx(self, async_session_with_logger):
- resp_400 = _mock_aio_response(400, json_data={"errors": ["bad"]}, reason="Bad Request")
- async_session_with_logger._req_session.request = AsyncMock(return_value=resp_400)
+ resp_400 = _mock_aio_response(status_code=400, json_data={"errors": ["bad"]}, reason_phrase="Bad Request")
+ async_session_with_logger._client.request = AsyncMock(return_value=resp_400)
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- with pytest.raises(AsyncAPIError):
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ with pytest.raises(APIError):
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
async_session_with_logger._logger.error.assert_called()
@pytest.mark.asyncio
async def test_logs_warning_on_bad_json_200(self, async_session_with_logger):
resp_bad = MagicMock()
- resp_bad.status = 200
- resp_bad.reason = "OK"
+ resp_bad.status_code = 200
+ resp_bad.reason_phrase = "OK"
resp_bad.headers = {}
resp_bad.links = {}
- resp_bad.json = AsyncMock(side_effect=aiohttp.client_exceptions.ContentTypeError(MagicMock(), MagicMock()))
- resp_bad.release = MagicMock()
- resp_bad.__aenter__ = AsyncMock(return_value=resp_bad)
- resp_bad.__aexit__ = AsyncMock(return_value=False)
+ resp_bad.json = MagicMock(side_effect=ValueError("Invalid JSON"))
+ resp_bad.close = MagicMock(side_effect=RuntimeError("Attempted to call an sync close on an async stream."))
+ resp_bad.aclose = AsyncMock()
- resp_200 = _mock_aio_response(200)
+ resp_200 = _mock_aio_response(status_code=200)
- async_session_with_logger._req_session.request = AsyncMock(side_effect=[resp_bad, resp_200])
+ async_session_with_logger._client.request = AsyncMock(side_effect=[resp_bad, resp_200])
with patch(SLEEP_PATCH, side_effect=_noop_sleep):
- await async_session_with_logger._request(_metadata(), "GET", "/organizations")
+ await async_session_with_logger.request(_metadata(), "GET", "/organizations")
async_session_with_logger._logger.warning.assert_called()
@@ -779,49 +581,60 @@ async def test_logs_warning_on_bad_json_200(self, async_session_with_logger):
class TestAsyncHTTPVerbs:
@pytest.mark.asyncio
async def test_get(self, async_session):
- resp_200 = _mock_aio_response(200, json_data={"data": [1, 2, 3]})
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200, json_data={"data": [1, 2, 3]})
+ async_session._client.request = AsyncMock(return_value=resp_200)
result = await async_session.get(_metadata(), "/organizations")
assert result == {"data": [1, 2, 3]}
@pytest.mark.asyncio
async def test_get_with_params(self, async_session):
- resp_200 = _mock_aio_response(200, json_data=[{"id": 1}])
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
+ async_session._client.request = AsyncMock(return_value=resp_200)
result = await async_session.get(_metadata(), "/organizations", params={"perPage": 10})
assert result == [{"id": 1}]
@pytest.mark.asyncio
async def test_post(self, async_session):
- resp_201 = _mock_aio_response(201, json_data={"id": "new"})
- async_session._req_session.request = AsyncMock(return_value=resp_201)
+ resp_201 = _mock_aio_response(status_code=201, json_data={"id": "new"})
+ async_session._client.request = AsyncMock(return_value=resp_201)
result = await async_session.post(_metadata(), "/organizations", json={"name": "Test"})
assert result == {"id": "new"}
@pytest.mark.asyncio
async def test_put(self, async_session):
- resp_200 = _mock_aio_response(200, json_data={"id": "updated"})
- async_session._req_session.request = AsyncMock(return_value=resp_200)
+ resp_200 = _mock_aio_response(status_code=200, json_data={"id": "updated"})
+ async_session._client.request = AsyncMock(return_value=resp_200)
result = await async_session.put(_metadata(), "/organizations/1", json={"name": "New"})
assert result == {"id": "updated"}
@pytest.mark.asyncio
async def test_delete(self, async_session):
- resp_204 = _mock_aio_response(204, json_data=None, reason="No Content")
- async_session._req_session.request = AsyncMock(return_value=resp_204)
+ resp_204 = _mock_aio_response(status_code=204, json_data=None, reason_phrase="No Content")
+ async_session._client.request = AsyncMock(return_value=resp_204)
result = await async_session.delete(_metadata(), "/organizations/1")
assert result is None
+ @pytest.mark.asyncio
+ async def test_delete_passes_query_params(self, async_session):
+ resp_204 = _mock_aio_response(status_code=204, json_data=None, reason_phrase="No Content")
+ async_session._client.request = AsyncMock(return_value=resp_204)
+
+ params = {"force": "true"}
+ result = await async_session.delete(_metadata(), "/networks/1/groupPolicies/1", params)
+ assert result is None
+ call_kwargs = async_session._client.request.call_args
+ assert call_kwargs.kwargs.get("params") == params
+
@pytest.mark.asyncio
async def test_close(self, async_session):
- async_session._req_session.close = AsyncMock()
+ async_session._client.aclose = AsyncMock()
await async_session.close()
- async_session._req_session.close.assert_called_once()
+ async_session._client.aclose.assert_called_once()
# --- Pagination: _get_pages_legacy ---
@@ -830,59 +643,59 @@ async def test_close(self, async_session):
class TestAsyncPaginationLegacy:
@pytest.mark.asyncio
async def test_single_page_no_links(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}, {"id": 2}])
- async_session._req_session.request = AsyncMock(return_value=resp)
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}, {"id": 2}])
+ async_session._client.request = AsyncMock(return_value=resp)
result = await async_session._get_pages_legacy(_metadata(), "/organizations")
assert result == [{"id": 1}, {"id": 2}]
@pytest.mark.asyncio
async def test_multiple_pages_list(self, async_session):
- resp1 = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp1 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp1.links = {"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"}}
- resp2 = _mock_aio_response(200, json_data=[{"id": 2}])
+ resp2 = _mock_aio_response(status_code=200, json_data=[{"id": 2}])
resp2.links = {}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
result = await async_session._get_pages_legacy(_metadata(), "/organizations")
assert result == [{"id": 1}, {"id": 2}]
@pytest.mark.asyncio
async def test_total_pages_string_all(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
result = await async_session._get_pages_legacy(_metadata(), "/organizations", total_pages="all")
assert result == [{"id": 1}]
@pytest.mark.asyncio
async def test_total_pages_numeric_string(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
result = await async_session._get_pages_legacy(_metadata(), "/organizations", total_pages="1")
assert result == [{"id": 1}]
@pytest.mark.asyncio
async def test_total_pages_limit(self, async_session):
- resp1 = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp1 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp1.links = {"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"}}
- resp2 = _mock_aio_response(200, json_data=[{"id": 2}])
+ resp2 = _mock_aio_response(status_code=200, json_data=[{"id": 2}])
resp2.links = {"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=2"}}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
result = await async_session._get_pages_legacy(_metadata(), "/organizations", total_pages=2)
assert result == [{"id": 1}, {"id": 2}]
@pytest.mark.asyncio
async def test_prev_direction(self, async_session):
- resp1 = _mock_aio_response(200, json_data=[{"id": 2}])
+ resp1 = _mock_aio_response(status_code=200, json_data=[{"id": 2}])
resp1.links = {"prev": {"url": "https://api.meraki.com/api/v1/organizations?endingBefore=2"}}
- resp2 = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp2 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp2.links = {}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
result = await async_session._get_pages_legacy(_metadata(), "/organizations", direction="prev")
assert result == [{"id": 2}, {"id": 1}]
@@ -905,7 +718,7 @@ async def test_items_dict_pagination(self, async_session):
},
)
resp2.links = {}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
result = await async_session._get_pages_legacy(_metadata(), "/items")
assert result == {
@@ -933,11 +746,11 @@ async def test_event_log_pagination_next(self, async_session):
},
)
resp2.links = {}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
- with patch("meraki.aio.rest_session.datetime") as mock_dt:
- mock_dt.utcnow.return_value = type(
+ with patch("meraki.session.async_.datetime") as mock_dt:
+ mock_dt.now.return_value = type(
"FakeDT",
(),
{"__sub__": lambda self, other: type("TD", (), {"total_seconds": lambda s: 86400})()},
@@ -959,13 +772,13 @@ async def test_event_log_breaks_on_recent_starting_after(self, async_session):
},
)
resp1.links = {"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-01-01T00:00:00Z"}}
- async_session._req_session.request = AsyncMock(return_value=resp1)
+ async_session._client.request = AsyncMock(return_value=resp1)
metadata = _metadata(operation="getNetworkEvents")
from datetime import datetime
- with patch("meraki.aio.rest_session.datetime") as mock_dt:
- mock_dt.utcnow.return_value = datetime(2024, 1, 1, 0, 2, 0)
+ with patch("meraki.session.async_.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2024, 1, 1, 0, 2, 0)
mock_dt.fromisoformat.return_value = datetime(2024, 1, 1, 0, 0, 0)
result = await async_session._get_pages_legacy(metadata, "/events", direction="next")
@@ -982,13 +795,13 @@ async def test_event_log_breaks_on_end_time(self, async_session):
},
)
resp1.links = {"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-06-01T00:00:00Z"}}
- async_session._req_session.request = AsyncMock(return_value=resp1)
+ async_session._client.request = AsyncMock(return_value=resp1)
metadata = _metadata(operation="getNetworkEvents")
from datetime import datetime
- with patch("meraki.aio.rest_session.datetime") as mock_dt:
- mock_dt.utcnow.return_value = datetime(2025, 1, 1, 0, 0, 0)
+ with patch("meraki.session.async_.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2025, 1, 1, 0, 0, 0)
mock_dt.fromisoformat.return_value = datetime(2024, 6, 1, 0, 0, 0)
result = await async_session._get_pages_legacy(
metadata,
@@ -1009,7 +822,7 @@ async def test_event_log_prev_direction_breaks_before_2014(self, async_session):
},
)
resp1.links = {"prev": {"url": "https://api.meraki.com/api/v1/events?endingBefore=2013-12-31T00:00:00Z"}}
- async_session._req_session.request = AsyncMock(return_value=resp1)
+ async_session._client.request = AsyncMock(return_value=resp1)
metadata = _metadata(operation="getNetworkEvents")
result = await async_session._get_pages_legacy(metadata, "/events", direction="prev")
@@ -1022,9 +835,9 @@ async def test_event_log_prev_direction_breaks_before_2014(self, async_session):
class TestAsyncPaginationIterator:
@pytest.mark.asyncio
async def test_single_page_yields_items(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}, {"id": 2}])
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}, {"id": 2}])
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
items = []
async for item in async_session._get_pages_iterator(_metadata(), "/organizations"):
@@ -1033,11 +846,11 @@ async def test_single_page_yields_items(self, async_session):
@pytest.mark.asyncio
async def test_multiple_pages_yields_all(self, async_session):
- resp1 = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp1 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp1.links = {"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"}}
- resp2 = _mock_aio_response(200, json_data=[{"id": 2}])
+ resp2 = _mock_aio_response(status_code=200, json_data=[{"id": 2}])
resp2.links = {}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
items = []
async for item in async_session._get_pages_iterator(_metadata(), "/organizations"):
@@ -1046,9 +859,9 @@ async def test_multiple_pages_yields_all(self, async_session):
@pytest.mark.asyncio
async def test_total_pages_string_all(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
items = []
async for item in async_session._get_pages_iterator(_metadata(), "/organizations", total_pages="all"):
@@ -1057,9 +870,9 @@ async def test_total_pages_string_all(self, async_session):
@pytest.mark.asyncio
async def test_total_pages_numeric_string(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
items = []
async for item in async_session._get_pages_iterator(_metadata(), "/organizations", total_pages="2"):
@@ -1068,9 +881,9 @@ async def test_total_pages_numeric_string(self, async_session):
@pytest.mark.asyncio
async def test_items_dict_yields_items(self, async_session):
- resp = _mock_aio_response(200, json_data={"items": [{"id": 1}, {"id": 2}]})
+ resp = _mock_aio_response(status_code=200, json_data={"items": [{"id": 1}, {"id": 2}]})
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
items = []
async for item in async_session._get_pages_iterator(_metadata(), "/items"):
@@ -1088,7 +901,7 @@ async def test_event_log_next_yields_reversed(self, async_session):
},
)
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
metadata = _metadata(operation="getNetworkEvents")
items = []
@@ -1107,7 +920,7 @@ async def test_event_log_prev_yields_normal(self, async_session):
},
)
resp.links = {}
- async_session._req_session.request = AsyncMock(return_value=resp)
+ async_session._client.request = AsyncMock(return_value=resp)
metadata = _metadata(operation="someOtherOp")
items = []
@@ -1117,11 +930,11 @@ async def test_event_log_prev_yields_normal(self, async_session):
@pytest.mark.asyncio
async def test_prev_direction_pagination(self, async_session):
- resp1 = _mock_aio_response(200, json_data=[{"id": 2}])
+ resp1 = _mock_aio_response(status_code=200, json_data=[{"id": 2}])
resp1.links = {"prev": {"url": "https://api.meraki.com/api/v1/orgs?endingBefore=2"}}
- resp2 = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp2 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
resp2.links = {}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
items = []
async for item in async_session._get_pages_iterator(_metadata(), "/orgs", direction="prev"):
@@ -1149,14 +962,14 @@ async def test_iterator_event_log_breaks_on_recent(self, async_session):
},
)
resp2.links = {"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-01-02T23:58:00Z"}}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
from datetime import datetime
call_count = [0]
- def fake_utcnow():
+ def fake_now(tz=None):
return datetime(2025, 1, 1, 0, 0, 0)
def fake_fromisoformat(s):
@@ -1165,8 +978,8 @@ def fake_fromisoformat(s):
return datetime(2024, 1, 1, 0, 0, 0)
return datetime(2025, 1, 1, 0, 0, 0)
- with patch("meraki.aio.rest_session.datetime") as mock_dt:
- mock_dt.utcnow = fake_utcnow
+ with patch("meraki.session.async_.datetime") as mock_dt:
+ mock_dt.now = fake_now
mock_dt.fromisoformat = fake_fromisoformat
items = []
async for item in async_session._get_pages_iterator(metadata, "/events", direction="next"):
@@ -1194,14 +1007,14 @@ async def test_iterator_event_log_breaks_on_end_time(self, async_session):
},
)
resp2.links = {"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-06-01T00:00:00Z"}}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
from datetime import datetime
call_count = [0]
- def fake_utcnow():
+ def fake_now(tz=None):
return datetime(2025, 1, 1, 0, 0, 0)
def fake_fromisoformat(s):
@@ -1210,8 +1023,8 @@ def fake_fromisoformat(s):
return datetime(2024, 4, 1, 0, 0, 0)
return datetime(2024, 6, 1, 0, 0, 0)
- with patch("meraki.aio.rest_session.datetime") as mock_dt:
- mock_dt.utcnow = fake_utcnow
+ with patch("meraki.session.async_.datetime") as mock_dt:
+ mock_dt.now = fake_now
mock_dt.fromisoformat = fake_fromisoformat
items = []
async for item in async_session._get_pages_iterator(
@@ -1243,7 +1056,7 @@ async def test_iterator_event_log_prev_breaks_before_2014(self, async_session):
},
)
resp2.links = {"prev": {"url": "https://api.meraki.com/api/v1/events?endingBefore=2013-06-01T00:00:00Z"}}
- async_session._req_session.request = AsyncMock(side_effect=[resp1, resp2])
+ async_session._client.request = AsyncMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
items = []
@@ -1259,8 +1072,222 @@ async def test_iterator_event_log_prev_breaks_before_2014(self, async_session):
class TestAsyncDownloadPage:
@pytest.mark.asyncio
async def test_download_page(self, async_session):
- resp = _mock_aio_response(200, json_data=[{"id": 1}])
+ resp = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
request_coro = AsyncMock(return_value=resp)()
response, result = await async_session._download_page(request_coro)
assert result == [{"id": 1}]
- assert response.status == 200
+ assert response.status_code == 200
+
+ @pytest.mark.asyncio
+ async def test_download_page_204_no_json(self, async_session):
+ """A 204 page yields result=None without calling .json()."""
+ resp = _mock_aio_response(status_code=204, reason_phrase="No Content", content=b"")
+ resp.json = MagicMock(side_effect=json.decoder.JSONDecodeError("", "", 0))
+ request_coro = AsyncMock(return_value=resp)()
+ response, result = await async_session._download_page(request_coro)
+ assert result is None
+ resp.json.assert_not_called()
+
+
+# --- Fix #4: async iterator 204 guard ---
+
+
+class TestAsyncIterator204Guard:
+ @pytest.mark.asyncio
+ async def test_204_page_terminates_iterator_cleanly(self, async_session):
+ """A 204 page terminates the async iterator without JSONDecodeError."""
+ resp_204 = _mock_aio_response(status_code=204, reason_phrase="No Content", content=b"")
+ resp_204.links = {}
+ resp_204.json = MagicMock(side_effect=json.decoder.JSONDecodeError("", "", 0))
+ async_session._client.request = AsyncMock(return_value=resp_204)
+
+ items = []
+ async for item in async_session._get_pages_iterator(_metadata(), "/organizations"):
+ items.append(item)
+ assert items == []
+ resp_204.json.assert_not_called()
+
+
+# --- Fix #5: smart-flow GET parses JSON only once ---
+
+
+class TestAsyncSuccessSingleParse:
+ @pytest.mark.asyncio
+ async def test_smart_flow_get_parses_json_once(self, async_session):
+ """With smart flow on, a successful GET must call response.json() exactly once."""
+ async_session._smart_flow = MagicMock()
+ async_session._smart_flow.acquire = AsyncMock()
+
+ body = {"organizationId": "42", "id": "N_1"}
+ resp = _mock_aio_response(status_code=200, json_data=body)
+ async_session._client.request = AsyncMock(return_value=resp)
+
+ await async_session.request(_metadata(), "GET", "/networks/N_1")
+
+ assert resp.json.call_count == 1
+ # learn_from_response receives the already-decoded body (same object)
+ async_session._smart_flow.learn_from_response.assert_called_once()
+ passed_body = async_session._smart_flow.learn_from_response.call_args.args[1]
+ assert passed_body == body
+
+ @pytest.mark.asyncio
+ async def test_handle_success_async_returns_response_and_body(self, async_session):
+ body = [{"id": 1}]
+ resp = _mock_aio_response(status_code=200, json_data=body)
+ result, parsed = await async_session._handle_success_async(resp, _metadata(), "GET")
+ assert result is resp
+ assert parsed == body
+ assert resp.json.call_count == 1
+
+ @pytest.mark.asyncio
+ async def test_handle_success_async_non_get_no_body(self, async_session):
+ resp = _mock_aio_response(status_code=201, json_data={"id": "x"})
+ result, parsed = await async_session._handle_success_async(resp, _metadata(), "POST")
+ assert result is resp
+ assert parsed is None
+ resp.json.assert_not_called()
+
+
+# --- Fix #9: early consumer break cancels the prefetch task ---
+
+
+class TestAsyncIteratorPrefetchCancel:
+ @pytest.mark.asyncio
+ async def test_early_break_cancels_prefetch(self, async_session):
+ """Breaking out of the iterator early cancels the in-flight prefetch task."""
+ import asyncio
+
+ resp1 = _mock_aio_response(status_code=200, json_data=[{"id": 1}])
+ resp1.links = {"next": {"url": "https://api.meraki.com/api/v1/orgs?startingAfter=1"}}
+
+ # Second request hangs forever so the prefetch task is genuinely pending at break.
+ never = asyncio.Event()
+
+ call_count = [0]
+
+ async def fake_request(*args, **kwargs):
+ call_count[0] += 1
+ if call_count[0] == 1:
+ return resp1
+ await never.wait() # never resolves
+ return _mock_aio_response(status_code=200, json_data=[{"id": 2}])
+
+ async_session._client.request = AsyncMock(side_effect=fake_request)
+
+ captured = {}
+ orig_create_task = asyncio.create_task
+
+ def capture_create_task(coro):
+ task = orig_create_task(coro)
+ captured.setdefault("tasks", []).append(task)
+ return task
+
+ agen = async_session._get_pages_iterator(_metadata(), "/orgs", total_pages=-1)
+ with patch("meraki.session.async_.asyncio.create_task", side_effect=capture_create_task):
+ first = await agen.__anext__()
+ assert first == {"id": 1}
+ # Break early: close the generator, triggering finally -> cancel prefetch.
+ await agen.aclose()
+
+ # The second (prefetch) task should have been cancelled.
+ prefetch_tasks = captured["tasks"]
+ assert len(prefetch_tasks) >= 2
+ assert prefetch_tasks[-1].cancelled()
+
+
+# --- Fix #12: internal resolver/hydrator GETs drain the global bucket ---
+
+
+def _make_async_smart_flow_session():
+ from tests.unit.conftest import DEFAULT_SESSION_KWARGS, FAKE_API_KEY
+
+ kwargs = {"maximum_concurrent_requests": 8, **DEFAULT_SESSION_KWARGS, "smart_flow_enabled": True}
+ with (
+ patch("meraki.session.base.check_python_version"),
+ patch("httpx.AsyncClient") as mock_client,
+ ):
+ mock_instance = MagicMock()
+ mock_instance.headers = {}
+ mock_instance.request = AsyncMock()
+ mock_client.return_value = mock_instance
+ from meraki.session.async_ import AsyncRestSession
+
+ return AsyncRestSession(logger=None, api_key=FAKE_API_KEY, **kwargs)
+
+
+class TestAsyncGlobalBucketAccounting:
+ @pytest.mark.asyncio
+ async def test_resolver_acquires_global_bucket(self):
+ s = _make_async_smart_flow_session()
+ s._smart_flow._global_bucket = MagicMock()
+ s._smart_flow._global_bucket.acquire = AsyncMock()
+ resp = _mock_aio_response(status_code=200, json_data={"organizationId": "999"})
+ s._client.request = AsyncMock(return_value=resp)
+
+ org = await s._resolve_org_for_limiter("network", "N_1")
+ assert org == "999"
+ s._smart_flow._global_bucket.acquire.assert_awaited_once()
+
+ @pytest.mark.asyncio
+ async def test_hydrator_acquires_global_bucket_per_page(self):
+ s = _make_async_smart_flow_session()
+ s._smart_flow._global_bucket = MagicMock()
+ s._smart_flow._global_bucket.acquire = AsyncMock()
+
+ page1 = _mock_aio_response(status_code=200, json_data=[{"id": "N_1"}])
+ page1.links = {"next": {"url": "https://api.meraki.com/api/v1/organizations/9/networks?page=2"}}
+ page2 = _mock_aio_response(status_code=200, json_data=[{"id": "N_2"}])
+ page2.links = {}
+ empty = _mock_aio_response(status_code=200, json_data=[])
+ empty.links = {}
+ s._client.request = AsyncMock(side_effect=[page1, page2, empty])
+
+ await s._hydrate_org_for_limiter("9")
+ assert s._smart_flow._global_bucket.acquire.await_count == 3
+
+ @pytest.mark.asyncio
+ async def test_acquire_global_bucket_defensive(self, async_session):
+ async_session._smart_flow = None
+ await async_session._acquire_global_bucket() # must not raise
+
+
+# --- Fix #15: Meraki array-of-objects param encoding on the wire (async) ---
+
+
+class TestMerakiParamEncodingAsync:
+ @pytest.mark.asyncio
+ async def test_list_of_dict_params_use_meraki_encoding(self, async_session):
+ resp = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp)
+
+ params = {"variables[]": [{"name": "n1", "value": "v1"}]}
+ await async_session.request(_metadata(), "GET", "/things", params=params)
+
+ call = async_session._client.request.call_args
+ sent_url = call.args[1]
+ assert "variables%5B%5Dname=n1" in sent_url
+ assert "variables%5B%5Dvalue=v1" in sent_url
+ assert call.kwargs.get("params") is None
+
+ @pytest.mark.asyncio
+ async def test_scalar_list_params_unchanged(self, async_session):
+ resp = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp)
+
+ params = {"networkIds[]": ["a", "b"]}
+ await async_session.request(_metadata(), "GET", "/things", params=params)
+
+ call = async_session._client.request.call_args
+ assert call.kwargs.get("params") == params
+ assert "networkIds" not in call.args[1]
+
+ @pytest.mark.asyncio
+ async def test_scalar_params_unchanged(self, async_session):
+ resp = _mock_aio_response(status_code=200)
+ async_session._client.request = AsyncMock(return_value=resp)
+
+ params = {"perPage": 10}
+ await async_session.request(_metadata(), "GET", "/things", params=params)
+
+ call = async_session._client.request.call_args
+ assert call.kwargs.get("params") == params
diff --git a/tests/unit/test_api_smoke.py b/tests/unit/test_api_smoke.py
new file mode 100644
index 00000000..d840c1d8
--- /dev/null
+++ b/tests/unit/test_api_smoke.py
@@ -0,0 +1,103 @@
+"""Smoke tests: all generated API modules import and instantiate."""
+
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+
+SYNC_API_CLASSES = [
+ ("meraki.api.administered", "Administered"),
+ ("meraki.api.appliance", "Appliance"),
+ ("meraki.api.camera", "Camera"),
+ ("meraki.api.campusGateway", "CampusGateway"),
+ ("meraki.api.cellularGateway", "CellularGateway"),
+ ("meraki.api.devices", "Devices"),
+ ("meraki.api.insight", "Insight"),
+ ("meraki.api.licensing", "Licensing"),
+ ("meraki.api.networks", "Networks"),
+ ("meraki.api.organizations", "Organizations"),
+ ("meraki.api.sensor", "Sensor"),
+ ("meraki.api.sm", "Sm"),
+ ("meraki.api.spaces", "Spaces"),
+ ("meraki.api.switch", "Switch"),
+ ("meraki.api.wireless", "Wireless"),
+ ("meraki.api.wirelessController", "WirelessController"),
+]
+
+ASYNC_API_CLASSES = [
+ ("meraki.aio.api.administered", "AsyncAdministered"),
+ ("meraki.aio.api.appliance", "AsyncAppliance"),
+ ("meraki.aio.api.camera", "AsyncCamera"),
+ ("meraki.aio.api.campusGateway", "AsyncCampusGateway"),
+ ("meraki.aio.api.cellularGateway", "AsyncCellularGateway"),
+ ("meraki.aio.api.devices", "AsyncDevices"),
+ ("meraki.aio.api.insight", "AsyncInsight"),
+ ("meraki.aio.api.licensing", "AsyncLicensing"),
+ ("meraki.aio.api.networks", "AsyncNetworks"),
+ ("meraki.aio.api.organizations", "AsyncOrganizations"),
+ ("meraki.aio.api.sensor", "AsyncSensor"),
+ ("meraki.aio.api.sm", "AsyncSm"),
+ ("meraki.aio.api.spaces", "AsyncSpaces"),
+ ("meraki.aio.api.switch", "AsyncSwitch"),
+ ("meraki.aio.api.wireless", "AsyncWireless"),
+ ("meraki.aio.api.wirelessController", "AsyncWirelessController"),
+]
+
+
+class TestSyncAPIModuleSmoke:
+ @pytest.mark.parametrize("module_path,class_name", SYNC_API_CLASSES)
+ def test_import_and_instantiate(self, module_path, class_name):
+ """Each sync API class imports and instantiates with a mock session."""
+ import importlib
+
+ module = importlib.import_module(module_path)
+ cls = getattr(module, class_name)
+ instance = cls(session=MagicMock())
+ assert instance is not None
+
+
+class TestAsyncAPIModuleSmoke:
+ @pytest.mark.parametrize("module_path,class_name", ASYNC_API_CLASSES)
+ def test_import_and_instantiate(self, module_path, class_name):
+ """Each async API class imports and instantiates with a mock session."""
+ import importlib
+
+ module = importlib.import_module(module_path)
+ cls = getattr(module, class_name)
+ instance = cls(session=MagicMock())
+ assert instance is not None
+
+
+class TestDashboardAPISectionsSmoke:
+ def test_all_sync_sections_accessible(self):
+ """DashboardAPI exposes all API sections after init."""
+ with patch("meraki.session.base.check_python_version"):
+ import meraki
+
+ api = meraki.DashboardAPI(
+ api_key="fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ )
+
+ expected_sections = [
+ "administered",
+ "appliance",
+ "camera",
+ "campusGateway",
+ "cellularGateway",
+ "devices",
+ "insight",
+ "licensing",
+ "networks",
+ "organizations",
+ "sensor",
+ "sm",
+ "spaces",
+ "switch",
+ "wireless",
+ "wirelessController",
+ "batch",
+ ]
+ for section in expected_sections:
+ attr = getattr(api, section, None)
+ assert attr is not None, f"DashboardAPI missing section: {section}"
diff --git a/tests/unit/test_async_lifecycle.py b/tests/unit/test_async_lifecycle.py
new file mode 100644
index 00000000..a9b7a78a
--- /dev/null
+++ b/tests/unit/test_async_lifecycle.py
@@ -0,0 +1,139 @@
+"""Test AsyncDashboardAPI context manager and session lifecycle."""
+
+import asyncio
+from unittest.mock import patch, AsyncMock, MagicMock
+
+import pytest
+
+from meraki.aio import AsyncDashboardAPI
+from meraki.exceptions import APIKeyError
+
+
+class TestAsyncDashboardAPILifecycle:
+ def test_missing_api_key_raises(self, monkeypatch):
+ monkeypatch.delenv("MERAKI_DASHBOARD_API_KEY", raising=False)
+ with pytest.raises(APIKeyError):
+ AsyncDashboardAPI(api_key=None, suppress_logging=True)
+
+ def test_instantiation_with_valid_key(self):
+ with patch("meraki.session.base.check_python_version"):
+ api = AsyncDashboardAPI(
+ api_key="fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ )
+ assert api._session is not None
+
+ @pytest.mark.asyncio
+ async def test_context_manager_enters_and_exits(self):
+ with patch("meraki.session.base.check_python_version"):
+ api = AsyncDashboardAPI(
+ api_key="fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ )
+
+ api._session._client = MagicMock()
+ api._session._client.aclose = AsyncMock()
+
+ async with api as dashboard:
+ assert dashboard is api
+
+ api._session._client.aclose.assert_called_once()
+
+ @pytest.mark.asyncio
+ async def test_aexit_shuts_down_smart_flow_before_closing_client(self):
+ # Regression for #7: __aexit__ must drain/cancel in-flight background
+ # smart-flow tasks (via shutdown()) and persist the cache BEFORE the
+ # httpx client is closed, otherwise those tasks fail with
+ # "client has been closed" and resolution is lost.
+ with patch("meraki.session.base.check_python_version"):
+ api = AsyncDashboardAPI(
+ api_key="fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ )
+
+ order = []
+ bg_task_done = asyncio.Event()
+
+ async def slow_background():
+ # Simulate an in-flight resolve/hydrate task touching the client.
+ await asyncio.sleep(0.05)
+ bg_task_done.set()
+
+ bg = asyncio.create_task(slow_background())
+
+ smart_flow = MagicMock()
+ save_calls = {"n": 0}
+
+ async def fake_shutdown():
+ order.append("shutdown")
+ # Drain the in-flight background task before the client closes.
+ await bg
+ save_calls["n"] += 1 # shutdown performs the final save itself
+
+ smart_flow.shutdown = AsyncMock(side_effect=fake_shutdown)
+ api._session._smart_flow = smart_flow
+
+ async def fake_close():
+ order.append("close")
+
+ api._session.close = AsyncMock(side_effect=fake_close)
+
+ async with api:
+ pass
+
+ # shutdown ran exactly once, before the client/session close
+ smart_flow.shutdown.assert_awaited_once()
+ assert order == ["shutdown", "close"]
+ # background task was awaited to completion (no lingering task)
+ assert bg.done()
+ assert bg_task_done.is_set()
+ # cache persisted exactly once (shutdown does the save, not save_cache)
+ assert save_calls["n"] == 1
+
+ @pytest.mark.asyncio
+ async def test_aexit_skips_shutdown_when_smart_flow_disabled(self):
+ # When smart flow is disabled the limiter is None; __aexit__ must not
+ # attempt to call shutdown() and must still close the client.
+ with patch("meraki.session.base.check_python_version"):
+ api = AsyncDashboardAPI(
+ api_key="fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=False,
+ )
+
+ assert api._session._smart_flow is None
+ api._session.close = AsyncMock()
+
+ async with api:
+ pass
+
+ api._session.close.assert_awaited_once()
+
+ def test_all_api_sections_assigned(self):
+ with patch("meraki.session.base.check_python_version"):
+ api = AsyncDashboardAPI(
+ api_key="fake_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ )
+
+ sections = [
+ "administered",
+ "appliance",
+ "camera",
+ "campusGateway",
+ "cellularGateway",
+ "devices",
+ "insight",
+ "licensing",
+ "networks",
+ "organizations",
+ "sensor",
+ "sm",
+ "spaces",
+ "switch",
+ "wireless",
+ "wirelessController",
+ ]
+ for section in sections:
+ assert hasattr(api, section), f"Missing API section: {section}"
+ assert getattr(api, section) is not None
diff --git a/tests/unit/test_common.py b/tests/unit/test_common.py
index 90293b4d..fd1f2a44 100644
--- a/tests/unit/test_common.py
+++ b/tests/unit/test_common.py
@@ -28,6 +28,21 @@ def test_python2_raises(self, mock_ver):
with pytest.raises(PythonVersionError):
check_python_version()
+ def test_check_python_version_valid_does_not_raise(self):
+ """check_python_version should not raise on current interpreter (>=3.10)."""
+ check_python_version()
+
+ def test_check_python_version_rejects_39(self):
+ """check_python_version raises PythonVersionError for 3.9."""
+ with patch("platform.python_version_tuple", return_value=("3", "9", "0")):
+ with pytest.raises(PythonVersionError):
+ check_python_version()
+
+ def test_check_python_version_accepts_310(self):
+ """check_python_version accepts exactly 3.10.0 (minimum)."""
+ with patch("platform.python_version_tuple", return_value=("3", "10", "0")):
+ check_python_version()
+
class TestValidateUserAgent:
def test_valid_caller(self):
@@ -74,6 +89,20 @@ def test_trailing_slash_stripped(self):
reject_v0_base_url(session)
assert session._base_url == "https://api.meraki.com/api/v1"
+ def test_reject_v0_strips_trailing_slash(self):
+ """reject_v0_base_url strips trailing slash from valid URLs."""
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1/"
+ reject_v0_base_url(obj)
+ assert obj._base_url == "https://api.meraki.com/api/v1"
+
+ def test_reject_v0_leaves_valid_url_unchanged(self):
+ """reject_v0_base_url leaves clean v1 URL untouched."""
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ reject_v0_base_url(obj)
+ assert obj._base_url == "https://api.meraki.com/api/v1"
+
class TestValidateBaseUrl:
def test_absolute_meraki_url_passthrough(self):
@@ -112,6 +141,111 @@ def test_gov_domain(self):
result = validate_base_url(session, "https://n1.gov-meraki.com/api/v1/x")
assert result == "https://n1.gov-meraki.com/api/v1/x"
+ def test_meraki_com_absolute(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ result = validate_base_url(obj, "https://n1.meraki.com/api/v1/networks")
+ assert result == "https://n1.meraki.com/api/v1/networks"
+
+ def test_relative_url_prepends_base(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ result = validate_base_url(obj, "/organizations")
+ assert result == "https://api.meraki.com/api/v1/organizations"
+
+ def test_canada_domain_treated_as_absolute(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.ca/api/v1"
+ result = validate_base_url(obj, "https://api.meraki.ca/api/v1/networks")
+ assert result == "https://api.meraki.ca/api/v1/networks"
+
+ def test_china_domain_treated_as_absolute(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.cn/api/v1"
+ result = validate_base_url(obj, "https://api.meraki.cn/api/v1/networks")
+ assert result == "https://api.meraki.cn/api/v1/networks"
+
+ def test_india_domain_treated_as_absolute(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.in/api/v1"
+ result = validate_base_url(obj, "https://api.meraki.in/api/v1/networks")
+ assert result == "https://api.meraki.in/api/v1/networks"
+
+ def test_gov_meraki_domain_treated_as_absolute(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.gov-meraki.com/api/v1"
+ result = validate_base_url(obj, "https://api.gov-meraki.com/api/v1/networks")
+ assert result == "https://api.gov-meraki.com/api/v1/networks"
+
+ def test_unknown_domain_treated_as_relative(self):
+ from meraki.common import validate_base_url
+
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ result = validate_base_url(obj, "https://evil.com/steal")
+ assert result == "https://api.meraki.com/api/v1https://evil.com/steal"
+
+ # --- Fix #14: host-boundary trusted-domain check (SSRF / key-exfil) ---
+
+ def test_legit_api_host_trusted(self):
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ result = validate_base_url(obj, "https://api.meraki.com/api/v1/orgs")
+ assert result == "https://api.meraki.com/api/v1/orgs"
+
+ def test_legit_shard_subdomain_trusted(self):
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ result = validate_base_url(obj, "https://n123.meraki.com/api/v1/orgs")
+ assert result == "https://n123.meraki.com/api/v1/orgs"
+
+ def test_legit_cn_host_trusted(self):
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.cn/api/v1"
+ result = validate_base_url(obj, "https://api.meraki.cn/api/v1/orgs")
+ assert result == "https://api.meraki.cn/api/v1/orgs"
+
+ def test_lookalike_suffix_rejected(self):
+ # "meraki.com" appears as a substring but not on a host boundary.
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ evil = "https://api.meraki.com.attacker.net/steal"
+ result = validate_base_url(obj, evil)
+ assert result == "https://api.meraki.com/api/v1" + evil
+
+ def test_lookalike_evil_example_rejected(self):
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ evil = "https://meraki.com.evil.example/steal"
+ result = validate_base_url(obj, evil)
+ assert result == "https://api.meraki.com/api/v1" + evil
+
+ def test_lookalike_prefix_rejected(self):
+ # "evil-meraki.com" embeds the domain but is a different host.
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ evil = "https://evil-meraki.com/steal"
+ result = validate_base_url(obj, evil)
+ assert result == "https://api.meraki.com/api/v1" + evil
+
+ def test_trusted_host_with_port(self):
+ obj = MagicMock()
+ obj._base_url = "https://api.meraki.com/api/v1"
+ result = validate_base_url(obj, "https://api.meraki.com:443/api/v1/orgs")
+ assert result == "https://api.meraki.com:443/api/v1/orgs"
+
class TestIteratorForGetPages:
def test_getter(self):
diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py
new file mode 100644
index 00000000..aac803f6
--- /dev/null
+++ b/tests/unit/test_config.py
@@ -0,0 +1,40 @@
+"""Verify config.py constants are sane and consumed correctly."""
+
+from meraki import config
+
+
+class TestConfigDefaults:
+ def test_default_base_url_is_v1(self):
+ assert "v1" in config.DEFAULT_BASE_URL
+ assert config.DEFAULT_BASE_URL.startswith("https://")
+
+ def test_alternate_urls_are_https(self):
+ for url in [
+ config.CANADA_BASE_URL,
+ config.CHINA_BASE_URL,
+ config.INDIA_BASE_URL,
+ config.UNITED_STATES_FED_BASE_URL,
+ ]:
+ assert url.startswith("https://"), f"{url} is not HTTPS"
+ assert "/api/v1" in url
+
+ def test_timeout_is_positive(self):
+ assert config.SINGLE_REQUEST_TIMEOUT > 0
+
+ def test_maximum_retries_is_positive(self):
+ assert config.MAXIMUM_RETRIES >= 1
+
+ def test_retry_wait_times_are_positive(self):
+ assert config.NGINX_429_RETRY_WAIT_TIME > 0
+ assert config.ACTION_BATCH_RETRY_WAIT_TIME > 0
+ assert config.NETWORK_DELETE_RETRY_WAIT_TIME > 0
+ assert config.RETRY_4XX_ERROR_WAIT_TIME > 0
+
+ def test_aio_max_concurrent_is_positive(self):
+ assert config.AIO_MAXIMUM_CONCURRENT_REQUESTS >= 1
+
+ def test_wait_on_rate_limit_defaults_true(self):
+ assert config.WAIT_ON_RATE_LIMIT is True
+
+ def test_simulate_defaults_false(self):
+ assert config.SIMULATE_API_CALLS is False
diff --git a/tests/unit/test_dashboard_api_init.py b/tests/unit/test_dashboard_api_init.py
index b2fb2575..c146d1e9 100644
--- a/tests/unit/test_dashboard_api_init.py
+++ b/tests/unit/test_dashboard_api_init.py
@@ -1,6 +1,6 @@
import logging
import os
-from unittest.mock import patch
+from unittest.mock import MagicMock, patch
import pytest
@@ -9,24 +9,20 @@
class TestDashboardAPIInit:
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_api_key_from_param(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
suppress_logging=True,
caller="TestApp TestVendor",
)
- assert (
- d._session._api_key == "test_key_1234567890123456789012345678901234567890"
- )
+ assert d._session._api_key == "test_key_1234567890123456789012345678901234567890"
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_api_key_from_env(self, mock_check):
with patch.dict(
os.environ,
- {
- "MERAKI_DASHBOARD_API_KEY": "env_key_12345678901234567890123456789012345678"
- },
+ {"MERAKI_DASHBOARD_API_KEY": "env_key_12345678901234567890123456789012345678"},
):
d = meraki.DashboardAPI(
suppress_logging=True,
@@ -40,7 +36,7 @@ def test_missing_api_key_raises(self):
with pytest.raises(APIKeyError):
meraki.DashboardAPI(suppress_logging=True, caller="TestApp TestVendor")
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_suppress_logging_sets_none(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -49,7 +45,7 @@ def test_suppress_logging_sets_none(self, mock_check):
)
assert d._logger is None
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_simulate_mode_propagates(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -59,7 +55,7 @@ def test_simulate_mode_propagates(self, mock_check):
)
assert d._session._simulate is True
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_custom_base_url(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -69,7 +65,7 @@ def test_custom_base_url(self, mock_check):
)
assert d._session._base_url == "https://api.meraki.cn/api/v1"
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_maximum_retries_propagates(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -79,7 +75,7 @@ def test_maximum_retries_propagates(self, mock_check):
)
assert d._session._maximum_retries == 10
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_use_iterator_propagates(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -89,16 +85,43 @@ def test_use_iterator_propagates(self, mock_check):
)
assert d._session.use_iterator_for_get_pages is True
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
+ def test_use_iterator_default_false_propagates(self, mock_check):
+ # Regression for removed dead self-assignment
+ # `use_iterator_for_get_pages = use_iterator_for_get_pages`: param
+ # must still reach the session unchanged.
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ use_iterator_for_get_pages=False,
+ caller="TestApp TestVendor",
+ )
+ assert d._session.use_iterator_for_get_pages is False
+
+ @patch("meraki.session.base.check_python_version")
+ def test_inherit_logging_config_param_takes_effect(self, mock_check):
+ # Regression for removed dead self-assignment
+ # `inherit_logging_config = inherit_logging_config`: passing True must
+ # leave the logger at its inherited (non-DEBUG-forced) level.
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=False,
+ inherit_logging_config=True,
+ caller="TestApp TestVendor",
+ )
+ assert d._logger is not None
+ d._logger.handlers.clear()
+
+ @patch("meraki.session.base.check_python_version")
def test_caller_from_env(self, mock_check):
with patch.dict(os.environ, {"MERAKI_PYTHON_SDK_CALLER": "EnvApp EnvVendor"}):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
suppress_logging=True,
)
- assert "EnvApp EnvVendor" in d._session._req_session.headers["User-Agent"]
+ assert "EnvApp EnvVendor" in d._session._client.headers["User-Agent"]
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_all_api_sections_initialized(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -111,9 +134,46 @@ def test_all_api_sections_initialized(self, mock_check):
assert d.appliance is not None
assert d.wireless is not None
+ @patch("meraki.session.base.check_python_version")
+ def test_be_geo_id_from_env(self, mock_check):
+ with patch.dict(os.environ, {"BE_GEO_ID": "GeoApp V1"}):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ )
+ assert "GeoApp V1" in d._session._client.headers["User-Agent"]
+
+ @patch("meraki.session.base.check_python_version")
+ def test_batch_initialized(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ caller="TestApp TestVendor",
+ )
+ assert d.batch is not None
+
+ @patch("meraki.session.base.check_python_version")
+ def test_all_additional_sections(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ caller="TestApp TestVendor",
+ )
+ assert d.administered is not None
+ assert d.camera is not None
+ assert d.cellularGateway is not None
+ assert d.insight is not None
+ assert d.licensing is not None
+ assert d.sensor is not None
+ assert d.sm is not None
+ assert d.switch is not None
+ assert d.spaces is not None
+ assert d.wirelessController is not None
+ assert d.campusGateway is not None
+
class TestDashboardAPILogging:
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_inherit_logging_config(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -124,7 +184,7 @@ def test_inherit_logging_config(self, mock_check):
assert d._logger is not None
assert d._logger.name == "meraki"
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_output_log_with_print_console(self, mock_check, tmp_path):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -140,10 +200,9 @@ def test_output_log_with_print_console(self, mock_check, tmp_path):
assert d._logger.level == logging.DEBUG
assert hasattr(d, "_log_file")
assert "test_log__" in d._log_file
- # Clean up handlers to avoid pollution
d._logger.handlers.clear()
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_output_log_path_without_trailing_slash(self, mock_check, tmp_path):
log_path = str(tmp_path).rstrip("/").rstrip("\\")
d = meraki.DashboardAPI(
@@ -160,7 +219,7 @@ def test_output_log_path_without_trailing_slash(self, mock_check, tmp_path):
assert "pfx_log__" in d._log_file
d._logger.handlers.clear()
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_output_log_path_with_trailing_slash(self, mock_check, tmp_path):
log_path = str(tmp_path) + "/"
d = meraki.DashboardAPI(
@@ -176,7 +235,7 @@ def test_output_log_path_with_trailing_slash(self, mock_check, tmp_path):
assert "//" not in d._log_file.replace("\\", "/").replace("//", "/", 1)
d._logger.handlers.clear()
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_no_output_log_with_print_console(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -190,7 +249,7 @@ def test_no_output_log_with_print_console(self, mock_check):
assert d._logger.level == logging.DEBUG
d._logger.handlers.clear()
- @patch("meraki.rest_session.check_python_version")
+ @patch("meraki.session.base.check_python_version")
def test_no_output_log_no_print_console(self, mock_check):
d = meraki.DashboardAPI(
"test_key_1234567890123456789012345678901234567890",
@@ -202,3 +261,238 @@ def test_no_output_log_no_print_console(self, mock_check):
)
assert d._logger is not None
d._logger.handlers.clear()
+
+
+class TestDashboardAPILoggingHandlers:
+ @patch("meraki.session.base.check_python_version")
+ def test_handlers_added_when_no_existing_handlers(self, mock_check, tmp_path):
+ with patch("meraki.__init__.logging.getLogger") as mock_get_logger:
+ mock_logger = MagicMock()
+ mock_logger.hasHandlers.return_value = False
+ mock_get_logger.return_value = mock_logger
+ meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=False,
+ inherit_logging_config=False,
+ output_log=True,
+ log_path=str(tmp_path),
+ log_file_prefix="t",
+ print_console=True,
+ caller="TestApp TestVendor",
+ )
+ assert mock_logger.addHandler.call_count == 2
+
+ @patch("meraki.session.base.check_python_version")
+ def test_no_handlers_added_when_already_has_handlers(self, mock_check, tmp_path):
+ with patch("meraki.__init__.logging.getLogger") as mock_get_logger:
+ mock_logger = MagicMock()
+ mock_logger.hasHandlers.return_value = True
+ mock_get_logger.return_value = mock_logger
+ meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=False,
+ inherit_logging_config=False,
+ output_log=True,
+ log_path=str(tmp_path),
+ log_file_prefix="t",
+ print_console=True,
+ caller="TestApp TestVendor",
+ )
+ assert mock_logger.addHandler.call_count == 0
+
+ @patch("meraki.session.base.check_python_version")
+ def test_console_only_handler_when_no_output_log(self, mock_check):
+ with patch("meraki.__init__.logging.getLogger") as mock_get_logger:
+ mock_logger = MagicMock()
+ mock_logger.hasHandlers.return_value = False
+ mock_get_logger.return_value = mock_logger
+ meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=False,
+ inherit_logging_config=False,
+ output_log=False,
+ print_console=True,
+ caller="TestApp TestVendor",
+ )
+ assert mock_logger.addHandler.call_count == 1
+
+
+class TestDashboardAPISmartLimiting:
+ @patch("meraki.session.base.check_python_version")
+ def test_smart_flow_enabled_by_default(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ caller="TestApp TestVendor",
+ )
+ assert d._session._smart_flow is not None
+
+ @patch("meraki.session.base.check_python_version")
+ def test_smart_flow_disabled_explicitly(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=False,
+ caller="TestApp TestVendor",
+ )
+ assert d._session._smart_flow is None
+
+ @patch("meraki.session.base.check_python_version")
+ def test_smart_flow_creates_limiter(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ caller="TestApp TestVendor",
+ )
+ assert d._session._smart_flow is not None
+
+ @patch("meraki.session.base.check_python_version")
+ def test_smart_flow_with_cache_path(self, mock_check, tmp_path):
+ cache_file = str(tmp_path / "test_cache.json")
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ smart_flow_cache_path=cache_file,
+ caller="TestApp TestVendor",
+ )
+ assert d._session._smart_flow is not None
+
+
+class TestDashboardAPIEagerLoad:
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_populates_cache(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ caller="TestApp TestVendor",
+ )
+ mock_orgs = [{"id": "org_1"}, {"id": "org_2"}]
+ mock_networks = [{"id": "N_1"}, {"id": "N_2"}]
+ mock_devices = [{"serial": "QABC-1234-5678"}, {"serial": "QDEF-5678-9012"}]
+
+ with patch.object(d.organizations, "getOrganizations", return_value=mock_orgs):
+ with patch.object(d.organizations, "getOrganizationNetworks", return_value=mock_networks):
+ with patch.object(d.organizations, "getOrganizationInventoryDevices", return_value=mock_devices):
+ d._eager_load_rate_limit_cache()
+
+ limiter = d._session._smart_flow
+ assert limiter.resolve_org("/organizations/org_1/x") == "org_1"
+ assert limiter.resolve_org("/networks/N_1/x") is not None
+ assert limiter.resolve_org("/devices/QABC-1234-5678/x") is not None
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_handles_org_failure(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ caller="TestApp TestVendor",
+ )
+ with patch.object(d.organizations, "getOrganizations", side_effect=Exception("API error")):
+ d._eager_load_rate_limit_cache()
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_handles_network_failure(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ caller="TestApp TestVendor",
+ )
+ mock_orgs = [{"id": "org_1"}]
+ with patch.object(d.organizations, "getOrganizations", return_value=mock_orgs):
+ with patch.object(d.organizations, "getOrganizationNetworks", side_effect=Exception("net fail")):
+ with patch.object(d.organizations, "getOrganizationInventoryDevices", return_value=[]):
+ d._eager_load_rate_limit_cache()
+ assert d._session._smart_flow.resolve_org("/organizations/org_1/x") == "org_1"
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_handles_device_failure(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ caller="TestApp TestVendor",
+ )
+ mock_orgs = [{"id": "org_1"}]
+ mock_networks = [{"id": "N_1"}]
+ with patch.object(d.organizations, "getOrganizations", return_value=mock_orgs):
+ with patch.object(d.organizations, "getOrganizationNetworks", return_value=mock_networks):
+ with patch.object(d.organizations, "getOrganizationInventoryDevices", side_effect=Exception("dev fail")):
+ d._eager_load_rate_limit_cache()
+ assert d._session._smart_flow.resolve_org("/networks/N_1/x") == "org_1"
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_skips_devices_without_serial(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="lazy",
+ caller="TestApp TestVendor",
+ )
+ mock_orgs = [{"id": "org_1"}]
+ mock_devices = [{"serial": "QABC-1234-5678"}, {"name": "no-serial-device"}]
+ with patch.object(d.organizations, "getOrganizations", return_value=mock_orgs):
+ with patch.object(d.organizations, "getOrganizationNetworks", return_value=[]):
+ with patch.object(d.organizations, "getOrganizationInventoryDevices", return_value=mock_devices):
+ d._eager_load_rate_limit_cache()
+ limiter = d._session._smart_flow
+ assert limiter.resolve_org("/devices/QABC-1234-5678/x") == "org_1"
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_noop_without_limiter(self, mock_check):
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=False,
+ caller="TestApp TestVendor",
+ )
+ d._eager_load_rate_limit_cache()
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_runs_during_init_when_cache_not_fresh(self, mock_check, tmp_path):
+ cache_file = str(tmp_path / "nonexistent_cache.json")
+ with patch("meraki.api.organizations.Organizations.getOrganizations", return_value=[]):
+ meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="eager",
+ smart_flow_cache_path=cache_file,
+ caller="TestApp TestVendor",
+ )
+
+ @patch("meraki.session.base.check_python_version")
+ def test_eager_load_skipped_when_cache_fresh(self, mock_check, tmp_path):
+ import json
+ from datetime import datetime, timezone
+
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "saved_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
+ "networks": [{"id": "N_cached", "organization": {"id": "org_cached"}}],
+ "devices": [],
+ }
+ )
+ )
+ d = meraki.DashboardAPI(
+ "test_key_1234567890123456789012345678901234567890",
+ suppress_logging=True,
+ smart_flow_enabled=True,
+ smart_flow_cache_mode="eager",
+ smart_flow_cache_path=str(cache_file),
+ caller="TestApp TestVendor",
+ )
+ assert d._session._smart_flow.resolve_org("/networks/N_cached/x") == "org_cached"
diff --git a/tests/unit/test_encoding.py b/tests/unit/test_encoding.py
new file mode 100644
index 00000000..de8b2f9a
--- /dev/null
+++ b/tests/unit/test_encoding.py
@@ -0,0 +1,123 @@
+"""Tests for meraki.encoding module (HTTP-04, QUAL-03)."""
+
+import inspect
+
+from hypothesis import given, strategies as st
+from urllib.parse import parse_qs
+
+from meraki.encoding import encode_meraki_params
+
+
+class TestEncodeMerakiParams:
+ """Unit tests replicating behavioral spec from test_rest_session.py."""
+
+ def test_string_passthrough(self):
+ assert encode_meraki_params("already_encoded") == "already_encoded"
+
+ def test_bytes_passthrough(self):
+ assert encode_meraki_params(b"raw") == b"raw"
+
+ def test_file_like_passthrough(self):
+ class FakeFile:
+ def read(self):
+ pass
+
+ f = FakeFile()
+ assert encode_meraki_params(f) is f
+
+ def test_non_iterable_passthrough(self):
+ assert encode_meraki_params(42) == 42
+
+ def test_simple_dict(self):
+ result = encode_meraki_params({"key": "value"})
+ assert "key=value" in result
+
+ def test_list_values(self):
+ result = encode_meraki_params({"tag": ["a", "b"]})
+ assert "tag=a" in result
+ assert "tag=b" in result
+
+ def test_array_of_objects(self):
+ result = encode_meraki_params({"param[]": [{"key1": "val1"}, {"key2": "val2"}]})
+ assert "param%5B%5Dkey1=val1" in result
+ assert "param%5B%5Dkey2=val2" in result
+
+ def test_list_of_tuples(self):
+ result = encode_meraki_params([("k", "v")])
+ assert "k=v" in result
+
+
+class TestNoRequestsDependency:
+ """Verify HTTP-04: no requests import in encoding module."""
+
+ def test_no_requests_import(self):
+ import meraki.encoding
+
+ source = inspect.getsource(meraki.encoding)
+ assert "import requests" not in source
+ assert "from requests" not in source
+
+
+# --- Property-based tests (QUAL-03, per D-04: roundtrip fidelity) ---
+
+# Strategy: printable text keys (no surrogates, no empty)
+_key_strategy = st.text(
+ alphabet=st.characters(whitelist_categories=("L", "N", "P"), blacklist_characters="="),
+ min_size=1,
+ max_size=20,
+)
+
+_value_strategy = st.text(
+ alphabet=st.characters(whitelist_categories=("L", "N", "P"), blacklist_characters="="),
+ min_size=1,
+ max_size=50,
+)
+
+
+@given(
+ st.dictionaries(
+ keys=_key_strategy,
+ values=st.lists(_value_strategy, min_size=1, max_size=5),
+ )
+)
+def test_roundtrip_simple(data):
+ """(D-04) Encoded output parsed back with parse_qs reconstructs keys and values."""
+ encoded = encode_meraki_params(data)
+ if not data:
+ assert encoded == ""
+ return
+ decoded = parse_qs(encoded)
+ assert set(decoded.keys()) == set(data.keys())
+ for k in data:
+ assert decoded[k] == data[k]
+
+
+@given(
+ st.dictionaries(
+ keys=_key_strategy,
+ values=st.lists(
+ st.dictionaries(
+ keys=_key_strategy,
+ values=_value_strategy,
+ min_size=1,
+ max_size=3,
+ ),
+ min_size=1,
+ max_size=3,
+ ),
+ )
+)
+def test_roundtrip_array_of_objects(data):
+ """(D-04, D-05) Array-of-objects encoding roundtrips: param+inner_key maps to value."""
+ encoded = encode_meraki_params(data)
+ if not data:
+ assert encoded == ""
+ return
+ decoded = parse_qs(encoded)
+ # Verify all expected keys exist
+ for param, obj_list in data.items():
+ for obj in obj_list:
+ for inner_key, inner_val in obj.items():
+ composite_key = param + inner_key
+ assert composite_key in decoded
+ assert inner_val in decoded[composite_key]
diff --git a/tests/unit/test_encoding_property.py b/tests/unit/test_encoding_property.py
new file mode 100644
index 00000000..c5dd5302
--- /dev/null
+++ b/tests/unit/test_encoding_property.py
@@ -0,0 +1,71 @@
+"""Property-based tests for meraki.encoding using hypothesis."""
+
+from hypothesis import given, settings
+from hypothesis import strategies as st
+
+from meraki.encoding import encode_meraki_params
+
+
+simple_params = st.dictionaries(
+ keys=st.text(min_size=1, max_size=20, alphabet=st.characters(whitelist_categories=("L", "N"))),
+ values=st.one_of(st.text(max_size=50), st.integers(), st.floats(allow_nan=False, allow_infinity=False)),
+ min_size=1,
+ max_size=10,
+)
+
+
+class TestEncodeRoundtripProperties:
+ @given(data=simple_params)
+ @settings(max_examples=200)
+ def test_always_returns_string(self, data):
+ """encode_meraki_params always returns a string for dict input."""
+ result = encode_meraki_params(data)
+ assert isinstance(result, str)
+
+ @given(data=simple_params)
+ @settings(max_examples=200)
+ def test_all_keys_present_in_output(self, data):
+ """Every key from input dict appears (URL-encoded) in output."""
+ from urllib.parse import quote_plus
+
+ result = encode_meraki_params(data)
+ for key in data:
+ encoded_key = quote_plus(key)
+ assert encoded_key in result, f"Key '{key}' (encoded: '{encoded_key}') missing from output"
+
+ @given(text=st.text(max_size=100))
+ def test_string_passthrough(self, text):
+ """String input passes through unchanged."""
+ assert encode_meraki_params(text) is text
+
+ @given(data=st.binary(max_size=100))
+ def test_bytes_passthrough(self, data):
+ """Bytes input passes through unchanged."""
+ assert encode_meraki_params(data) is data
+
+ def test_none_values_excluded(self):
+ """None values are excluded from encoding."""
+ data = {"key1": "value1", "key2": None}
+ result = encode_meraki_params(data)
+ assert "key1" in result
+ assert "key2" not in result
+
+ def test_empty_dict_returns_empty_string(self):
+ """Empty dict produces empty string."""
+ result = encode_meraki_params({})
+ assert result == ""
+
+ def test_file_like_object_passthrough(self):
+ """Objects with .read() attribute pass through."""
+ import io
+
+ f = io.BytesIO(b"file content")
+ assert encode_meraki_params(f) is f
+
+ def test_array_of_objects_encoding(self):
+ """Array-of-objects uses Meraki bracket concatenation."""
+ data = {"rules[]": [{"policy": "allow", "destPort": "80"}]}
+ result = encode_meraki_params(data)
+ assert "rules" in result
+ assert "policy" in result
+ assert "allow" in result
diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py
index 05e1e184..64f9e0bf 100644
--- a/tests/unit/test_exceptions.py
+++ b/tests/unit/test_exceptions.py
@@ -51,12 +51,10 @@ def test_str(self):
class TestAPIError:
- def _make_response(
- self, status_code=400, reason="Bad Request", json_data=None, content=b""
- ):
+ def _make_response(self, status_code=400, reason_phrase="Bad Request", json_data=None, content=b""):
resp = MagicMock()
resp.status_code = status_code
- resp.reason = reason
+ resp.reason_phrase = reason_phrase
resp.json.return_value = json_data or {"errors": ["something"]}
resp.content = content
return resp
@@ -84,7 +82,7 @@ def test_none_response_fields(self):
metadata = {"tags": ["orgs"], "operation": "getOrgs"}
resp = MagicMock()
resp.status_code = None
- resp.reason = None
+ resp.reason_phrase = None
resp.json.return_value = None
err = APIError(metadata, resp)
assert err.status is None
@@ -95,7 +93,7 @@ def test_json_decode_error_falls_back_to_content(self):
metadata = {"tags": ["orgs"], "operation": "getOrgs"}
resp = MagicMock()
resp.status_code = 500
- resp.reason = "Server Error"
+ resp.reason_phrase = "Server Error"
resp.json.side_effect = ValueError("No JSON")
resp.content = b"Internal Server Error"
err = APIError(metadata, resp)
@@ -105,7 +103,7 @@ def test_404_appends_wait_message(self):
metadata = {"tags": ["orgs"], "operation": "getOrg"}
resp = MagicMock()
resp.status_code = 404
- resp.reason = "Not Found"
+ resp.reason_phrase = "Not Found"
resp.json.side_effect = ValueError("No JSON")
resp.content = b"Not found here"
err = APIError(metadata, resp)
@@ -115,7 +113,7 @@ def test_non_404_does_not_append_wait_message(self):
metadata = {"tags": ["orgs"], "operation": "getOrg"}
resp = MagicMock()
resp.status_code = 500
- resp.reason = "Server Error"
+ resp.reason_phrase = "Server Error"
resp.json.side_effect = ValueError("No JSON")
resp.content = b"error text"
err = APIError(metadata, resp)
@@ -123,16 +121,17 @@ def test_non_404_does_not_append_wait_message(self):
class TestAsyncAPIError:
- def _make_response(self, status=400, reason="Bad Request"):
+ def _make_response(self, status_code=400, reason_phrase="Bad Request"):
resp = MagicMock()
- resp.status = status
- resp.reason = reason
+ resp.status_code = status_code
+ resp.reason_phrase = reason_phrase
return resp
def test_basic_init(self):
metadata = {"tags": ["devices"], "operation": "getDevices"}
resp = self._make_response()
- err = AsyncAPIError(metadata, resp, {"errors": ["fail"]})
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp, {"errors": ["fail"]})
assert err.tag == "devices"
assert err.operation == "getDevices"
assert err.status == 400
@@ -142,7 +141,8 @@ def test_basic_init(self):
def test_repr(self):
metadata = {"tags": ["devices"], "operation": "getDevices"}
resp = self._make_response()
- err = AsyncAPIError(metadata, resp, "some error")
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp, "some error")
r = repr(err)
assert "devices" in r
assert "400" in r
@@ -150,27 +150,52 @@ def test_repr(self):
def test_string_message_stripped(self):
metadata = {"tags": ["orgs"], "operation": "getOrgs"}
resp = self._make_response()
- err = AsyncAPIError(metadata, resp, " spaces around ")
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp, " spaces around ")
assert err.message == "spaces around"
def test_404_appends_wait_message(self):
metadata = {"tags": ["orgs"], "operation": "getOrg"}
- resp = self._make_response(status=404, reason="Not Found")
- err = AsyncAPIError(metadata, resp, "resource missing")
+ resp = self._make_response(status_code=404, reason_phrase="Not Found")
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp, "resource missing")
assert "please wait" in err.message
def test_non_404_does_not_append_wait_message(self):
metadata = {"tags": ["orgs"], "operation": "getOrg"}
- resp = self._make_response(status=500, reason="Server Error")
- err = AsyncAPIError(metadata, resp, "server broke")
+ resp = self._make_response(status_code=500, reason_phrase="Server Error")
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp, "server broke")
assert "please wait" not in err.message
def test_none_response(self):
metadata = {"tags": ["orgs"], "operation": "getOrg"}
- err = AsyncAPIError(metadata, None, "no response")
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, None, "no response")
assert err.status is None
assert err.reason is None
+ def test_is_subclass_of_api_error(self):
+ metadata = {"tags": ["devices"], "operation": "getDevices"}
+ resp = self._make_response()
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp, "msg")
+ assert isinstance(err, APIError)
+
+ def test_emits_deprecation_warning(self):
+ metadata = {"tags": ["devices"], "operation": "getDevices"}
+ resp = self._make_response()
+ with pytest.warns(DeprecationWarning, match="AsyncAPIError is deprecated"):
+ AsyncAPIError(metadata, resp, {"errors": ["fail"]})
+
+ def test_2arg_signature_delegates_to_parent(self):
+ metadata = {"tags": ["networks"], "operation": "getNetworks"}
+ resp = self._make_response()
+ resp.json.return_value = {"errors": ["server failed"]}
+ with pytest.warns(DeprecationWarning):
+ err = AsyncAPIError(metadata, resp)
+ assert err.message == {"errors": ["server failed"]}
+
class TestPythonVersionError:
def test_message_preserved(self):
@@ -181,9 +206,7 @@ def test_message_preserved(self):
class TestSessionInputError:
def test_fields(self):
- err = SessionInputError(
- "CALLER", "bad!!!", "Format wrong", "https://docs.example.com"
- )
+ err = SessionInputError("CALLER", "bad!!!", "Format wrong", "https://docs.example.com")
assert err.argument == "CALLER"
assert err.value == "bad!!!"
assert err.message == "Format wrong"
diff --git a/tests/unit/test_mock_integration.py b/tests/unit/test_mock_integration.py
index 055738ac..3d968394 100644
--- a/tests/unit/test_mock_integration.py
+++ b/tests/unit/test_mock_integration.py
@@ -4,8 +4,9 @@
but against canned HTTP responses, so it can run in CI without API keys.
"""
+import httpx
import pytest
-import responses
+import respx
import meraki
@@ -18,7 +19,7 @@
@pytest.fixture
def mock_api():
- with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
+ with respx.mock(assert_all_mocked=False) as rsps:
yield rsps
@@ -37,14 +38,15 @@ def dashboard(mock_api):
class TestGetAdministeredIdentitiesMe:
def test_returns_identity(self, mock_api, dashboard):
- mock_api.add(
- responses.GET,
- f"{BASE}/administered/identities/me",
- json={
- "name": "Test User",
- "email": "test@example.com",
- "authentication": {"api": {"key": {"created": True}}},
- },
+ mock_api.get(f"{BASE}/administered/identities/me").mock(
+ return_value=httpx.Response(
+ 200,
+ json={
+ "name": "Test User",
+ "email": "test@example.com",
+ "authentication": {"api": {"key": {"created": True}}},
+ },
+ )
)
me = dashboard.administered.getAdministeredIdentitiesMe()
assert me is not None
@@ -57,20 +59,14 @@ def test_returns_identity(self, mock_api, dashboard):
class TestOrganizations:
def test_get_organizations(self, mock_api, dashboard):
- mock_api.add(
- responses.GET,
- f"{BASE}/organizations",
- json=[{"id": ORG_ID, "name": "Test Org"}],
- )
+ mock_api.get(f"{BASE}/organizations").mock(return_value=httpx.Response(200, json=[{"id": ORG_ID, "name": "Test Org"}]))
orgs = dashboard.organizations.getOrganizations()
assert orgs is not None
assert len(orgs) > 0
def test_get_organization(self, mock_api, dashboard):
- mock_api.add(
- responses.GET,
- f"{BASE}/organizations/{ORG_ID}",
- json={"id": ORG_ID, "name": "Test Org"},
+ mock_api.get(f"{BASE}/organizations/{ORG_ID}").mock(
+ return_value=httpx.Response(200, json={"id": ORG_ID, "name": "Test Org"})
)
org = dashboard.organizations.getOrganization(ORG_ID)
assert isinstance(org, dict)
@@ -82,16 +78,17 @@ def test_get_organization(self, mock_api, dashboard):
class TestNetworks:
def test_create_network(self, mock_api, dashboard):
- mock_api.add(
- responses.POST,
- f"{BASE}/organizations/{ORG_ID}/networks",
- json={
- "id": NETWORK_ID,
- "name": "_Test Network",
- "productTypes": ["appliance", "switch", "wireless"],
- "tags": ["test_tag"],
- "timeZone": "America/Los_Angeles",
- },
+ mock_api.post(f"{BASE}/organizations/{ORG_ID}/networks").mock(
+ return_value=httpx.Response(
+ 201,
+ json={
+ "id": NETWORK_ID,
+ "name": "_Test Network",
+ "productTypes": ["appliance", "switch", "wireless"],
+ "tags": ["test_tag"],
+ "timeZone": "America/Los_Angeles",
+ },
+ )
)
network = dashboard.organizations.createOrganizationNetwork(
ORG_ID,
@@ -104,38 +101,30 @@ def test_create_network(self, mock_api, dashboard):
assert network["name"] == "_Test Network"
def test_get_organization_networks(self, mock_api, dashboard):
- mock_api.add(
- responses.GET,
- f"{BASE}/organizations/{ORG_ID}/networks",
- json=[{"id": NETWORK_ID, "name": "_Test Network"}],
+ mock_api.get(f"{BASE}/organizations/{ORG_ID}/networks").mock(
+ return_value=httpx.Response(200, json=[{"id": NETWORK_ID, "name": "_Test Network"}])
)
networks = dashboard.organizations.getOrganizationNetworks(ORG_ID)
assert networks is not None
assert len(networks) > 0
def test_update_network(self, mock_api, dashboard):
- mock_api.add(
- responses.PUT,
- f"{BASE}/networks/{NETWORK_ID}",
- json={
- "id": NETWORK_ID,
- "name": "_Test Network new",
- "tags": ["updated_test_tag"],
- },
- )
- updated = dashboard.networks.updateNetwork(
- NETWORK_ID, name="_Test Network new", tags=["updated_test_tag"]
+ mock_api.put(f"{BASE}/networks/{NETWORK_ID}").mock(
+ return_value=httpx.Response(
+ 200,
+ json={
+ "id": NETWORK_ID,
+ "name": "_Test Network new",
+ "tags": ["updated_test_tag"],
+ },
+ )
)
+ updated = dashboard.networks.updateNetwork(NETWORK_ID, name="_Test Network new", tags=["updated_test_tag"])
assert updated is not None
assert updated["name"] == "_Test Network new"
def test_delete_network(self, mock_api, dashboard):
- mock_api.add(
- responses.DELETE,
- f"{BASE}/networks/{NETWORK_ID}",
- body="",
- status=204,
- )
+ mock_api.delete(f"{BASE}/networks/{NETWORK_ID}").mock(return_value=httpx.Response(204))
result = dashboard.networks.deleteNetwork(NETWORK_ID)
assert result is None
@@ -145,16 +134,17 @@ def test_delete_network(self, mock_api, dashboard):
class TestPolicyObjects:
def test_create_policy_object(self, mock_api, dashboard):
- mock_api.add(
- responses.POST,
- f"{BASE}/organizations/{ORG_ID}/policyObjects",
- json={
- "id": POLICY_OBJ_1_ID,
- "name": "Ham",
- "category": "network",
- "type": "cidr",
- "cidr": "10.51.1.253",
- },
+ mock_api.post(f"{BASE}/organizations/{ORG_ID}/policyObjects").mock(
+ return_value=httpx.Response(
+ 201,
+ json={
+ "id": POLICY_OBJ_1_ID,
+ "name": "Ham",
+ "category": "network",
+ "type": "cidr",
+ "cidr": "10.51.1.253",
+ },
+ )
)
obj = dashboard.organizations.createOrganizationPolicyObject(
ORG_ID, name="Ham", category="network", type="cidr", cidr="10.51.1.253"
@@ -163,28 +153,24 @@ def test_create_policy_object(self, mock_api, dashboard):
assert isinstance(obj["id"], str)
def test_get_policy_objects(self, mock_api, dashboard):
- mock_api.add(
- responses.GET,
- f"{BASE}/organizations/{ORG_ID}/policyObjects",
- json=[
- {"id": POLICY_OBJ_1_ID, "name": "Ham"},
- {"id": POLICY_OBJ_2_ID, "name": "Hamlet"},
- ],
+ mock_api.get(f"{BASE}/organizations/{ORG_ID}/policyObjects").mock(
+ return_value=httpx.Response(
+ 200,
+ json=[
+ {"id": POLICY_OBJ_1_ID, "name": "Ham"},
+ {"id": POLICY_OBJ_2_ID, "name": "Hamlet"},
+ ],
+ )
)
objs = dashboard.organizations.getOrganizationPolicyObjects(ORG_ID)
assert objs is not None
assert len(objs) > 0
def test_delete_policy_object(self, mock_api, dashboard):
- mock_api.add(
- responses.DELETE,
- f"{BASE}/organizations/{ORG_ID}/policyObjects/{POLICY_OBJ_1_ID}",
- body="",
- status=204,
- )
- result = dashboard.organizations.deleteOrganizationPolicyObject(
- ORG_ID, POLICY_OBJ_1_ID
+ mock_api.delete(f"{BASE}/organizations/{ORG_ID}/policyObjects/{POLICY_OBJ_1_ID}").mock(
+ return_value=httpx.Response(204)
)
+ result = dashboard.organizations.deleteOrganizationPolicyObject(ORG_ID, POLICY_OBJ_1_ID)
assert result is None
@@ -193,43 +179,43 @@ def test_delete_policy_object(self, mock_api, dashboard):
class TestAppliance:
def test_get_l3_firewall_rules(self, mock_api, dashboard):
- mock_api.add(
- responses.GET,
- f"{BASE}/networks/{NETWORK_ID}/appliance/firewall/l3FirewallRules",
- json={
- "rules": [
- {"comment": "Default rule", "policy": "allow", "protocol": "Any"}
- ]
- },
- )
- rules = dashboard.appliance.getNetworkApplianceFirewallL3FirewallRules(
- NETWORK_ID
+ mock_api.get(f"{BASE}/networks/{NETWORK_ID}/appliance/firewall/l3FirewallRules").mock(
+ return_value=httpx.Response(
+ 200,
+ json={
+ "rules": [
+ {
+ "comment": "Default rule",
+ "policy": "allow",
+ "protocol": "Any",
+ }
+ ]
+ },
+ )
)
+ rules = dashboard.appliance.getNetworkApplianceFirewallL3FirewallRules(NETWORK_ID)
assert rules is not None
assert len(rules) > 0
def test_update_vlan_settings(self, mock_api, dashboard):
- mock_api.add(
- responses.PUT,
- f"{BASE}/networks/{NETWORK_ID}/appliance/vlans/settings",
- json={"vlansEnabled": True},
- )
- resp = dashboard.appliance.updateNetworkApplianceVlansSettings(
- NETWORK_ID, vlansEnabled=True
+ mock_api.put(f"{BASE}/networks/{NETWORK_ID}/appliance/vlans/settings").mock(
+ return_value=httpx.Response(200, json={"vlansEnabled": True})
)
+ resp = dashboard.appliance.updateNetworkApplianceVlansSettings(NETWORK_ID, vlansEnabled=True)
assert resp is not None
assert resp["vlansEnabled"]
def test_create_vlan(self, mock_api, dashboard):
- mock_api.add(
- responses.POST,
- f"{BASE}/networks/{NETWORK_ID}/appliance/vlans",
- json={
- "id": "51",
- "name": "testy_vlan",
- "subnet": "10.51.1.0/24",
- "applianceIp": "10.51.1.1",
- },
+ mock_api.post(f"{BASE}/networks/{NETWORK_ID}/appliance/vlans").mock(
+ return_value=httpx.Response(
+ 201,
+ json={
+ "id": "51",
+ "name": "testy_vlan",
+ "subnet": "10.51.1.0/24",
+ "applianceIp": "10.51.1.1",
+ },
+ )
)
vlan = dashboard.appliance.createNetworkApplianceVlan(
NETWORK_ID,
@@ -242,16 +228,25 @@ def test_create_vlan(self, mock_api, dashboard):
assert vlan["name"] == "testy_vlan"
def test_update_l3_firewall_rules(self, mock_api, dashboard):
- mock_api.add(
- responses.PUT,
- f"{BASE}/networks/{NETWORK_ID}/appliance/firewall/l3FirewallRules",
- json={
- "rules": [
- {"comment": "HamByIP", "policy": "deny", "protocol": "tcp"},
- {"comment": "Ham", "policy": "deny", "protocol": "tcp"},
- {"comment": "Default rule", "policy": "allow", "protocol": "Any"},
- ]
- },
+ mock_api.put(f"{BASE}/networks/{NETWORK_ID}/appliance/firewall/l3FirewallRules").mock(
+ return_value=httpx.Response(
+ 200,
+ json={
+ "rules": [
+ {
+ "comment": "HamByIP",
+ "policy": "deny",
+ "protocol": "tcp",
+ },
+ {"comment": "Ham", "policy": "deny", "protocol": "tcp"},
+ {
+ "comment": "Default rule",
+ "policy": "allow",
+ "protocol": "Any",
+ },
+ ]
+ },
+ )
)
updated = dashboard.appliance.updateNetworkApplianceFirewallL3FirewallRules(
NETWORK_ID,
diff --git a/tests/unit/test_rest_session.py b/tests/unit/test_rest_session.py
index e6fe4035..1c593c5d 100644
--- a/tests/unit/test_rest_session.py
+++ b/tests/unit/test_rest_session.py
@@ -1,136 +1,11 @@
from unittest.mock import MagicMock, patch
+import httpx
import pytest
-import requests
from meraki.exceptions import APIError, SessionInputError
-from meraki.rest_session import RestSession, encode_params, user_agent_extended
-
-
-@pytest.fixture
-def session():
- with patch("meraki.rest_session.check_python_version"):
- s = RestSession(
- logger=None,
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- certificate_path="",
- requests_proxy="",
- wait_on_rate_limit=True,
- nginx_429_retry_wait_time=2,
- action_batch_retry_wait_time=2,
- network_delete_retry_wait_time=2,
- retry_4xx_error=False,
- retry_4xx_error_wait_time=1,
- maximum_retries=3,
- simulate=False,
- be_geo_id="",
- caller="TestApp TestVendor",
- use_iterator_for_get_pages=False,
- )
- return s
-
-
-@pytest.fixture
-def session_with_logger():
- with patch("meraki.rest_session.check_python_version"):
- s = RestSession(
- logger=MagicMock(),
- api_key="fake_api_key_1234567890123456789012345678901234567890",
- base_url="https://api.meraki.com/api/v1",
- single_request_timeout=60,
- certificate_path="",
- requests_proxy="",
- wait_on_rate_limit=True,
- nginx_429_retry_wait_time=2,
- action_batch_retry_wait_time=2,
- network_delete_retry_wait_time=2,
- retry_4xx_error=False,
- retry_4xx_error_wait_time=1,
- maximum_retries=2,
- simulate=False,
- be_geo_id="",
- caller="TestApp TestVendor",
- use_iterator_for_get_pages=False,
- )
- return s
-
-
-def _metadata(operation="getOrganizations", tags=None):
- return {"tags": tags or ["organizations"], "operation": operation}
-
-
-def _mock_response(
- status_code=200,
- json_data=None,
- reason="OK",
- headers=None,
- content=b'{"ok":true}',
- links=None,
-):
- resp = MagicMock(spec=requests.Response)
- resp.status_code = status_code
- resp.reason = reason
- resp.headers = headers or {}
- resp.content = content
- resp.links = links or {}
- resp.json.return_value = json_data if json_data is not None else {"ok": True}
- resp.close = MagicMock()
- return resp
-
-
-# --- encode_params tests ---
-
-
-class TestEncodeParams:
- def test_string_passthrough(self):
- assert encode_params(None, "already_encoded") == "already_encoded"
-
- def test_bytes_passthrough(self):
- assert encode_params(None, b"raw") == b"raw"
-
- def test_file_like_passthrough(self):
- class FakeFile:
- def read(self):
- pass
-
- f = FakeFile()
- assert encode_params(None, f) is f
- def test_simple_dict(self):
- result = encode_params(None, {"key": "value"})
- assert "key=value" in result
-
- def test_list_values(self):
- result = encode_params(None, {"tag": ["a", "b"]})
- assert "tag=a" in result
- assert "tag=b" in result
-
- def test_dict_values_appended_keys(self):
- result = encode_params(None, {"param[]": [{"key1": "val1"}, {"key2": "val2"}]})
- assert "param%5B%5Dkey1=val1" in result
- assert "param%5B%5Dkey2=val2" in result
-
- def test_none_passthrough(self):
- assert encode_params(None, 42) == 42
-
-
-# --- user_agent_extended tests ---
-
-
-class TestUserAgentExtended:
- def test_with_caller(self):
- result = user_agent_extended(None, "MyApp MyVendor")
- assert "MyApp MyVendor" in result
-
- def test_with_be_geo_id_fallback(self):
- result = user_agent_extended("geo123", None)
- assert "geo123" in result
-
- def test_unidentified_fallback(self):
- result = user_agent_extended(None, None)
- assert "unidentified" in result
+from tests.unit.conftest import make_metadata as _metadata, make_mock_response as _mock_response
# --- Retry logic tests ---
@@ -139,11 +14,9 @@ def test_unidentified_fallback(self):
class TestRetryLogic:
@patch("time.sleep", return_value=None)
def test_retry_on_429_with_retry_after(self, mock_sleep, session):
- resp_429 = _mock_response(
- 429, reason="Too Many Requests", headers={"Retry-After": "1"}
- )
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_429, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_429, resp_200])
result = session.request(_metadata(), "GET", "/organizations")
assert result.status_code == 200
@@ -151,9 +24,9 @@ def test_retry_on_429_with_retry_after(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_retry_on_429_without_retry_after(self, mock_sleep, session):
- resp_429 = _mock_response(429, reason="Too Many Requests", headers={})
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={})
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_429, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_429, resp_200])
with patch("random.randint", return_value=1):
result = session.request(_metadata(), "GET", "/organizations")
@@ -162,10 +35,8 @@ def test_retry_on_429_without_retry_after(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_429_raises_after_max_retries(self, mock_sleep, session):
session._maximum_retries = 2
- resp_429 = _mock_response(
- 429, reason="Too Many Requests", headers={"Retry-After": "1"}
- )
- session._req_session.request = MagicMock(return_value=resp_429)
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
+ session._client.request = MagicMock(return_value=resp_429)
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
@@ -173,17 +44,17 @@ def test_429_raises_after_max_retries(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_429_raises_immediately_when_wait_disabled(self, mock_sleep, session):
session._wait_on_rate_limit = False
- resp_429 = _mock_response(429, reason="Too Many Requests", headers={})
- session._req_session.request = MagicMock(return_value=resp_429)
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={})
+ session._client.request = MagicMock(return_value=resp_429)
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
@patch("time.sleep", return_value=None)
def test_retry_on_5xx(self, mock_sleep, session):
- resp_500 = _mock_response(500, reason="Internal Server Error")
+ resp_500 = _mock_response(500, reason_phrase="Internal Server Error")
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_500, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_500, resp_200])
result = session.request(_metadata(), "GET", "/organizations")
assert result.status_code == 200
@@ -191,12 +62,77 @@ def test_retry_on_5xx(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_5xx_raises_after_max_retries(self, mock_sleep, session):
session._maximum_retries = 2
- resp_500 = _mock_response(500, reason="Internal Server Error")
- session._req_session.request = MagicMock(return_value=resp_500)
+ resp_500 = _mock_response(500, reason_phrase="Internal Server Error")
+ session._client.request = MagicMock(return_value=resp_500)
+
+ with pytest.raises(APIError):
+ session.request(_metadata(), "GET", "/organizations")
+
+ @patch("time.sleep", return_value=None)
+ def test_retry_on_connection_error(self, mock_sleep, session):
+ exc = httpx.ConnectError("Connection refused")
+ resp_200 = _mock_response(200)
+ session._client.request = MagicMock(side_effect=[exc, resp_200])
+
+ result = session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
+
+ @patch("time.sleep", return_value=None)
+ def test_connection_error_raises_after_max_retries(self, mock_sleep, session):
+ session._maximum_retries = 1
+ exc = httpx.ConnectError("Connection refused")
+ session._client.request = MagicMock(side_effect=[exc])
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
+ @patch("time.sleep", return_value=None)
+ def test_429_retry_count_matches_maximum_retries(self, mock_sleep, session):
+ """Verify exactly maximum_retries attempts occur before APIError."""
+ session._maximum_retries = 3
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={"Retry-After": "1"})
+ session._client.request = MagicMock(return_value=resp_429)
+
+ with pytest.raises(APIError):
+ session.request(_metadata(), "GET", "/organizations")
+
+ assert session._client.request.call_count == 3
+
+ @patch("time.sleep", return_value=None)
+ def test_429_uses_retry_after_header_value(self, mock_sleep, session):
+ """Verify sleep uses exact Retry-After header value."""
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={"Retry-After": "7"})
+ resp_200 = _mock_response(200)
+ session._client.request = MagicMock(side_effect=[resp_429, resp_200])
+
+ session.request(_metadata(), "GET", "/organizations")
+ mock_sleep.assert_called_with(7)
+
+ @patch("time.sleep", return_value=None)
+ def test_server_error_retries_exactly_maximum_retries(self, mock_sleep, session):
+ """Verify 5xx retries exhaust exactly maximum_retries attempts."""
+ session._maximum_retries = 2
+ resp_500 = _mock_response(500, reason_phrase="Internal Server Error")
+ session._client.request = MagicMock(return_value=resp_500)
+
+ with pytest.raises(APIError):
+ session.request(_metadata(), "GET", "/organizations")
+
+ assert session._client.request.call_count == 2
+ assert mock_sleep.call_count == 2
+
+ @patch("time.sleep", return_value=None)
+ def test_connection_error_retries_exactly_maximum_retries(self, mock_sleep, session):
+ """Verify HTTPError retries exhaust exactly maximum_retries attempts."""
+ session._maximum_retries = 3
+ session._client.request = MagicMock(side_effect=httpx.ConnectError("connection refused"))
+
+ with pytest.raises(APIError):
+ session.request(_metadata(), "GET", "/organizations")
+
+ assert session._client.request.call_count == 3
+ assert mock_sleep.call_count == 3
+
# --- X-Request-Id logging on 5xx ---
@@ -207,11 +143,11 @@ def test_request_id_logged_in_warning(self, mock_sleep, session_with_logger):
session = session_with_logger
resp_500 = _mock_response(
500,
- reason="Internal Server Error",
+ reason_phrase="Internal Server Error",
headers={"X-Request-Id": "abc123def456"},
)
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_500, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_500, resp_200])
result = session.request(_metadata(), "GET", "/organizations")
@@ -225,10 +161,10 @@ def test_request_id_logged_as_error_after_exhausting_retries(self, mock_sleep, s
session._maximum_retries = 2
resp_500 = _mock_response(
500,
- reason="Internal Server Error",
+ reason_phrase="Internal Server Error",
headers={"X-Request-Id": "deadbeef00112233"},
)
- session._req_session.request = MagicMock(return_value=resp_500)
+ session._client.request = MagicMock(return_value=resp_500)
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
@@ -241,8 +177,8 @@ def test_request_id_logged_as_error_after_exhausting_retries(self, mock_sleep, s
def test_no_request_id_logs_none(self, mock_sleep, session_with_logger):
session = session_with_logger
session._maximum_retries = 2
- resp_500 = _mock_response(500, reason="Internal Server Error", headers={})
- session._req_session.request = MagicMock(return_value=resp_500)
+ resp_500 = _mock_response(500, reason_phrase="Internal Server Error", headers={})
+ session._client.request = MagicMock(return_value=resp_500)
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
@@ -252,26 +188,6 @@ def test_no_request_id_logs_none(self, mock_sleep, session_with_logger):
error_messages = [c.args[0] for c in session._logger.error.call_args_list]
assert any("log lookup: none" in m for m in error_messages)
- @patch("time.sleep", return_value=None)
- def test_retry_on_connection_error(self, mock_sleep, session):
- exc = requests.exceptions.ConnectionError("Connection refused")
- exc.response = None
- resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[exc, resp_200])
-
- result = session.request(_metadata(), "GET", "/organizations")
- assert result.status_code == 200
-
- @patch("time.sleep", return_value=None)
- def test_connection_error_raises_after_max_retries(self, mock_sleep, session):
- session._maximum_retries = 1
- exc = requests.exceptions.ConnectionError("Connection refused")
- exc.response = None
- session._req_session.request = MagicMock(side_effect=[exc])
-
- with pytest.raises(APIError):
- session.request(_metadata(), "GET", "/organizations")
-
# --- Pagination tests ---
@@ -280,7 +196,7 @@ class TestPaginationLegacy:
@patch("time.sleep", return_value=None)
def test_single_page(self, mock_sleep, session):
resp = _mock_response(200, json_data=[{"id": "1"}], links={})
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session._get_pages_legacy(_metadata(), "/organizations")
assert result == [{"id": "1"}]
@@ -290,18 +206,12 @@ def test_multiple_pages(self, mock_sleep, session):
resp1 = _mock_response(
200,
json_data=[{"id": "1"}],
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"}},
)
resp2 = _mock_response(200, json_data=[{"id": "2"}], links={})
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
- result = session._get_pages_legacy(
- _metadata(), "/organizations", total_pages=-1
- )
+ result = session._get_pages_legacy(_metadata(), "/organizations", total_pages=-1)
assert result == [{"id": "1"}, {"id": "2"}]
@patch("time.sleep", return_value=None)
@@ -309,22 +219,14 @@ def test_total_pages_limit(self, mock_sleep, session):
resp1 = _mock_response(
200,
json_data=[{"id": "1"}],
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=1"}},
)
resp2 = _mock_response(
200,
json_data=[{"id": "2"}],
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/organizations?startingAfter=2"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/organizations?startingAfter=2"}},
)
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
result = session._get_pages_legacy(_metadata(), "/organizations", total_pages=2)
assert result == [{"id": "1"}, {"id": "2"}]
@@ -332,24 +234,20 @@ def test_total_pages_limit(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_total_pages_string_all(self, mock_sleep, session):
resp = _mock_response(200, json_data=[{"id": "1"}], links={})
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
- result = session._get_pages_legacy(
- _metadata(), "/organizations", total_pages="all"
- )
+ result = session._get_pages_legacy(_metadata(), "/organizations", total_pages="all")
assert result == [{"id": "1"}]
@patch("time.sleep", return_value=None)
def test_total_pages_invalid_raises(self, mock_sleep, session):
with pytest.raises(SessionInputError):
- session._get_pages_legacy(
- _metadata(), "/organizations", total_pages="invalid"
- )
+ session._get_pages_legacy(_metadata(), "/organizations", total_pages="invalid")
@patch("time.sleep", return_value=None)
def test_204_no_content(self, mock_sleep, session):
- resp = _mock_response(204, json_data=None, reason="No Content", links={})
- session._req_session.request = MagicMock(return_value=resp)
+ resp = _mock_response(204, json_data=None, reason_phrase="No Content", links={})
+ session._client.request = MagicMock(return_value=resp)
result = session._get_pages_legacy(_metadata(), "/organizations")
assert result is None
@@ -362,9 +260,7 @@ def test_items_dict_pagination(self, mock_sleep, session):
"items": [{"id": "1"}],
"meta": {"counts": {"items": {"remaining": 1}}},
},
- links={
- "next": {"url": "https://api.meraki.com/api/v1/things?startingAfter=1"}
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/things?startingAfter=1"}},
)
resp2 = _mock_response(
200,
@@ -374,7 +270,7 @@ def test_items_dict_pagination(self, mock_sleep, session):
},
links={},
)
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
result = session._get_pages_legacy(_metadata(), "/things", total_pages=-1)
assert result["items"] == [{"id": "1"}, {"id": "2"}]
@@ -385,7 +281,7 @@ class TestPaginationIterator:
@patch("time.sleep", return_value=None)
def test_single_page_yields_items(self, mock_sleep, session):
resp = _mock_response(200, json_data=[{"id": "1"}, {"id": "2"}], links={})
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
results = list(session._get_pages_iterator(_metadata(), "/organizations"))
assert results == [{"id": "1"}, {"id": "2"}]
@@ -395,24 +291,18 @@ def test_multiple_pages_yields_all(self, mock_sleep, session):
resp1 = _mock_response(
200,
json_data=[{"id": "1"}],
- links={
- "next": {"url": "https://api.meraki.com/api/v1/orgs?startingAfter=1"}
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/orgs?startingAfter=1"}},
)
resp2 = _mock_response(200, json_data=[{"id": "2"}], links={})
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
- results = list(
- session._get_pages_iterator(_metadata(), "/organizations", total_pages=-1)
- )
+ results = list(session._get_pages_iterator(_metadata(), "/organizations", total_pages=-1))
assert results == [{"id": "1"}, {"id": "2"}]
@patch("time.sleep", return_value=None)
def test_items_dict_yields_items(self, mock_sleep, session):
- resp = _mock_response(
- 200, json_data={"items": [{"id": "a"}, {"id": "b"}]}, links={}
- )
- session._req_session.request = MagicMock(return_value=resp)
+ resp = _mock_response(200, json_data={"items": [{"id": "a"}, {"id": "b"}]}, links={})
+ session._client.request = MagicMock(return_value=resp)
results = list(session._get_pages_iterator(_metadata(), "/things"))
assert results == [{"id": "a"}, {"id": "b"}]
@@ -424,10 +314,8 @@ def test_items_dict_yields_items(self, mock_sleep, session):
class TestHandle4xxErrors:
@patch("time.sleep", return_value=None)
def test_generic_4xx_raises_immediately(self, mock_sleep, session):
- resp_400 = _mock_response(
- 400, json_data={"errors": ["bad request"]}, reason="Bad Request"
- )
- session._req_session.request = MagicMock(return_value=resp_400)
+ resp_400 = _mock_response(400, json_data={"errors": ["bad request"]}, reason_phrase="Bad Request")
+ session._client.request = MagicMock(return_value=resp_400)
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
@@ -437,15 +325,13 @@ def test_network_delete_concurrency_retries(self, mock_sleep, session):
resp_400 = _mock_response(
400,
json_data={"errors": ["concurrent requests detected"]},
- reason="Bad Request",
+ reason_phrase="Bad Request",
)
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_400, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_400, resp_200])
with patch("random.randint", return_value=1):
- result = session.request(
- _metadata(operation="deleteNetwork"), "DELETE", "/networks/123"
- )
+ result = session.request(_metadata(operation="deleteNetwork"), "DELETE", "/networks/123")
assert result.status_code == 200
@patch("time.sleep", return_value=None)
@@ -453,10 +339,10 @@ def test_action_batch_concurrency_retries(self, mock_sleep, session):
resp_400 = _mock_response(
400,
json_data={"errors": ["Too many concurrently executing batches"]},
- reason="Bad Request",
+ reason_phrase="Bad Request",
)
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_400, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_400, resp_200])
result = session.request(_metadata(operation="createBatch"), "POST", "/batches")
assert result.status_code == 200
@@ -464,11 +350,9 @@ def test_action_batch_concurrency_retries(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_retry_4xx_when_enabled(self, mock_sleep, session):
session._retry_4xx_error = True
- resp_400 = _mock_response(
- 400, json_data={"errors": ["something"]}, reason="Bad Request"
- )
+ resp_400 = _mock_response(400, json_data={"errors": ["something"]}, reason_phrase="Bad Request")
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_400, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_400, resp_200])
with patch("random.randint", return_value=1):
result = session.request(_metadata(), "GET", "/organizations")
@@ -487,7 +371,7 @@ def test_simulate_skips_non_get(self, session):
def test_simulate_allows_get(self, session):
session._simulate = True
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(return_value=resp_200)
+ session._client.request = MagicMock(return_value=resp_200)
result = session.request(_metadata(), "GET", "/organizations")
assert result.status_code == 200
@@ -500,41 +384,35 @@ class TestRedirect:
def test_follows_redirect(self, mock_sleep, session):
resp_301 = _mock_response(
301,
- reason="Moved",
+ reason_phrase="Moved",
headers={"Location": "https://n123.meraki.com/api/v1/organizations"},
)
resp_200 = _mock_response(200)
- session._req_session.request = MagicMock(side_effect=[resp_301, resp_200])
+ session._client.request = MagicMock(side_effect=[resp_301, resp_200])
result = session.request(_metadata(), "GET", "/organizations")
assert result.status_code == 200
-# --- prepare_request ---
+# --- _transport_kwargs ---
-class TestPrepareRequest:
- def test_sets_timeout(self, session):
- kwargs = {}
- session.prepare_request(kwargs)
- assert kwargs["timeout"] == 60
+class TestTransportKwargs:
+ def test_returns_kwargs_unchanged(self, session):
+ kwargs = {"params": {"foo": "bar"}}
+ result = session._transport_kwargs(kwargs)
+ assert result == {"params": {"foo": "bar"}}
- def test_sets_certificate(self, session):
- session._certificate_path = "/path/to/cert.pem"
+ def test_does_not_inject_timeout(self, session):
kwargs = {}
- session.prepare_request(kwargs)
- assert kwargs["verify"] == "/path/to/cert.pem"
+ result = session._transport_kwargs(kwargs)
+ assert "timeout" not in result
- def test_sets_proxy(self, session):
- session._requests_proxy = "https://proxy:8080"
+ def test_does_not_inject_verify(self, session):
+ session._certificate_path = "/path/to/cert.pem"
kwargs = {}
- session.prepare_request(kwargs)
- assert kwargs["proxies"] == {"https": "https://proxy:8080"}
-
- def test_does_not_override_existing(self, session):
- kwargs = {"timeout": 30}
- session.prepare_request(kwargs)
- assert kwargs["timeout"] == 30
+ result = session._transport_kwargs(kwargs)
+ assert "verify" not in result
# --- HTTP verb methods ---
@@ -543,56 +421,62 @@ def test_does_not_override_existing(self, session):
class TestHTTPVerbs:
def test_get_returns_json(self, session):
resp = _mock_response(200, json_data={"id": "1"}, content=b'{"id":"1"}')
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session.get(_metadata(), "/organizations")
assert result == {"id": "1"}
def test_get_returns_none_on_empty_content(self, session):
resp = _mock_response(200, json_data=None, content=b" ")
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session.get(_metadata(), "/organizations")
assert result is None
def test_get_returns_none_when_simulated(self, session):
session._simulate = True
resp = _mock_response(200, json_data={"id": "1"}, content=b'{"id":"1"}')
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
# GET still goes through in simulate mode
result = session.get(_metadata(), "/organizations")
assert result == {"id": "1"}
def test_post_returns_json(self, session):
resp = _mock_response(201, json_data={"id": "new"}, content=b'{"id":"new"}')
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session.post(_metadata(), "/organizations", json={"name": "Test"})
assert result == {"id": "new"}
def test_post_returns_none_on_empty_content(self, session):
resp = _mock_response(204, json_data=None, content=b"")
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session.post(_metadata(), "/organizations", json={"name": "Test"})
assert result is None
def test_put_returns_json(self, session):
- resp = _mock_response(
- 200, json_data={"id": "updated"}, content=b'{"id":"updated"}'
- )
- session._req_session.request = MagicMock(return_value=resp)
+ resp = _mock_response(200, json_data={"id": "updated"}, content=b'{"id":"updated"}')
+ session._client.request = MagicMock(return_value=resp)
result = session.put(_metadata(), "/organizations/1", json={"name": "New"})
assert result == {"id": "updated"}
def test_put_returns_none_on_empty_content(self, session):
resp = _mock_response(200, json_data=None, content=b" ")
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session.put(_metadata(), "/organizations/1", json={"name": "New"})
assert result is None
def test_delete_returns_none(self, session):
- resp = _mock_response(204, reason="No Content", content=b"")
- session._req_session.request = MagicMock(return_value=resp)
+ resp = _mock_response(204, reason_phrase="No Content", content=b"")
+ session._client.request = MagicMock(return_value=resp)
result = session.delete(_metadata(), "/organizations/1")
assert result is None
+ def test_delete_passes_query_params(self, session):
+ resp = _mock_response(204, reason_phrase="No Content", content=b"")
+ session._client.request = MagicMock(return_value=resp)
+ params = {"force": "true"}
+ session.delete(_metadata(), "/networks/1/groupPolicies/1", params)
+ call_kwargs = session._client.request.call_args
+ assert call_kwargs.kwargs.get("params") == params
+
# --- Connection error with response object ---
@@ -601,14 +485,11 @@ class TestConnectionErrorWithResponse:
@patch("time.sleep", return_value=None)
def test_connection_error_with_response_status(self, mock_sleep, session):
session._maximum_retries = 1
- exc = requests.exceptions.ConnectionError("refused")
- exc.response = MagicMock()
- exc.response.status_code = 502
- session._req_session.request = MagicMock(side_effect=[exc])
+ exc = httpx.ConnectError("refused")
+ session._client.request = MagicMock(side_effect=[exc])
- with pytest.raises(APIError) as exc_info:
+ with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
- assert exc_info.value.status == 502
# --- JSON decode retry exhaustion ---
@@ -622,7 +503,7 @@ def test_bad_json_raises_after_max_retries(self, mock_sleep, session):
session._maximum_retries = 2
resp = _mock_response(200, content=b'{"ok":true}')
resp.json.side_effect = json_mod.decoder.JSONDecodeError("", "", 0)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
with pytest.raises(APIError):
session.request(_metadata(), "GET", "/organizations")
@@ -637,12 +518,10 @@ def test_prev_direction(self, mock_sleep, session):
resp1 = _mock_response(
200,
json_data=[{"id": "2"}],
- links={
- "prev": {"url": "https://api.meraki.com/api/v1/orgs?endingBefore=2"}
- },
+ links={"prev": {"url": "https://api.meraki.com/api/v1/orgs?endingBefore=2"}},
)
resp2 = _mock_response(200, json_data=[{"id": "1"}], links={})
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
result = session._get_pages_legacy(_metadata(), "/orgs", direction="prev")
assert result == [{"id": "2"}, {"id": "1"}]
@@ -658,7 +537,7 @@ def test_event_log_next_reverses_events(self, mock_sleep, session):
},
links={},
)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
metadata = _metadata(operation="getNetworkEvents")
result = session._get_pages_legacy(metadata, "/events", direction="next")
@@ -675,22 +554,14 @@ def test_event_log_breaks_on_recent_starting_after(self, mock_sleep, session):
"pageStartAt": "2024-01-01T00:00:00Z",
"pageEndAt": "2024-01-01T01:00:00Z",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2024-01-01T00:00:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-01-01T00:00:00+00:00"}},
)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
metadata = _metadata(operation="getNetworkEvents")
- with patch("meraki.rest_session.datetime") as mock_dt:
- mock_dt.now.return_value = datetime(
- 2024, 1, 1, 0, 2, 0, tzinfo=timezone.utc
- )
- mock_dt.fromisoformat.return_value = datetime(
- 2024, 1, 1, 0, 0, 0, tzinfo=timezone.utc
- )
+ with patch("meraki.session.sync.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2024, 1, 1, 0, 2, 0, tzinfo=timezone.utc)
+ mock_dt.fromisoformat.return_value = datetime(2024, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
result = session._get_pages_legacy(metadata, "/events", direction="next")
assert result["events"] == [{"ts": "a"}]
@@ -705,22 +576,14 @@ def test_event_log_breaks_on_end_time(self, mock_sleep, session):
"pageStartAt": "2024-01-01T00:00:00Z",
"pageEndAt": "2024-01-01T01:00:00Z",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2024-06-01T00:00:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-06-01T00:00:00+00:00"}},
)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
metadata = _metadata(operation="getNetworkEvents")
- with patch("meraki.rest_session.datetime") as mock_dt:
- mock_dt.now.return_value = datetime(
- 2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc
- )
- mock_dt.fromisoformat.return_value = datetime(
- 2024, 6, 1, 0, 0, 0, tzinfo=timezone.utc
- )
+ with patch("meraki.session.sync.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
+ mock_dt.fromisoformat.return_value = datetime(2024, 6, 1, 0, 0, 0, tzinfo=timezone.utc)
result = session._get_pages_legacy(
metadata,
"/events",
@@ -738,13 +601,9 @@ def test_event_log_prev_breaks_before_2014(self, mock_sleep, session):
"pageStartAt": "2014-01-01T00:00:00Z",
"pageEndAt": "2014-01-02T00:00:00Z",
},
- links={
- "prev": {
- "url": "https://api.meraki.com/api/v1/events?endingBefore=2013-12-31T00:00:00Z"
- }
- },
+ links={"prev": {"url": "https://api.meraki.com/api/v1/events?endingBefore=2013-12-31T00:00:00Z"}},
)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
metadata = _metadata(operation="getNetworkEvents")
result = session._get_pages_legacy(metadata, "/events", direction="prev")
@@ -753,7 +612,7 @@ def test_event_log_prev_breaks_before_2014(self, mock_sleep, session):
@patch("time.sleep", return_value=None)
def test_total_pages_numeric_string(self, mock_sleep, session):
resp = _mock_response(200, json_data=[{"id": "1"}], links={})
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
result = session._get_pages_legacy(_metadata(), "/orgs", total_pages="3")
assert result == [{"id": "1"}]
@@ -767,11 +626,7 @@ def test_event_log_multi_page_extends_events(self, mock_sleep, session):
"pageStartAt": "2024-01-01T00:00:00Z",
"pageEndAt": "2024-01-01T01:00:00Z",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2014-06-01T00:00:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2014-06-01T00:00:00+00:00"}},
)
resp2 = _mock_response(
200,
@@ -782,18 +637,14 @@ def test_event_log_multi_page_extends_events(self, mock_sleep, session):
},
links={},
)
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
from datetime import datetime, timezone
- with patch("meraki.rest_session.datetime") as mock_dt:
- mock_dt.now.return_value = datetime(
- 2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc
- )
- mock_dt.fromisoformat.return_value = datetime(
- 2014, 6, 1, 0, 0, 0, tzinfo=timezone.utc
- )
+ with patch("meraki.session.sync.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
+ mock_dt.fromisoformat.return_value = datetime(2014, 6, 1, 0, 0, 0, tzinfo=timezone.utc)
result = session._get_pages_legacy(metadata, "/events", direction="next")
# First page reversed, second page reversed and appended
@@ -805,39 +656,128 @@ def test_event_log_multi_page_extends_events(self, mock_sleep, session):
# --- Pagination iterator: extended coverage ---
+class TestBackoffStrategy:
+ @patch("time.sleep", return_value=None)
+ @patch("random.random", return_value=0.5)
+ def test_429_exponential_backoff_without_retry_after(self, mock_random, mock_sleep, session):
+ """Without Retry-After, backoff is 2^attempt * (1 + random), capped."""
+ session._maximum_retries = 4
+ session._nginx_429_retry_wait_time = 60
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={})
+ resp_200 = _mock_response(200)
+
+ session._client.request = MagicMock(side_effect=[resp_429, resp_429, resp_429, resp_200])
+
+ session.request(_metadata(), "GET", "/organizations")
+
+ sleep_calls = [call.args[0] for call in mock_sleep.call_args_list]
+ assert len(sleep_calls) == 3
+ # attempt 0: 2^0 * 1.5 = 1.5
+ # attempt 1: 2^1 * 1.5 = 3.0
+ # attempt 2: 2^2 * 1.5 = 6.0
+ assert sleep_calls[0] == pytest.approx(1.5)
+ assert sleep_calls[1] == pytest.approx(3.0)
+ assert sleep_calls[2] == pytest.approx(6.0)
+
+ @patch("time.sleep", return_value=None)
+ @patch("random.random", return_value=0.0)
+ def test_429_backoff_capped_at_nginx_wait_time(self, mock_random, mock_sleep, session):
+ """Backoff never exceeds nginx_429_retry_wait_time."""
+ session._maximum_retries = 10
+ session._nginx_429_retry_wait_time = 5
+ resp_429 = _mock_response(429, reason_phrase="Too Many Requests", headers={})
+ resp_200 = _mock_response(200)
+
+ session._client.request = MagicMock(side_effect=[resp_429] * 8 + [resp_200])
+
+ session.request(_metadata(), "GET", "/organizations")
+
+ sleep_calls = [call.args[0] for call in mock_sleep.call_args_list]
+ for wait in sleep_calls:
+ assert wait <= 5, f"Wait {wait} exceeds cap of 5"
+
+
+class TestEdgeCases:
+ @patch("time.sleep", return_value=None)
+ def test_json_decode_failure_retries(self, mock_sleep, session):
+ """Invalid JSON on GET triggers retry, eventual success returns response."""
+ bad_resp = _mock_response(200, content=b"not json")
+ bad_resp.json.side_effect = ValueError("No JSON")
+ good_resp = _mock_response(200, json_data={"id": "123"})
+
+ session._client.request = MagicMock(side_effect=[bad_resp, good_resp])
+ result = session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
+ assert session._client.request.call_count == 2
+
+ @patch("time.sleep", return_value=None)
+ def test_json_decode_failure_exhausts_retries(self, mock_sleep, session):
+ """Persistent invalid JSON exhausts retries and raises APIError."""
+ session._maximum_retries = 2
+ bad_resp = _mock_response(200, content=b"not json")
+ bad_resp.json.side_effect = ValueError("No JSON")
+
+ session._client.request = MagicMock(return_value=bad_resp)
+
+ with pytest.raises(APIError):
+ session.request(_metadata(), "GET", "/organizations")
+
+ assert session._client.request.call_count == 2
+
+ def test_simulate_mode_skips_post(self, session):
+ """Simulate mode returns None for POST without making HTTP call."""
+ session._simulate = True
+ session._client.request = MagicMock()
+
+ result = session.request(_metadata(), "POST", "/organizations")
+ assert result is None
+ session._client.request.assert_not_called()
+
+ def test_simulate_mode_allows_get(self, session):
+ """Simulate mode still executes GET requests."""
+ session._simulate = True
+ resp_200 = _mock_response(200)
+ session._client.request = MagicMock(return_value=resp_200)
+
+ result = session.request(_metadata(), "GET", "/organizations")
+ assert result.status_code == 200
+ session._client.request.assert_called_once()
+
+ def test_204_no_content_returns_response(self, session):
+ """204 No Content returns the response object (not None)."""
+ resp_204 = _mock_response(204, content=b"", reason_phrase="No Content")
+ resp_204.json.side_effect = ValueError("No JSON")
+ session._client.request = MagicMock(return_value=resp_204)
+
+ result = session.request(_metadata(), "DELETE", "/organizations/123")
+ assert result.status_code == 204
+
+
class TestPaginationIteratorExtended:
@patch("time.sleep", return_value=None)
def test_total_pages_numeric_string(self, mock_sleep, session):
resp = _mock_response(200, json_data=[{"id": "1"}], links={})
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
- results = list(
- session._get_pages_iterator(_metadata(), "/orgs", total_pages="3")
- )
+ results = list(session._get_pages_iterator(_metadata(), "/orgs", total_pages="3"))
assert results == [{"id": "1"}]
@patch("time.sleep", return_value=None)
def test_total_pages_invalid_raises(self, mock_sleep, session):
with pytest.raises(SessionInputError):
- list(
- session._get_pages_iterator(_metadata(), "/orgs", total_pages="invalid")
- )
+ list(session._get_pages_iterator(_metadata(), "/orgs", total_pages="invalid"))
@patch("time.sleep", return_value=None)
def test_prev_direction(self, mock_sleep, session):
resp1 = _mock_response(
200,
json_data=[{"id": "2"}],
- links={
- "prev": {"url": "https://api.meraki.com/api/v1/orgs?endingBefore=2"}
- },
+ links={"prev": {"url": "https://api.meraki.com/api/v1/orgs?endingBefore=2"}},
)
resp2 = _mock_response(200, json_data=[{"id": "1"}], links={})
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
- results = list(
- session._get_pages_iterator(_metadata(), "/orgs", direction="prev")
- )
+ results = list(session._get_pages_iterator(_metadata(), "/orgs", direction="prev"))
assert results == [{"id": "2"}, {"id": "1"}]
@patch("time.sleep", return_value=None)
@@ -851,12 +791,10 @@ def test_event_log_next_reverses(self, mock_sleep, session):
},
links={},
)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
metadata = _metadata(operation="getNetworkEvents")
- results = list(
- session._get_pages_iterator(metadata, "/events", direction="next")
- )
+ results = list(session._get_pages_iterator(metadata, "/events", direction="next"))
assert results == [{"ts": "a"}, {"ts": "b"}]
@patch("time.sleep", return_value=None)
@@ -870,12 +808,10 @@ def test_event_log_prev_normal_order(self, mock_sleep, session):
},
links={},
)
- session._req_session.request = MagicMock(return_value=resp)
+ session._client.request = MagicMock(return_value=resp)
metadata = _metadata(operation="someOp")
- results = list(
- session._get_pages_iterator(metadata, "/events", direction="prev")
- )
+ results = list(session._get_pages_iterator(metadata, "/events", direction="prev"))
assert results == [{"ts": "a"}, {"ts": "b"}]
@patch("time.sleep", return_value=None)
@@ -890,11 +826,7 @@ def test_event_log_breaks_on_recent_starting_after(self, mock_sleep, session):
"pageStartAt": "2024-01-01",
"pageEndAt": "2024-01-02",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2014-06-01T00:00:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2014-06-01T00:00:00+00:00"}},
)
# Page 2: too recent, triggers break before yielding
resp2 = _mock_response(
@@ -904,13 +836,9 @@ def test_event_log_breaks_on_recent_starting_after(self, mock_sleep, session):
"pageStartAt": "2025-01-01",
"pageEndAt": "2025-01-02",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2025-01-01T23:58:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2025-01-01T23:58:00+00:00"}},
)
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
call_count = [0]
@@ -921,14 +849,10 @@ def fake_fromisoformat(s):
return datetime(2014, 6, 1, 0, 0, 0, tzinfo=timezone.utc)
return datetime(2025, 1, 1, 23, 58, 0, tzinfo=timezone.utc)
- with patch("meraki.rest_session.datetime") as mock_dt:
- mock_dt.now.return_value = datetime(
- 2025, 1, 2, 0, 0, 0, tzinfo=timezone.utc
- )
+ with patch("meraki.session.sync.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2025, 1, 2, 0, 0, 0, tzinfo=timezone.utc)
mock_dt.fromisoformat = fake_fromisoformat
- results = list(
- session._get_pages_iterator(metadata, "/events", direction="next")
- )
+ results = list(session._get_pages_iterator(metadata, "/events", direction="next"))
# Only page 1 yielded (reversed)
assert results == [{"ts": "a"}]
@@ -944,11 +868,7 @@ def test_event_log_breaks_on_end_time(self, mock_sleep, session):
"pageStartAt": "2024-01-01",
"pageEndAt": "2024-01-02",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2024-03-01T00:00:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-03-01T00:00:00+00:00"}},
)
# Page 2: past end_time, triggers break
resp2 = _mock_response(
@@ -958,13 +878,9 @@ def test_event_log_breaks_on_end_time(self, mock_sleep, session):
"pageStartAt": "2024-06-01",
"pageEndAt": "2024-06-02",
},
- links={
- "next": {
- "url": "https://api.meraki.com/api/v1/events?startingAfter=2024-07-01T00:00:00+00:00"
- }
- },
+ links={"next": {"url": "https://api.meraki.com/api/v1/events?startingAfter=2024-07-01T00:00:00+00:00"}},
)
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
call_count = [0]
@@ -975,10 +891,8 @@ def fake_fromisoformat(s):
return datetime(2024, 3, 1, 0, 0, 0, tzinfo=timezone.utc)
return datetime(2024, 7, 1, 0, 0, 0, tzinfo=timezone.utc)
- with patch("meraki.rest_session.datetime") as mock_dt:
- mock_dt.now.return_value = datetime(
- 2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc
- )
+ with patch("meraki.session.sync.datetime") as mock_dt:
+ mock_dt.now.return_value = datetime(2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
mock_dt.fromisoformat = fake_fromisoformat
results = list(
session._get_pages_iterator(
@@ -1000,11 +914,7 @@ def test_event_log_prev_breaks_before_2014(self, mock_sleep, session):
"pageStartAt": "2014-06-01",
"pageEndAt": "2014-06-02",
},
- links={
- "prev": {
- "url": "https://api.meraki.com/api/v1/events?endingBefore=2014-06-01T00:00:00Z"
- }
- },
+ links={"prev": {"url": "https://api.meraki.com/api/v1/events?endingBefore=2014-06-01T00:00:00Z"}},
)
# Page 2: endingBefore is before 2014, triggers break
resp2 = _mock_response(
@@ -1014,17 +924,126 @@ def test_event_log_prev_breaks_before_2014(self, mock_sleep, session):
"pageStartAt": "2014-01-01",
"pageEndAt": "2014-01-02",
},
- links={
- "prev": {
- "url": "https://api.meraki.com/api/v1/events?endingBefore=2013-12-31T00:00:00Z"
- }
- },
+ links={"prev": {"url": "https://api.meraki.com/api/v1/events?endingBefore=2013-12-31T00:00:00Z"}},
)
- session._req_session.request = MagicMock(side_effect=[resp1, resp2])
+ session._client.request = MagicMock(side_effect=[resp1, resp2])
metadata = _metadata(operation="getNetworkEvents")
- results = list(
- session._get_pages_iterator(metadata, "/events", direction="prev")
- )
+ results = list(session._get_pages_iterator(metadata, "/events", direction="prev"))
# Only page 1 yielded
assert results == [{"ts": "a"}]
+
+
+# --- Fix #4: sync iterator 204 guard ---
+
+
+class TestSyncIterator204Guard:
+ @patch("time.sleep", return_value=None)
+ def test_204_page_terminates_iterator_cleanly(self, mock_sleep, session):
+ """A 204 No Content page must terminate the iterator without JSONDecodeError."""
+ import json as json_mod
+
+ resp_204 = _mock_response(204, reason_phrase="No Content", content=b"", links={})
+ # A 204 body would raise on .json() in the real client; ensure we never call it.
+ resp_204.json.side_effect = json_mod.decoder.JSONDecodeError("", "", 0)
+ session._client.request = MagicMock(return_value=resp_204)
+
+ results = list(session._get_pages_iterator(_metadata(), "/organizations"))
+ assert results == []
+ resp_204.json.assert_not_called()
+
+
+# --- Fix #15: Meraki array-of-objects param encoding on the wire ---
+
+
+class TestMerakiParamEncodingSync:
+ def test_list_of_dict_params_use_meraki_encoding(self, session):
+ """params dict with list-of-dict values is pre-encoded into the URL, params dropped."""
+ resp = _mock_response(200)
+ session._client.request = MagicMock(return_value=resp)
+
+ params = {"variables[]": [{"name": "n1", "value": "v1"}]}
+ session.request(_metadata(), "GET", "/things", params=params)
+
+ call = session._client.request.call_args
+ sent_url = call.args[1]
+ # array-of-objects: param[] keys concatenated with inner dict keys
+ assert "variables%5B%5Dname=n1" in sent_url
+ assert "variables%5B%5Dvalue=v1" in sent_url
+ # params must be dropped so httpx does not re-encode
+ assert call.kwargs.get("params") is None
+
+ def test_scalar_list_params_unchanged(self, session):
+ """Scalar-list params (networkIds[]=a&b) are left for httpx (repeated keys)."""
+ resp = _mock_response(200)
+ session._client.request = MagicMock(return_value=resp)
+
+ params = {"networkIds[]": ["a", "b"]}
+ session.request(_metadata(), "GET", "/things", params=params)
+
+ call = session._client.request.call_args
+ # Not folded into URL; passed through untouched to httpx
+ assert call.kwargs.get("params") == params
+ assert "networkIds" not in call.args[1]
+
+ def test_scalar_params_unchanged(self, session):
+ """Plain scalar params pass straight through to httpx."""
+ resp = _mock_response(200)
+ session._client.request = MagicMock(return_value=resp)
+
+ params = {"perPage": 10, "total_pages": "all"}
+ session.request(_metadata(), "GET", "/things", params=params)
+
+ call = session._client.request.call_args
+ assert call.kwargs.get("params") == params
+
+
+# --- Fix #12: internal resolver/hydrator GETs drain the global bucket ---
+
+
+class TestSyncGlobalBucketAccounting:
+ def _smart_flow_session(self):
+ from tests.unit.conftest import DEFAULT_SESSION_KWARGS, FAKE_API_KEY
+ from meraki.session.sync import RestSession
+
+ kwargs = {**DEFAULT_SESSION_KWARGS, "smart_flow_enabled": True}
+ with patch("meraki.session.base.check_python_version"):
+ with patch("httpx.Client") as mock_client:
+ mock_instance = MagicMock()
+ mock_instance.headers = MagicMock(spec=dict)
+ mock_client.return_value = mock_instance
+ s = RestSession(logger=None, api_key=FAKE_API_KEY, **kwargs)
+ return s
+
+ def test_resolver_acquires_global_bucket(self):
+ s = self._smart_flow_session()
+ s._smart_flow._global_bucket = MagicMock()
+ resp = _mock_response(200, json_data={"organizationId": "999"})
+ s._client.request = MagicMock(return_value=resp)
+
+ org = s._resolve_org_for_limiter("network", "N_1")
+ assert org == "999"
+ s._smart_flow._global_bucket.acquire.assert_called_once()
+
+ def test_hydrator_acquires_global_bucket_per_page(self):
+ s = self._smart_flow_session()
+ s._smart_flow._global_bucket = MagicMock()
+ page1 = _mock_response(
+ 200,
+ json_data=[{"id": "N_1"}],
+ links={"next": {"url": "https://api.meraki.com/api/v1/organizations/9/networks?page=2"}},
+ )
+ page2 = _mock_response(200, json_data=[{"id": "N_2"}], links={})
+ # _fetch_all_pages is called twice (networks then devices); supply enough responses
+ empty = _mock_response(200, json_data=[], links={})
+ s._client.request = MagicMock(side_effect=[page1, page2, empty])
+
+ s._hydrate_org_for_limiter("9")
+ # one acquire per internal GET: 2 network pages + 1 devices page = 3
+ assert s._smart_flow._global_bucket.acquire.call_count == 3
+
+ def test_acquire_global_bucket_defensive_no_smart_flow(self, session):
+ """Helper is a no-op when smart flow is disabled (no bucket present)."""
+ session._smart_flow = None
+ # Should not raise
+ session._acquire_global_bucket()
diff --git a/tests/unit/test_session_base.py b/tests/unit/test_session_base.py
new file mode 100644
index 00000000..93cacad2
--- /dev/null
+++ b/tests/unit/test_session_base.py
@@ -0,0 +1,364 @@
+"""Tests for SessionBase ABC contract and behavior."""
+
+import ast
+import json
+from pathlib import Path
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+from meraki.exceptions import APIError
+from meraki.session.base import SessionBase
+from tests.unit.conftest import make_metadata as _metadata
+
+
+# ---------------------------------------------------------------------------
+# Test helper: concrete subclass
+# ---------------------------------------------------------------------------
+
+
+class ConcreteSession(SessionBase):
+ """Minimal concrete implementation for testing."""
+
+ def __init__(self, **kwargs):
+ self.sleeps: list[float] = []
+ self._mock_response = kwargs.pop("mock_response", None)
+ with patch("meraki.session.base.check_python_version"):
+ super().__init__(**kwargs)
+
+ def _send_request(self, method: str, url: str, **kwargs):
+ return self._mock_response
+
+ def _sleep(self, seconds: float) -> None:
+ self.sleeps.append(seconds)
+
+ def _transport_kwargs(self, kwargs):
+ return kwargs
+
+
+def _make_session(**overrides):
+ """Factory with sensible defaults."""
+ from tests.unit.conftest import DEFAULT_SESSION_KWARGS, FAKE_API_KEY
+
+ defaults = {"logger": None, "api_key": FAKE_API_KEY, **DEFAULT_SESSION_KWARGS}
+ defaults.update(overrides)
+ return ConcreteSession(**defaults)
+
+
+def _mock_response(
+ status_code=200,
+ json_data=None,
+ reason_phrase="OK",
+ headers=None,
+ content=b'{"ok":true}',
+):
+ """Create a mock httpx-like response."""
+ resp = MagicMock()
+ resp.status_code = status_code
+ resp.reason_phrase = reason_phrase
+ resp.headers = headers or {}
+ resp.content = content
+ if json_data is not None:
+ resp.json.return_value = json_data
+ else:
+ try:
+ resp.json.return_value = json.loads(content) if content.strip() else None
+ except (json.JSONDecodeError, ValueError):
+ resp.json.side_effect = ValueError("No JSON")
+ return resp
+
+
+# ---------------------------------------------------------------------------
+# Tests
+# ---------------------------------------------------------------------------
+
+
+class TestABCEnforcement:
+ def test_abc_enforcement(self):
+ """SessionBase cannot be instantiated directly."""
+ with pytest.raises(TypeError):
+ SessionBase(
+ logger=None,
+ api_key="test_key_00000000000000000000000000000000000test",
+ caller="TestApp TestVendor",
+ )
+
+
+class TestConfigStorage:
+ def test_config_storage(self):
+ """Constructor stores all config attributes."""
+ session = _make_session()
+ assert session._api_key == "fake_api_key_1234567890123456789012345678901234567890"
+ assert session._base_url == "https://api.meraki.com/api/v1"
+ assert session._maximum_retries == 3
+ assert session._wait_on_rate_limit is True
+ assert session._single_request_timeout == 60
+ assert session._simulate is False
+ assert session._retry_4xx_error is False
+
+
+class TestBuildHeaders:
+ def test_build_headers(self):
+ """_build_headers produces correct Authorization, Content-Type, User-Agent."""
+ session = _make_session()
+ headers = session._build_headers()
+ assert headers["Authorization"] == "Bearer fake_api_key_1234567890123456789012345678901234567890"
+ assert headers["Content-Type"] == "application/json"
+ assert "python-meraki/" in headers["User-Agent"]
+
+
+class TestRequestSuccess:
+ def test_request_success_dispatch(self):
+ """200 response dispatches to _handle_success and returns response."""
+ resp = _mock_response(status_code=200, content=b'{"data": 1}')
+ session = _make_session(mock_response=resp)
+ result = session.request(_metadata(), "GET", "/test")
+ assert result is resp
+
+ def test_request_success_with_page(self):
+ """200 response with page metadata logs page counter."""
+ logger = MagicMock()
+ resp = _mock_response(status_code=200, content=b"[1,2,3]")
+ session = _make_session(mock_response=resp, logger=logger)
+ result = session.request(_metadata(page=2), "GET", "/test")
+ assert result is resp
+
+
+class TestRequestRateLimit:
+ def test_request_rate_limit(self):
+ """429 response triggers _handle_rate_limit with Retry-After."""
+ resp_429 = _mock_response(
+ status_code=429,
+ reason_phrase="Too Many Requests",
+ headers={"Retry-After": "3"},
+ content=b"rate limited",
+ )
+ resp_200 = _mock_response(status_code=200, content=b'{"ok":true}')
+
+ call_count = [0]
+ original_429 = resp_429
+ original_200 = resp_200
+
+ def side_effect(method, url, **kwargs):
+ call_count[0] += 1
+ if call_count[0] == 1:
+ return original_429
+ return original_200
+
+ session = _make_session()
+ session._send_request = side_effect
+ result = session.request(_metadata(), "GET", "/test")
+ assert result.status_code == 200
+ assert 3 in session.sleeps
+
+
+class TestRequestServerError:
+ def test_request_server_error(self):
+ """500 response triggers retry with 1s sleep."""
+ resp_500 = _mock_response(status_code=500, reason_phrase="Internal Server Error", content=b"error")
+ resp_200 = _mock_response(status_code=200, content=b'{"ok":true}')
+
+ call_count = [0]
+
+ def side_effect(method, url, **kwargs):
+ call_count[0] += 1
+ if call_count[0] == 1:
+ return resp_500
+ return resp_200
+
+ session = _make_session()
+ session._send_request = side_effect
+ result = session.request(_metadata(), "GET", "/test")
+ assert result.status_code == 200
+ assert 1 in session.sleeps
+
+
+class TestRequestRedirect:
+ def test_request_redirect(self):
+ """301 response updates URL via _handle_redirect."""
+ resp_301 = _mock_response(
+ status_code=301,
+ reason_phrase="Moved Permanently",
+ headers={"Location": "https://n123.meraki.com/api/v1/test"},
+ content=b"",
+ )
+ resp_200 = _mock_response(status_code=200, content=b'{"redirected":true}')
+
+ call_count = [0]
+
+ def side_effect(method, url, **kwargs):
+ call_count[0] += 1
+ if call_count[0] == 1:
+ return resp_301
+ return resp_200
+
+ session = _make_session()
+ session._send_request = side_effect
+ result = session.request(_metadata(), "GET", "/test")
+ assert result.status_code == 200
+
+
+class TestRetriesExhausted:
+ def test_request_raises_apierror_when_retries_exhausted(self):
+ """APIError raised after max retries on 500."""
+ resp_500 = _mock_response(status_code=500, reason_phrase="ISE", content=b"err")
+ session = _make_session(maximum_retries=1, mock_response=resp_500)
+ with pytest.raises(APIError):
+ session.request(_metadata(), "GET", "/test")
+
+
+class TestClientErrorNetworkDelete:
+ def test_handle_client_error_network_delete_concurrency(self):
+ """Network delete concurrency error triggers retry with random wait."""
+ resp_400 = _mock_response(
+ status_code=400,
+ reason_phrase="Bad Request",
+ content=b'{"errors":["concurrent network deletion in progress"]}',
+ json_data={"errors": ["concurrent network deletion in progress"]},
+ )
+ resp_200 = _mock_response(status_code=200, content=b'{"ok":true}')
+
+ call_count = [0]
+
+ def side_effect(method, url, **kwargs):
+ call_count[0] += 1
+ if call_count[0] == 1:
+ return resp_400
+ return resp_200
+
+ session = _make_session(network_delete_retry_wait_time=60)
+ session._send_request = side_effect
+ result = session.request(_metadata(operation="deleteNetwork"), "DELETE", "/test")
+ assert result.status_code == 200
+ assert len(session.sleeps) == 1
+ assert 30 <= session.sleeps[0] <= 60
+
+
+class TestClientErrorActionBatch:
+ def test_handle_client_error_action_batch_concurrency(self):
+ """Action batch concurrency error triggers retry."""
+ resp_400 = _mock_response(
+ status_code=400,
+ reason_phrase="Bad Request",
+ content=b'{"errors":["Currently executing batches. Try again later."]}',
+ json_data={"errors": ["Currently executing batches. Try again later."]},
+ )
+ resp_200 = _mock_response(status_code=200, content=b'{"ok":true}')
+
+ call_count = [0]
+
+ def side_effect(method, url, **kwargs):
+ call_count[0] += 1
+ if call_count[0] == 1:
+ return resp_400
+ return resp_200
+
+ session = _make_session(action_batch_retry_wait_time=5)
+ session._send_request = side_effect
+ result = session.request(_metadata(), "POST", "/test")
+ assert result.status_code == 200
+ assert 5 in session.sleeps
+
+
+class TestSimulateMode:
+ def test_simulate_mode_returns_none_for_non_get(self):
+ """Simulate mode returns None for POST without calling _send_request."""
+ session = _make_session(simulate=True)
+ call_tracker = []
+ session._send_request = lambda *a, **kw: call_tracker.append(1)
+ result = session.request(_metadata(), "POST", "/test")
+ assert result is None
+ assert len(call_tracker) == 0
+
+ def test_simulate_mode_allows_get(self):
+ """Simulate mode still performs GET requests."""
+ resp = _mock_response(status_code=200, content=b'{"data":1}')
+ session = _make_session(simulate=True, mock_response=resp)
+ result = session.request(_metadata(), "GET", "/test")
+ assert result is resp
+
+
+class TestComplexityAudit:
+ def test_complexity_audit(self):
+ """All handler methods have cyclomatic complexity under 10."""
+ base_path = Path(__file__).resolve().parent.parent.parent / "meraki" / "session" / "base.py"
+ source = base_path.read_text()
+ tree = ast.parse(source)
+
+ handler_methods = [
+ "_handle_success",
+ "_handle_redirect",
+ "_handle_rate_limit",
+ "_handle_server_error",
+ "_handle_client_error",
+ ]
+
+ for node in ast.walk(tree):
+ if isinstance(node, ast.FunctionDef) and node.name in handler_methods:
+ complexity = _compute_complexity(node)
+ assert complexity < 10, f"{node.name} has complexity {complexity} (must be < 10)"
+
+
+class TestMerakiParamEncodingHelpers:
+ """Fix #15: shared param-encoding helpers in base.py."""
+
+ def test_detects_list_of_dict(self):
+ from meraki.session.base import params_need_meraki_encoding
+
+ assert params_need_meraki_encoding({"variables[]": [{"name": "n"}]}) is True
+
+ def test_ignores_scalar_list(self):
+ from meraki.session.base import params_need_meraki_encoding
+
+ assert params_need_meraki_encoding({"networkIds[]": ["a", "b"]}) is False
+
+ def test_ignores_scalars_and_non_dict(self):
+ from meraki.session.base import params_need_meraki_encoding
+
+ assert params_need_meraki_encoding({"perPage": 10}) is False
+ assert params_need_meraki_encoding(None) is False
+ assert params_need_meraki_encoding("a=b") is False
+
+ def test_apply_folds_query_and_drops_params(self):
+ from meraki.session.base import apply_meraki_param_encoding
+
+ kwargs = {"params": {"variables[]": [{"name": "n1", "value": "v1"}]}}
+ url = apply_meraki_param_encoding("https://x/api/v1/things", kwargs)
+ assert "variables%5B%5Dname=n1" in url
+ assert "variables%5B%5Dvalue=v1" in url
+ assert url.count("?") == 1
+ assert kwargs["params"] is None
+
+ def test_apply_appends_with_ampersand_when_query_exists(self):
+ from meraki.session.base import apply_meraki_param_encoding
+
+ kwargs = {"params": {"variables[]": [{"name": "n1"}]}}
+ url = apply_meraki_param_encoding("https://x/api/v1/things?foo=bar", kwargs)
+ assert "?foo=bar&variables%5B%5Dname=n1" in url
+ assert kwargs["params"] is None
+
+ def test_apply_leaves_scalar_params_untouched(self):
+ from meraki.session.base import apply_meraki_param_encoding
+
+ kwargs = {"params": {"perPage": 10}}
+ url = apply_meraki_param_encoding("https://x/api/v1/things", kwargs)
+ assert url == "https://x/api/v1/things"
+ assert kwargs["params"] == {"perPage": 10}
+
+
+def _compute_complexity(func_node: ast.FunctionDef) -> int:
+ """Approximate McCabe cyclomatic complexity: count decision points + 1."""
+ complexity = 1
+ for node in ast.walk(func_node):
+ if isinstance(node, (ast.If, ast.IfExp)):
+ complexity += 1
+ elif isinstance(node, ast.For):
+ complexity += 1
+ elif isinstance(node, ast.While):
+ complexity += 1
+ elif isinstance(node, ast.ExceptHandler):
+ complexity += 1
+ elif isinstance(node, ast.BoolOp):
+ # Each and/or adds a branch
+ complexity += len(node.values) - 1
+ return complexity
diff --git a/tests/unit/test_smart_flow.py b/tests/unit/test_smart_flow.py
new file mode 100644
index 00000000..69aad6b2
--- /dev/null
+++ b/tests/unit/test_smart_flow.py
@@ -0,0 +1,1185 @@
+"""Tests for meraki.smart_flow module."""
+
+import asyncio
+import json
+import time
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+from meraki.smart_flow import (
+ AsyncOrgRateLimiter,
+ AsyncTokenBucket,
+ OrgRateLimiter,
+ TokenBucket,
+ _parse_saved_at,
+)
+
+
+class TestParseSavedAt:
+ def test_valid_timestamp(self):
+ ts = _parse_saved_at("2026-01-15T12:30:00Z")
+ assert ts is not None
+ assert isinstance(ts, float)
+
+ def test_non_string_returns_none(self):
+ assert _parse_saved_at(None) is None
+ assert _parse_saved_at(12345) is None
+
+ def test_invalid_format_returns_none(self):
+ assert _parse_saved_at("not-a-date") is None
+ assert _parse_saved_at("2026-13-01T00:00:00Z") is None
+
+
+class TestTokenBucket:
+ def test_acquire_within_capacity_does_not_block(self):
+ bucket = TokenBucket(rate=10.0, capacity=10)
+ start = time.monotonic()
+ for _ in range(10):
+ bucket.acquire()
+ elapsed = time.monotonic() - start
+ assert elapsed < 0.1
+
+ def test_acquire_blocks_when_exhausted(self):
+ bucket = TokenBucket(rate=10.0, capacity=1)
+ bucket.acquire()
+ start = time.monotonic()
+ bucket.acquire()
+ elapsed = time.monotonic() - start
+ assert elapsed >= 0.05
+
+ def test_rate_setter_floors_at_half(self):
+ bucket = TokenBucket(rate=10.0, capacity=10)
+ bucket.rate = 0.1
+ assert bucket.rate == 0.5
+
+ def test_rate_setter_accepts_normal_values(self):
+ bucket = TokenBucket(rate=10.0, capacity=10)
+ bucket.rate = 5.0
+ assert bucket.rate == 5.0
+
+ def test_tokens_refill_over_time(self):
+ bucket = TokenBucket(rate=100.0, capacity=5)
+ for _ in range(5):
+ bucket.acquire()
+ time.sleep(0.06)
+ start = time.monotonic()
+ bucket.acquire()
+ elapsed = time.monotonic() - start
+ assert elapsed < 0.05
+
+
+class TestAsyncTokenBucket:
+ @pytest.mark.asyncio
+ async def test_acquire_within_capacity_does_not_block(self):
+ bucket = AsyncTokenBucket(rate=10.0, capacity=10)
+ start = asyncio.get_event_loop().time()
+ for _ in range(10):
+ await bucket.acquire()
+ elapsed = asyncio.get_event_loop().time() - start
+ assert elapsed < 0.1
+
+ @pytest.mark.asyncio
+ async def test_acquire_blocks_when_exhausted(self):
+ bucket = AsyncTokenBucket(rate=10.0, capacity=1)
+ await bucket.acquire()
+ start = asyncio.get_event_loop().time()
+ await bucket.acquire()
+ elapsed = asyncio.get_event_loop().time() - start
+ assert elapsed >= 0.05
+
+ @pytest.mark.asyncio
+ async def test_rate_setter_floors_at_half(self):
+ bucket = AsyncTokenBucket(rate=10.0, capacity=10)
+ bucket.rate = 0.1
+ assert bucket.rate == 0.5
+
+ @pytest.mark.asyncio
+ async def test_rate_setter_accepts_normal_values(self):
+ bucket = AsyncTokenBucket(rate=10.0, capacity=10)
+ bucket.rate = 7.0
+ assert bucket.rate == 7.0
+
+
+class TestOrgResolveOrg:
+ def test_resolves_org_from_url(self):
+ limiter = OrgRateLimiter()
+ assert limiter.resolve_org("/organizations/123/networks") == "123"
+
+ def test_resolves_org_via_network_cache(self):
+ limiter = OrgRateLimiter()
+ limiter.register_network("N_abc", "org_1")
+ assert limiter.resolve_org("/networks/N_abc/ssids") == "org_1"
+
+ def test_resolves_org_via_device_cache(self):
+ limiter = OrgRateLimiter()
+ limiter.register_device("Q2AB-CDE4-FGHI", "org_2")
+ assert limiter.resolve_org("/devices/Q2AB-CDE4-FGHI/clients") == "org_2"
+
+ def test_returns_none_for_unknown(self):
+ limiter = OrgRateLimiter()
+ assert limiter.resolve_org("/networks/N_unknown/ssids") is None
+
+ def test_returns_none_for_unrecognized_url(self):
+ limiter = OrgRateLimiter()
+ assert limiter.resolve_org("/admin/something") is None
+
+
+class TestOrgAIMD:
+ def test_on_rate_limited_decreases_rate(self):
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.register_org("org_1")
+ url = "/organizations/org_1/networks"
+ limiter.on_rate_limited(url)
+ bucket = limiter._org_buckets["org_1"]
+ assert bucket.rate == pytest.approx(7.0, abs=0.01)
+
+ def test_on_success_increases_rate(self):
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.register_org("org_1")
+ url = "/organizations/org_1/networks"
+ limiter.on_rate_limited(url)
+ limiter.on_success(url)
+ bucket = limiter._org_buckets["org_1"]
+ assert bucket.rate == pytest.approx(7.2, abs=0.01)
+
+ def test_on_success_caps_at_configured_rate(self):
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.register_org("org_1")
+ url = "/organizations/org_1/networks"
+ for _ in range(100):
+ limiter.on_success(url)
+ bucket = limiter._org_buckets["org_1"]
+ assert bucket.rate == 10.0
+
+ def test_on_rate_limited_unknown_org_decreases_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ limiter.on_rate_limited("/organizations/ghost/networks")
+ assert limiter._global_bucket.rate == pytest.approx(70.0, abs=0.1)
+
+ def test_on_success_unknown_org_nudges_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ limiter._global_bucket.rate = 90.0
+ limiter.on_success("/organizations/ghost/networks")
+ assert limiter._global_bucket.rate == pytest.approx(90.5, abs=0.01)
+
+ def test_on_success_unresolvable_url_nudges_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ limiter._global_bucket.rate = 80.0
+ limiter.on_success("/admin/something")
+ assert limiter._global_bucket.rate == pytest.approx(80.5, abs=0.01)
+
+ def test_on_rate_limited_unresolvable_url_decreases_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ limiter.on_rate_limited("/admin/something")
+ assert limiter._global_bucket.rate == pytest.approx(70.0, abs=0.1)
+
+ def test_on_success_global_caps_at_configured(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ for _ in range(1000):
+ limiter.on_success("/admin/something")
+ assert limiter._global_bucket.rate == 100.0
+
+
+class TestOrgAcquire:
+ def test_acquire_with_org_url(self):
+ limiter = OrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.acquire("/organizations/org_1/networks")
+ assert "org_1" in limiter._org_buckets
+
+ def test_acquire_org_url_deducts_from_both(self):
+ limiter = OrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.acquire("/organizations/org_1/networks")
+ assert limiter._global_bucket._tokens < 100.0
+ assert limiter._org_buckets["org_1"]._tokens < 10.0
+
+ def test_acquire_with_cached_network(self):
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.register_network("N_1", "org_1")
+ limiter.acquire("/networks/N_1/ssids")
+ assert "org_1" in limiter._org_buckets
+
+ def test_acquire_unresolvable_url_uses_global_only(self):
+ limiter = OrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.acquire("/admin/something")
+ assert len(limiter._org_buckets) == 0
+ assert limiter._global_bucket._tokens < 100.0
+
+ def test_acquire_unknown_network_with_resolver(self):
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.set_resolver(lambda id_type, ident: "org_resolved")
+ limiter.acquire("/networks/N_unknown/ssids")
+ assert limiter._network_to_org.get("N_unknown") == "org_resolved"
+
+ def test_acquire_unknown_device_with_resolver(self):
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.set_resolver(lambda id_type, ident: "org_dev")
+ limiter.acquire("/devices/QXYZ-1234-ABCD/clients")
+ assert limiter._serial_to_org.get("QXYZ-1234-ABCD") == "org_dev"
+
+ def test_acquire_resolver_returns_none_uses_global_only(self):
+ limiter = OrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.set_resolver(lambda id_type, ident: None)
+ limiter.acquire("/networks/N_mystery/ssids")
+ assert "N_mystery" not in limiter._network_to_org
+ assert len(limiter._org_buckets) == 0
+
+ def test_acquire_resolver_exception_uses_global_only(self):
+ def bad_resolver(id_type, ident):
+ raise RuntimeError("boom")
+
+ limiter = OrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.set_resolver(bad_resolver)
+ limiter.acquire("/networks/N_err/ssids")
+ assert len(limiter._org_buckets) == 0
+
+ def test_acquire_deduplicates_pending_lookups(self):
+ call_count = 0
+
+ def counting_resolver(id_type, ident):
+ nonlocal call_count
+ call_count += 1
+ return "org_1"
+
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.set_resolver(counting_resolver)
+ limiter._pending_lookups.add("N_dup")
+ limiter.acquire("/networks/N_dup/ssids")
+ assert call_count == 0
+
+
+class TestOrgResolverHydrator:
+ def test_resolver_triggers_hydrator_once(self):
+ hydrated = []
+
+ def mock_hydrator(org_id):
+ hydrated.append(org_id)
+
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.set_resolver(lambda id_type, ident: "org_h1")
+ limiter.set_hydrator(mock_hydrator)
+ limiter.acquire("/networks/N_1/ssids")
+ limiter.acquire("/networks/N_2/ssids")
+ assert hydrated == ["org_h1"]
+
+ def test_hydrator_not_called_without_resolver_result(self):
+ hydrated = []
+
+ def mock_hydrator(org_id):
+ hydrated.append(org_id)
+
+ limiter = OrgRateLimiter(rate=10.0)
+ limiter.set_resolver(lambda id_type, ident: None)
+ limiter.set_hydrator(mock_hydrator)
+ limiter.acquire("/networks/N_nope/ssids")
+ assert hydrated == []
+
+
+class TestOrgMaybeFlush:
+ def test_flush_at_threshold(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = OrgRateLimiter(cache_path=cache_file)
+ limiter._dirty = 50
+ limiter._maybe_flush()
+ assert limiter._dirty == 0
+ assert (tmp_path / "cache.json").exists()
+
+ def test_no_flush_below_threshold(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = OrgRateLimiter(cache_path=cache_file)
+ limiter._dirty = 49
+ limiter._maybe_flush()
+ assert limiter._dirty == 49
+
+
+class TestOrgLogger:
+ def test_log_with_logger(self):
+ logger = MagicMock()
+ limiter = OrgRateLimiter(logger=logger)
+ limiter._log("test message")
+ logger.debug.assert_called_once_with("smart_flow, test message")
+
+ def test_log_without_logger(self):
+ limiter = OrgRateLimiter()
+ limiter._log("no crash")
+
+
+class TestCacheTTL:
+ def test_save_and_load_fresh_cache(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = OrgRateLimiter(cache_path=cache_file)
+ limiter.register_network("N_1", "org_A")
+ limiter.register_device("SERIAL_1", "org_B")
+ limiter.save_cache()
+
+ limiter2 = OrgRateLimiter(cache_path=cache_file)
+ assert limiter2.resolve_org("/networks/N_1/ssids") == "org_A"
+ assert limiter2.resolve_org("/devices/SERIAL_1/clients") == "org_B"
+
+ def test_expired_cache_is_ignored(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = OrgRateLimiter(cache_path=cache_file, cache_ttl=60.0)
+ limiter.register_network("N_1", "org_A")
+ limiter.save_cache()
+
+ with patch("time.time", return_value=time.time() + 120):
+ limiter2 = OrgRateLimiter(cache_path=cache_file, cache_ttl=60.0)
+ assert limiter2.resolve_org("/networks/N_1/ssids") is None
+
+ def test_cache_without_timestamp_is_treated_as_expired(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "networks": [{"id": "N_1", "organization": {"id": "org_A"}}],
+ "devices": [],
+ }
+ )
+ )
+
+ limiter = OrgRateLimiter(cache_path=str(cache_file), cache_ttl=60.0)
+ assert limiter.resolve_org("/networks/N_1/ssids") is None
+
+ def test_none_ttl_disables_expiration(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "networks": [{"id": "N_1", "organization": {"id": "org_A"}}],
+ "devices": [],
+ }
+ )
+ )
+
+ limiter = OrgRateLimiter(cache_path=str(cache_file), cache_ttl=None)
+ assert limiter.resolve_org("/networks/N_1/ssids") == "org_A"
+
+ def test_corrupt_cache_is_ignored(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text("not json{{{")
+
+ limiter = OrgRateLimiter(cache_path=str(cache_file))
+ assert limiter.resolve_org("/networks/N_1/ssids") is None
+
+ def test_cache_fresh_flag(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = OrgRateLimiter(cache_path=cache_file)
+ assert limiter.cache_fresh is False
+ limiter.register_network("N_1", "org_A")
+ limiter.save_cache()
+ limiter2 = OrgRateLimiter(cache_path=cache_file)
+ assert limiter2.cache_fresh is True
+
+ def test_save_without_cache_path_is_noop(self):
+ limiter = OrgRateLimiter()
+ limiter.save_cache()
+
+ def test_load_nonexistent_cache(self, tmp_path):
+ limiter = OrgRateLimiter(cache_path=str(tmp_path / "nope.json"))
+ assert limiter.cache_fresh is False
+
+ def test_cache_with_invalid_saved_at_format(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "saved_at": "invalid-date",
+ "networks": [{"id": "N_1", "organization": {"id": "org_A"}}],
+ "devices": [],
+ }
+ )
+ )
+ limiter = OrgRateLimiter(cache_path=str(cache_file), cache_ttl=60.0)
+ assert limiter.resolve_org("/networks/N_1/ssids") is None
+
+
+class TestLearnFromResponse:
+ def test_learns_org_from_url(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response("/organizations/org_1/networks", [{"id": "N_1"}])
+ assert "org_1" in limiter._org_buckets
+
+ def test_learns_network_from_url(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/networks/N_1/ssids",
+ {"name": "test"},
+ )
+ assert limiter._network_to_org.get("N_1") == "org_1"
+
+ def test_learns_serial_from_url(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/devices/Q2AB-1234-ABCD/clients",
+ {},
+ )
+ assert limiter._serial_to_org.get("Q2AB-1234-ABCD") == "org_1"
+
+ def test_learns_network_id_from_body(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/something",
+ {"networkId": "N_99"},
+ )
+ assert limiter._network_to_org.get("N_99") == "org_1"
+
+ def test_learns_serial_from_body(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/something",
+ {"serial": "QXYZ-0000-1111"},
+ )
+ assert limiter._serial_to_org.get("QXYZ-0000-1111") == "org_1"
+
+ def test_learns_org_from_body_organizationId(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/networks/N_5/ssids",
+ {"organizationId": "org_7", "networkId": "N_5"},
+ )
+ assert limiter._network_to_org.get("N_5") == "org_7"
+
+ def test_learns_org_from_body_organization_dict(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/networks/N_6/clients",
+ {"organization": {"id": "org_8"}, "networkId": "N_6"},
+ )
+ assert limiter._network_to_org.get("N_6") == "org_8"
+
+ def test_learns_network_from_body_network_dict(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/something",
+ {"network": {"id": "N_nested"}},
+ )
+ assert limiter._network_to_org.get("N_nested") == "org_1"
+
+ def test_noop_when_no_org_resolvable(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response("/admin/page", {"foo": "bar"})
+ assert not limiter._network_to_org
+ assert not limiter._serial_to_org
+
+ def test_overwrites_stale_mapping_on_org_change(self):
+ limiter = OrgRateLimiter()
+ limiter.register_network("N_1", "org_original")
+ limiter.learn_from_response(
+ "/organizations/org_new/networks/N_1/ssids",
+ {},
+ )
+ assert limiter._network_to_org["N_1"] == "org_new"
+
+ def test_handles_non_dict_body(self):
+ limiter = OrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/networks",
+ [{"id": "N_1"}, {"id": "N_2"}],
+ )
+ assert "org_1" in limiter._org_buckets
+
+ def test_no_change_does_not_increment_dirty(self):
+ limiter = OrgRateLimiter()
+ limiter.register_network("N_1", "org_1")
+ limiter._dirty = 0
+ limiter.learn_from_response(
+ "/organizations/org_1/networks/N_1/ssids",
+ {},
+ )
+ assert limiter._dirty == 0
+
+ def test_learn_triggers_flush_at_threshold(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = OrgRateLimiter(cache_path=cache_file)
+ limiter._dirty = 49
+ limiter.learn_from_response(
+ "/organizations/org_1/networks/N_new/ssids",
+ {},
+ )
+ assert (tmp_path / "cache.json").exists()
+
+ def test_learn_with_logger_logs_changes(self):
+ logger = MagicMock()
+ limiter = OrgRateLimiter(logger=logger)
+ limiter.learn_from_response(
+ "/organizations/org_1/networks/N_1/ssids",
+ {"serial": "QABC-1111-2222"},
+ )
+ assert logger.debug.call_count >= 1
+
+
+class TestAsyncTokenBucketRateSetter:
+ @pytest.mark.asyncio
+ async def test_rate_property(self):
+ bucket = AsyncTokenBucket(rate=10.0, capacity=10)
+ assert bucket.rate == 10.0
+
+
+class TestAsyncOrgRateLimiter:
+ @pytest.mark.asyncio
+ async def test_resolve_org_from_url(self):
+ limiter = AsyncOrgRateLimiter()
+ assert limiter.resolve_org("/organizations/org_1/networks") == "org_1"
+
+ @pytest.mark.asyncio
+ async def test_resolve_org_via_network_cache(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.register_network("N_1", "org_1")
+ assert limiter.resolve_org("/networks/N_1/ssids") == "org_1"
+
+ @pytest.mark.asyncio
+ async def test_resolve_org_via_device_cache(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.register_device("QABC-1234-5678", "org_2")
+ assert limiter.resolve_org("/devices/QABC-1234-5678/clients") == "org_2"
+
+ @pytest.mark.asyncio
+ async def test_resolve_org_returns_none(self):
+ limiter = AsyncOrgRateLimiter()
+ assert limiter.resolve_org("/admin/page") is None
+
+ @pytest.mark.asyncio
+ async def test_acquire_with_org_url(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ await limiter.acquire("/organizations/org_1/networks")
+ assert "org_1" in limiter._org_buckets
+
+ @pytest.mark.asyncio
+ async def test_acquire_unknown_triggers_background_resolve(self):
+ resolved = []
+
+ async def mock_resolver(id_type, ident):
+ resolved.append((id_type, ident))
+ return "org_bg"
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(mock_resolver)
+ await limiter.acquire("/networks/N_unknown/ssids")
+ await asyncio.sleep(0.05)
+ assert resolved == [("network", "N_unknown")]
+ assert limiter._network_to_org.get("N_unknown") == "org_bg"
+
+ @pytest.mark.asyncio
+ async def test_acquire_unknown_device_triggers_resolve(self):
+ async def mock_resolver(id_type, ident):
+ return "org_dev"
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(mock_resolver)
+ await limiter.acquire("/devices/QABC-0000-1111/uplink")
+ await asyncio.sleep(0.05)
+ assert limiter._serial_to_org.get("QABC-0000-1111") == "org_dev"
+
+ @pytest.mark.asyncio
+ async def test_acquire_no_resolver_uses_global_only(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0, global_rate=100.0)
+ await limiter.acquire("/networks/N_mystery/ssids")
+ assert len(limiter._org_buckets) == 0
+ assert limiter._global_bucket._tokens < 100.0
+
+ @pytest.mark.asyncio
+ async def test_background_resolve_deduplicates(self):
+ call_count = 0
+
+ async def mock_resolver(id_type, ident):
+ nonlocal call_count
+ call_count += 1
+ await asyncio.sleep(0.05)
+ return "org_1"
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(mock_resolver)
+ await limiter.acquire("/networks/N_dup/ssids")
+ await limiter.acquire("/networks/N_dup/ssids")
+ await asyncio.sleep(0.1)
+ assert call_count == 1
+
+ @pytest.mark.asyncio
+ async def test_background_resolve_with_hydrator(self):
+ hydrated = []
+
+ async def mock_resolver(id_type, ident):
+ return "org_h"
+
+ async def mock_hydrator(org_id):
+ hydrated.append(org_id)
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(mock_resolver)
+ limiter.set_hydrator(mock_hydrator)
+ await limiter.acquire("/networks/N_1/ssids")
+ await asyncio.sleep(0.05)
+ assert hydrated == ["org_h"]
+
+ @pytest.mark.asyncio
+ async def test_hydrator_only_called_once_per_org(self):
+ hydrated = []
+
+ async def mock_resolver(id_type, ident):
+ return "org_h"
+
+ async def mock_hydrator(org_id):
+ hydrated.append(org_id)
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(mock_resolver)
+ limiter.set_hydrator(mock_hydrator)
+ await limiter.acquire("/networks/N_1/ssids")
+ await asyncio.sleep(0.05)
+ await limiter.acquire("/networks/N_2/ssids")
+ await asyncio.sleep(0.05)
+ assert hydrated == ["org_h"]
+
+ @pytest.mark.asyncio
+ async def test_resolve_exception_is_swallowed(self):
+ async def bad_resolver(id_type, ident):
+ raise RuntimeError("boom")
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(bad_resolver)
+ await limiter.acquire("/networks/N_err/ssids")
+ await asyncio.sleep(0.05)
+
+ @pytest.mark.asyncio
+ async def test_resolver_returns_none(self):
+ async def none_resolver(id_type, ident):
+ return None
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(none_resolver)
+ await limiter.acquire("/networks/N_nope/ssids")
+ await asyncio.sleep(0.05)
+ assert "N_nope" not in limiter._network_to_org
+
+ @pytest.mark.asyncio
+ async def test_on_rate_limited(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.register_org("org_1")
+ limiter.on_rate_limited("/organizations/org_1/networks")
+ bucket = limiter._org_buckets["org_1"]
+ assert bucket.rate == pytest.approx(7.0, abs=0.01)
+
+ @pytest.mark.asyncio
+ async def test_on_rate_limited_unknown_decreases_global(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.on_rate_limited("/organizations/ghost/x")
+ assert limiter._global_bucket.rate == pytest.approx(70.0, abs=0.1)
+
+ @pytest.mark.asyncio
+ async def test_on_success(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.register_org("org_1")
+ limiter.on_rate_limited("/organizations/org_1/x")
+ limiter.on_success("/organizations/org_1/x")
+ bucket = limiter._org_buckets["org_1"]
+ assert bucket.rate == pytest.approx(7.2, abs=0.01)
+
+ @pytest.mark.asyncio
+ async def test_on_success_caps_at_rate(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.register_org("org_1")
+ for _ in range(100):
+ limiter.on_success("/organizations/org_1/x")
+ bucket = limiter._org_buckets["org_1"]
+ assert bucket.rate == 10.0
+
+ @pytest.mark.asyncio
+ async def test_on_success_unknown_nudges_global(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter._global_bucket.rate = 80.0
+ limiter.on_success("/organizations/ghost/x")
+ assert limiter._global_bucket.rate == pytest.approx(80.5, abs=0.01)
+
+ @pytest.mark.asyncio
+ async def test_register_org(self):
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.register_org("org_new")
+ assert "org_new" in limiter._org_buckets
+
+ @pytest.mark.asyncio
+ async def test_learn_from_response_network(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/networks/N_1/ssids",
+ {"networkId": "N_1"},
+ )
+ assert limiter._network_to_org.get("N_1") == "org_1"
+
+ @pytest.mark.asyncio
+ async def test_learn_from_response_device(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/devices/QABC-1234-5678/clients",
+ {"serial": "QABC-1234-5678"},
+ )
+ assert limiter._serial_to_org.get("QABC-1234-5678") == "org_1"
+
+ @pytest.mark.asyncio
+ async def test_learn_from_response_body_org_id(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.learn_from_response(
+ "/networks/N_5/ssids",
+ {"organizationId": "org_7", "networkId": "N_5"},
+ )
+ assert limiter._network_to_org.get("N_5") == "org_7"
+
+ @pytest.mark.asyncio
+ async def test_learn_from_response_body_org_dict(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.learn_from_response(
+ "/networks/N_6/clients",
+ {"organization": {"id": "org_8"}, "networkId": "N_6"},
+ )
+ assert limiter._network_to_org.get("N_6") == "org_8"
+
+ @pytest.mark.asyncio
+ async def test_learn_from_response_network_dict_in_body(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.learn_from_response(
+ "/organizations/org_1/something",
+ {"network": {"id": "N_nested"}},
+ )
+ assert limiter._network_to_org.get("N_nested") == "org_1"
+
+ @pytest.mark.asyncio
+ async def test_learn_noop_no_org(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.learn_from_response("/admin/x", {"foo": "bar"})
+ assert not limiter._network_to_org
+
+ @pytest.mark.asyncio
+ async def test_learn_no_change_no_dirty(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter.register_network("N_1", "org_1")
+ limiter._dirty = 0
+ limiter.learn_from_response("/organizations/org_1/networks/N_1/ssids", {})
+ assert limiter._dirty == 0
+
+ @pytest.mark.asyncio
+ async def test_learn_logs_changes(self):
+ logger = MagicMock()
+ limiter = AsyncOrgRateLimiter(logger=logger)
+ limiter.learn_from_response(
+ "/organizations/org_1/networks/N_1/ssids",
+ {"serial": "QABC-0000-1111"},
+ )
+ assert logger.debug.call_count >= 1
+
+ @pytest.mark.asyncio
+ async def test_maybe_flush_at_threshold(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file)
+ limiter._dirty = 50
+ limiter._maybe_flush()
+ await asyncio.sleep(0.05)
+ assert (tmp_path / "cache.json").exists()
+
+ @pytest.mark.asyncio
+ async def test_maybe_flush_skips_if_task_running(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file)
+ limiter._dirty = 50
+ limiter._flush_task = asyncio.ensure_future(asyncio.sleep(1.0))
+ limiter._maybe_flush()
+ assert limiter._dirty == 50
+ limiter._flush_task.cancel()
+ try:
+ await limiter._flush_task
+ except asyncio.CancelledError:
+ pass
+
+ @pytest.mark.asyncio
+ async def test_log_with_logger(self):
+ logger = MagicMock()
+ limiter = AsyncOrgRateLimiter(logger=logger)
+ limiter._log("hello")
+ logger.debug.assert_called_with("smart_flow, hello")
+
+ @pytest.mark.asyncio
+ async def test_log_without_logger(self):
+ limiter = AsyncOrgRateLimiter()
+ limiter._log("no crash")
+
+ @pytest.mark.asyncio
+ async def test_cache_fresh_property(self):
+ limiter = AsyncOrgRateLimiter()
+ assert limiter.cache_fresh is False
+
+
+class TestAsyncCacheTTL:
+ @pytest.mark.asyncio
+ async def test_save_and_load_fresh_cache(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file)
+ limiter.register_network("N_1", "org_A")
+ await limiter.save_cache()
+
+ limiter2 = AsyncOrgRateLimiter(cache_path=cache_file)
+ assert limiter2.resolve_org("/networks/N_1/ssids") == "org_A"
+
+ @pytest.mark.asyncio
+ async def test_expired_cache_is_ignored(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file, cache_ttl=60.0)
+ limiter.register_network("N_1", "org_A")
+ await limiter.save_cache()
+
+ with patch("time.time", return_value=time.time() + 120):
+ limiter2 = AsyncOrgRateLimiter(cache_path=cache_file, cache_ttl=60.0)
+ assert limiter2.resolve_org("/networks/N_1/ssids") is None
+
+ @pytest.mark.asyncio
+ async def test_save_without_cache_path(self):
+ limiter = AsyncOrgRateLimiter()
+ await limiter.save_cache()
+
+ @pytest.mark.asyncio
+ async def test_none_ttl_disables_expiration(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "networks": [{"id": "N_1", "organization": {"id": "org_A"}}],
+ "devices": [],
+ }
+ )
+ )
+ limiter = AsyncOrgRateLimiter(cache_path=str(cache_file), cache_ttl=None)
+ assert limiter.resolve_org("/networks/N_1/ssids") == "org_A"
+
+ @pytest.mark.asyncio
+ async def test_corrupt_cache_ignored(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text("not json{{{")
+ limiter = AsyncOrgRateLimiter(cache_path=str(cache_file))
+ assert limiter.cache_fresh is False
+
+ @pytest.mark.asyncio
+ async def test_cache_without_timestamp_expired(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "networks": [{"id": "N_1", "organization": {"id": "org_A"}}],
+ "devices": [],
+ }
+ )
+ )
+ limiter = AsyncOrgRateLimiter(cache_path=str(cache_file), cache_ttl=60.0)
+ assert limiter.resolve_org("/networks/N_1/ssids") is None
+
+ @pytest.mark.asyncio
+ async def test_nonexistent_cache_path(self, tmp_path):
+ limiter = AsyncOrgRateLimiter(cache_path=str(tmp_path / "nope.json"))
+ assert limiter.cache_fresh is False
+
+ @pytest.mark.asyncio
+ async def test_invalid_saved_at_treated_as_expired(self, tmp_path):
+ cache_file = tmp_path / "cache.json"
+ cache_file.write_text(
+ json.dumps(
+ {
+ "saved_at": "bad-format",
+ "networks": [{"id": "N_1", "organization": {"id": "org_A"}}],
+ "devices": [],
+ }
+ )
+ )
+ limiter = AsyncOrgRateLimiter(cache_path=str(cache_file), cache_ttl=60.0)
+ assert limiter.resolve_org("/networks/N_1/ssids") is None
+
+
+class TestSyncTokenBucketThreadSafety:
+ """Fix #11: TokenBucket must have a real lock and not over-spend."""
+
+ def test_lock_exists_and_is_a_lock(self):
+ bucket = TokenBucket(rate=10.0, capacity=10)
+ # threading.Lock() returns a lock object exposing acquire/release.
+ assert hasattr(bucket, "_lock")
+ assert hasattr(bucket._lock, "acquire")
+ assert hasattr(bucket._lock, "release")
+
+ def test_concurrent_threads_do_not_overspend(self):
+ import threading
+
+ # Capacity covers the burst exactly; with a real lock, total wall time
+ # for capacity-many concurrent acquires stays near zero (no double-spend
+ # forcing a sleep). Without a lock, the read-modify-write races.
+ bucket = TokenBucket(rate=10.0, capacity=20)
+ barrier = threading.Barrier(20)
+
+ def worker():
+ barrier.wait()
+ bucket.acquire()
+
+ threads = [threading.Thread(target=worker) for _ in range(20)]
+ start = time.monotonic()
+ for t in threads:
+ t.start()
+ for t in threads:
+ t.join()
+ elapsed = time.monotonic() - start
+
+ # 20 acquires against capacity 20 should all be served from the bucket
+ # without anyone sleeping for a refill.
+ assert elapsed < 0.5
+ # Exactly 20 tokens were spent. With a real lock the deficit is bounded
+ # (~0, give or take tiny refill); without one, racing read-modify-writes
+ # would let tokens stay well above 0 (double-spend) or be inconsistent.
+ assert -0.05 <= bucket._tokens <= 0.05
+
+ def test_aggregate_rate_not_exceeded_when_drained(self):
+ # Drain the bucket, then 5 concurrent acquires must take ~ (5 / rate).
+ import threading
+
+ bucket = TokenBucket(rate=20.0, capacity=1)
+ bucket.acquire() # drain the single token
+
+ def worker():
+ bucket.acquire()
+
+ threads = [threading.Thread(target=worker) for _ in range(5)]
+ start = time.monotonic()
+ for t in threads:
+ t.start()
+ for t in threads:
+ t.join()
+ elapsed = time.monotonic() - start
+
+ # 5 tokens at 20/s with a drained bucket => >= ~0.20s minimum.
+ assert elapsed >= 0.20 - 0.03
+
+
+class TestAsyncTokenBucketConcurrency:
+ """Fix #10: acquire() must not serialize all coroutines behind one sleeper."""
+
+ @pytest.mark.asyncio
+ async def test_concurrent_acquirers_not_serialized(self):
+ # Drained bucket, 5 concurrent acquirers. If the lock were held across
+ # the sleep they would queue serially (~5 * per-token wait). With the
+ # reservation fix they each sleep concurrently against a shared deficit.
+ bucket = AsyncTokenBucket(rate=10.0, capacity=1)
+ await bucket.acquire() # drain
+
+ start = asyncio.get_event_loop().time()
+ await asyncio.gather(*(bucket.acquire() for _ in range(5)))
+ elapsed = asyncio.get_event_loop().time() - start
+
+ # Serialized-across-sleep behavior would be ~5 * 0.1 = 0.5s+ stacking.
+ # Concurrent reservation: the last reservation waits ~5/10 = 0.5s, but
+ # they overlap so total is bounded by the max single wait (~0.5s) and
+ # crucially is NOT additive blow-up. Assert it's not pathologically
+ # serialized (which would be each waiting then the next computing fresh
+ # after the previous slept -> well over the deficit window).
+ assert elapsed < 1.0
+
+ @pytest.mark.asyncio
+ async def test_aggregate_rate_not_exceeded(self):
+ # Across many acquires the steady-state dispatch must stay <= rate.
+ rate = 50.0
+ n = 25
+ bucket = AsyncTokenBucket(rate=rate, capacity=1)
+ await bucket.acquire() # drain
+
+ start = asyncio.get_event_loop().time()
+ await asyncio.gather(*(bucket.acquire() for _ in range(n)))
+ elapsed = asyncio.get_event_loop().time() - start
+
+ # n tokens at `rate`/s from a drained bucket cannot complete faster than
+ # n/rate seconds without exceeding the configured rate.
+ min_expected = n / rate
+ assert elapsed >= min_expected - 0.05
+
+
+class TestAsyncBgTaskRetention:
+ """Fix #6: background resolve tasks are held then discarded on completion."""
+
+ @pytest.mark.asyncio
+ async def test_bg_task_retained_then_discarded(self):
+ started = asyncio.Event()
+ release = asyncio.Event()
+
+ async def slow_resolver(id_type, ident):
+ started.set()
+ await release.wait()
+ return "org_bg"
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(slow_resolver)
+ await limiter.acquire("/networks/N_held/ssids")
+ await started.wait()
+
+ # While in flight, the limiter holds a strong ref.
+ assert len(limiter._bg_tasks) == 1
+
+ release.set()
+ await asyncio.sleep(0.02)
+
+ # Done-callback discards it.
+ assert len(limiter._bg_tasks) == 0
+ assert limiter._network_to_org.get("N_held") == "org_bg"
+
+ @pytest.mark.asyncio
+ async def test_resolver_exception_logged_not_swallowed(self):
+ logger = MagicMock()
+
+ async def bad_resolver(id_type, ident):
+ raise RuntimeError("boom")
+
+ limiter = AsyncOrgRateLimiter(rate=10.0, logger=logger)
+ limiter.set_resolver(bad_resolver)
+ await limiter.acquire("/networks/N_err/ssids")
+ await asyncio.sleep(0.02)
+
+ # The bare except now logs at debug instead of fully swallowing.
+ logged = " ".join(str(c) for c in logger.debug.call_args_list)
+ assert "failed" in logged
+ assert len(limiter._bg_tasks) == 0
+
+
+class TestAsyncFlushDirtyOnFailure:
+ """Fix #8: dirty count must survive a failed save."""
+
+ @pytest.mark.asyncio
+ async def test_dirty_not_zeroed_when_save_raises(self):
+ limiter = AsyncOrgRateLimiter(cache_path="ignored")
+ limiter._dirty = 50
+
+ async def failing_save():
+ raise OSError("disk full")
+
+ with patch.object(limiter, "save_cache", side_effect=failing_save):
+ limiter._maybe_flush()
+ await asyncio.sleep(0.02)
+
+ # Save failed -> dirty must be retained, not lost.
+ assert limiter._dirty == 50
+
+ @pytest.mark.asyncio
+ async def test_dirty_zeroed_on_successful_save(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file)
+ limiter.register_network("N_1", "org_A")
+ limiter._dirty = 50
+ limiter._maybe_flush()
+ # Wait for the flush task and its done-callback to run.
+ if limiter._flush_task:
+ await limiter._flush_task
+ await asyncio.sleep(0.02)
+ assert limiter._dirty == 0
+
+
+class TestUnresolvedRateLimitGlobalProtection:
+ """Fix #13: a 429 on an unresolved network/device must not lower global."""
+
+ def test_sync_unresolved_network_does_not_lower_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ before = limiter._global_bucket.rate
+ limiter.on_rate_limited("/networks/N_unknown/ssids")
+ assert limiter._global_bucket.rate == before
+
+ def test_sync_unresolved_device_does_not_lower_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ before = limiter._global_bucket.rate
+ limiter.on_rate_limited("/devices/Q2AB-CDE4-FGHI/clients")
+ assert limiter._global_bucket.rate == before
+
+ def test_sync_explicit_org_url_still_lowers_global(self):
+ # An explicit, unbucketed org URL is a known org -> existing behavior.
+ limiter = OrgRateLimiter(global_rate=100.0)
+ limiter.on_rate_limited("/organizations/ghost/networks")
+ assert limiter._global_bucket.rate == pytest.approx(70.0, abs=0.1)
+
+ def test_sync_truly_unscoped_url_still_lowers_global(self):
+ limiter = OrgRateLimiter(global_rate=100.0)
+ limiter.on_rate_limited("/admin/something")
+ assert limiter._global_bucket.rate == pytest.approx(70.0, abs=0.1)
+
+ def test_sync_resolved_network_penalizes_org_not_global(self):
+ limiter = OrgRateLimiter(rate=10.0, global_rate=100.0)
+ limiter.register_network("N_known", "org_k")
+ limiter.register_org("org_k")
+ global_before = limiter._global_bucket.rate
+ limiter.on_rate_limited("/networks/N_known/ssids")
+ assert limiter._org_buckets["org_k"].rate == pytest.approx(7.0, abs=0.01)
+ assert limiter._global_bucket.rate == global_before
+
+ @pytest.mark.asyncio
+ async def test_async_unresolved_network_does_not_lower_global(self):
+ limiter = AsyncOrgRateLimiter(global_rate=100.0)
+ before = limiter._global_bucket.rate
+ limiter.on_rate_limited("/networks/N_unknown/ssids")
+ assert limiter._global_bucket.rate == before
+
+ @pytest.mark.asyncio
+ async def test_async_explicit_org_url_still_lowers_global(self):
+ limiter = AsyncOrgRateLimiter(global_rate=100.0)
+ limiter.on_rate_limited("/organizations/ghost/x")
+ assert limiter._global_bucket.rate == pytest.approx(70.0, abs=0.1)
+
+
+class TestAsyncShutdown:
+ """Fix #7-SUPPORT: shutdown() drains bg tasks, flush, and saves."""
+
+ @pytest.mark.asyncio
+ async def test_shutdown_awaits_pending_bg_tasks(self, tmp_path):
+ release = asyncio.Event()
+ finished = []
+
+ async def slow_resolver(id_type, ident):
+ await release.wait()
+ finished.append(ident)
+ return "org_s"
+
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(rate=10.0, cache_path=cache_file)
+ limiter.set_resolver(slow_resolver)
+ await limiter.acquire("/networks/N_shutdown/ssids")
+ assert len(limiter._bg_tasks) == 1
+
+ # Release the resolver, then shutdown should await it to completion.
+ release.set()
+ await limiter.shutdown()
+
+ assert finished == ["N_shutdown"]
+ assert len(limiter._bg_tasks) == 0
+ assert limiter._network_to_org.get("N_shutdown") == "org_s"
+ # Final save happened.
+ assert (tmp_path / "cache.json").exists()
+
+ @pytest.mark.asyncio
+ async def test_shutdown_idempotent_with_no_work(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file)
+ # No bg tasks, no flush task -> safe to call, does a final save.
+ await limiter.shutdown()
+ await limiter.shutdown()
+ assert (tmp_path / "cache.json").exists()
+
+ @pytest.mark.asyncio
+ async def test_shutdown_awaits_pending_flush(self, tmp_path):
+ cache_file = str(tmp_path / "cache.json")
+ limiter = AsyncOrgRateLimiter(cache_path=cache_file)
+ limiter.register_network("N_1", "org_A")
+ limiter._dirty = 50
+ limiter._maybe_flush()
+ assert limiter._flush_task is not None
+ await limiter.shutdown()
+ # Flush completed without error -> dirty zeroed.
+ assert limiter._dirty == 0
+
+
+class TestAsyncBackgroundResolveEdgeCases:
+ @pytest.mark.asyncio
+ async def test_unrecognized_url_no_resolve(self):
+ called = []
+
+ async def mock_resolver(id_type, ident):
+ called.append(ident)
+ return "org_1"
+
+ limiter = AsyncOrgRateLimiter(rate=10.0)
+ limiter.set_resolver(mock_resolver)
+ await limiter.acquire("/admin/something")
+ await asyncio.sleep(0.05)
+ assert called == []
diff --git a/uv.lock b/uv.lock
index 4fdccfd6..1652dd30 100644
--- a/uv.lock
+++ b/uv.lock
@@ -3,152 +3,16 @@ revision = 3
requires-python = ">=3.11"
[[package]]
-name = "aiohappyeyeballs"
-version = "2.6.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
-]
-
-[[package]]
-name = "aiohttp"
-version = "3.14.1"
+name = "anyio"
+version = "4.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "aiohappyeyeballs" },
- { name = "aiosignal" },
- { name = "attrs" },
- { name = "frozenlist" },
- { name = "multidict" },
- { name = "propcache" },
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
- { name = "yarl" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/82/78/8ea7308cac6934de8c74a14f3d5f65d1c89287426688be79538d0e5c013d/aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035", size = 7955794, upload-time = "2026-06-07T21:09:35.529Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/26/dd/bf526e6f0a1120dd6f2df2e97bacfe4d358f13d17a0ff5847301a1375a51/aiohttp-3.14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa00140699487bd435fde4342d85c94cb256b7cd3a5b9c3396c67f19922afda2", size = 765225, upload-time = "2026-06-07T21:06:07.957Z" },
- { url = "https://files.pythonhosted.org/packages/8f/e1/a2872aa55495a70f61310d411541c6ee23812d9a884e000c716e1bc3edbf/aiohttp-3.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c1af67559445498b502030c35c59db59966f47041ca9de5b4e707f86bd10b5f", size = 518743, upload-time = "2026-06-07T21:06:09.749Z" },
- { url = "https://files.pythonhosted.org/packages/5b/e7/c60c7b209e509cc787de3cea0550a518538cfc08003e1c1e14c1c63fff71/aiohttp-3.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d44ec478e713ee7f29b439f7eb8dc2b9d4079e11ae114d2c2ac3d5daf30516c8", size = 514139, upload-time = "2026-06-07T21:06:11.26Z" },
- { url = "https://files.pythonhosted.org/packages/5b/8d/614ace2f579702c9840ab1e1447fd8509e35b0b904f7196418fa2f57b25d/aiohttp-3.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d3b1a184a9a8f548a6b73f1e26b96b052193e4b3175ed7342aaf1151a1f00a04", size = 1784088, upload-time = "2026-06-07T21:06:12.887Z" },
- { url = "https://files.pythonhosted.org/packages/49/e0/726e90f99542bf292f81a96a12cc4847deb86f3ccf62c6f4014a201f4d33/aiohttp-3.14.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5f2504bc0322437c9a1ff6d3333ca56c7477b727c995f036b976ae17b98372c8", size = 1737835, upload-time = "2026-06-07T21:06:14.564Z" },
- { url = "https://files.pythonhosted.org/packages/0b/4b/d176d5c4db9d33dacf0543102ea59503bc1d528af4cfd0b719949ca49389/aiohttp-3.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73f05ea02013e02512c3bf42714f1208c57168c779cc6fe23516e4543089d0a6", size = 1842801, upload-time = "2026-06-07T21:06:16.228Z" },
- { url = "https://files.pythonhosted.org/packages/dc/d6/5a99b563690ea0cbed912ae94a2ce33993a5709a651a3a4fe761e7dd973a/aiohttp-3.14.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:797457503c2d426bee06eef808d07b31ede30b65e054444e7de64cad0061b7af", size = 1929992, upload-time = "2026-06-07T21:06:17.947Z" },
- { url = "https://files.pythonhosted.org/packages/76/7f/a987b14a3859094b3cea3f4825219c3e5536242564af6e3f9c2f6c994eb2/aiohttp-3.14.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b821a1f7dedf7e37450654e620038ac3b2e81e8fa6ea269337e97101978ec730", size = 1786989, upload-time = "2026-06-07T21:06:19.677Z" },
- { url = "https://files.pythonhosted.org/packages/f1/1a/420e5c85a3e73349372ed22ce0b6af86bfa6ce16a4b20a64a2e94608c781/aiohttp-3.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4cd96b5ba05d67ed0cf00b5b405c8cd99586d8e3481e8ee0a831057591af7621", size = 1640129, upload-time = "2026-06-07T21:06:22.558Z" },
- { url = "https://files.pythonhosted.org/packages/a7/80/18a592ed3be0a402cc03670bd72ee1f8563ddbe1d8d5542dbf868f274136/aiohttp-3.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d459b98a932296c6f0e94f87511a0b1b90a8a02c30a50e60a297619cd5a58ee", size = 1756576, upload-time = "2026-06-07T21:06:24.8Z" },
- { url = "https://files.pythonhosted.org/packages/ec/0b/8b3d5713373858ff71a617daf6e3b0e81ad63e79d09a3cf2f6b6b983939c/aiohttp-3.14.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:764457a7be60825fb770a644852ff717bcbb5042f189f2bd16df61a81b3f6573", size = 1754668, upload-time = "2026-06-07T21:06:26.528Z" },
- { url = "https://files.pythonhosted.org/packages/9f/49/fd564575cf225821d7ba5a117cb8bc27213d8a7e1811162afb43ae077039/aiohttp-3.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f7a16ef45b081454ef844502d87a848876c490c4cb5c650c230f6ec79ed2c1e7", size = 1817019, upload-time = "2026-06-07T21:06:28.297Z" },
- { url = "https://files.pythonhosted.org/packages/ed/1b/e850c9ae6fc91356552ae668bb6c51e93fa29c8aef13398a10b56678557f/aiohttp-3.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2fbc3ed048b3475b9f0cbcb9978e9d2d3511acd91ead203af26ed9f0056004cf", size = 1631638, upload-time = "2026-06-07T21:06:30.242Z" },
- { url = "https://files.pythonhosted.org/packages/eb/94/3c337ba72451a89806ace6f75bddc92bafc5b8d53d90115a512858024b63/aiohttp-3.14.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bedb0cd073cc2dc035e30aeb99444389d3cd2113afe4ef9fcd23d439f5bade85", size = 1835660, upload-time = "2026-06-07T21:06:31.943Z" },
- { url = "https://files.pythonhosted.org/packages/2b/9c/9c18cf367a0498212d9ba7daf990b504a5e8ae064cda4b504e2647c89c03/aiohttp-3.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6feea921016eb3d4e04d65fc4e9ca402d1a3801f562aef94989f54694917af3", size = 1775698, upload-time = "2026-06-07T21:06:33.72Z" },
- { url = "https://files.pythonhosted.org/packages/b5/63/a251a9d2a6cb45065b2ddc0bde2b3dd10108740a9a42f632c66405a761a2/aiohttp-3.14.1-cp311-cp311-win32.whl", hash = "sha256:313701e488100074ce99850404ee36e741abf6330179fec908a1944ecf570126", size = 458386, upload-time = "2026-06-07T21:06:35.279Z" },
- { url = "https://files.pythonhosted.org/packages/17/ca/69274c51dcd6e8947d77b2806cf47a4a15f2c846e2cbeb1882547d3da283/aiohttp-3.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:03ab4530fdcb3a543a122ba4b65ac9919da9fe9f78a03d328a6e38ff962f7aa5", size = 483406, upload-time = "2026-06-07T21:06:36.824Z" },
- { url = "https://files.pythonhosted.org/packages/2c/8a/c25904f77690c3688ec140f87591ef11a0cfe36bf3d5c0f1f38056fb62b3/aiohttp-3.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:486f7d16ed54c39c2cbd7ca71fd8ba2b8bb7860df65bd7b6ed640bab96a38a8b", size = 452987, upload-time = "2026-06-07T21:06:38.371Z" },
- { url = "https://files.pythonhosted.org/packages/1d/21/151624b51cd92553d95424daf4bf19f19ce9be9002d19253e7e7ce67197b/aiohttp-3.14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480", size = 757402, upload-time = "2026-06-07T21:06:40.311Z" },
- { url = "https://files.pythonhosted.org/packages/c2/82/280619e0bd7bf2454987e19282616e84762255dd9c8468f62382e8c191f1/aiohttp-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d", size = 512310, upload-time = "2026-06-07T21:06:42.207Z" },
- { url = "https://files.pythonhosted.org/packages/55/b2/2aac325583aaa1353045f96dffa586d8a34e8322e14a7ba49cffeb103ab4/aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2", size = 512448, upload-time = "2026-06-07T21:06:43.813Z" },
- { url = "https://files.pythonhosted.org/packages/8a/72/a60607cb849faa8af8a356c9329ea2eb6f395d49e82cc82ccba1fd8deb8f/aiohttp-3.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2", size = 1766854, upload-time = "2026-06-07T21:06:45.391Z" },
- { url = "https://files.pythonhosted.org/packages/b5/d3/d9fe1c9ec7557ab4d0d82bebaa728c6418f0b93295ec2f4ab015f7710cc7/aiohttp-3.14.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a", size = 1740884, upload-time = "2026-06-07T21:06:47.413Z" },
- { url = "https://files.pythonhosted.org/packages/c1/dc/f2cecfaf9337ba3e63f181500814ff502aa3d00d9c7ec93a9d23d10a27b2/aiohttp-3.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264", size = 1810034, upload-time = "2026-06-07T21:06:50.165Z" },
- { url = "https://files.pythonhosted.org/packages/66/d7/2ff65c5e65c0d7476daf7e15c032e0805e36811185b9623e3238ad6c763e/aiohttp-3.14.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842", size = 1904054, upload-time = "2026-06-07T21:06:52.035Z" },
- { url = "https://files.pythonhosted.org/packages/20/9c/d445818389df371f56d141d881153ba23183c4735a03f7356ffb43f7757d/aiohttp-3.14.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c", size = 1790278, upload-time = "2026-06-07T21:06:54.049Z" },
- { url = "https://files.pythonhosted.org/packages/4d/aa/bf04cb4d865fc6101c2229a294ad744973b72e513fdc5a6b791e6983d72a/aiohttp-3.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95", size = 1591795, upload-time = "2026-06-07T21:06:55.911Z" },
- { url = "https://files.pythonhosted.org/packages/dc/b4/4dac0038960427ba832f6609dfb4ea5437d7fd80c72001b9e48f834f428b/aiohttp-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199", size = 1728397, upload-time = "2026-06-07T21:06:57.777Z" },
- { url = "https://files.pythonhosted.org/packages/2b/f9/7cd4e8ad7aa3b75f17d56bb5498dd604a93d4e6eece822ba0568c413fff0/aiohttp-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817", size = 1766504, upload-time = "2026-06-07T21:07:00.009Z" },
- { url = "https://files.pythonhosted.org/packages/f9/df/fc01d9fcad0f73fed3f3d361f1f94f975947b50dff82919f6dc2bf4316cc/aiohttp-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a", size = 1777806, upload-time = "2026-06-07T21:07:02.064Z" },
- { url = "https://files.pythonhosted.org/packages/41/09/47e2d090bddcc8fb4ccb4c314aadc32d7c5d9bb55f50f6ad1c92fc15d501/aiohttp-3.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4", size = 1580707, upload-time = "2026-06-07T21:07:03.942Z" },
- { url = "https://files.pythonhosted.org/packages/3d/36/f1a4ce904ae0b6930cfe9afc96d0896f7ec1a620c400405d63783bb95a9c/aiohttp-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087", size = 1798121, upload-time = "2026-06-07T21:07:05.987Z" },
- { url = "https://files.pythonhosted.org/packages/70/0a/e0075ce9ca0279ee1d4f0c0b85f54fea02ebc83c3007651a72bece658fec/aiohttp-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3", size = 1767580, upload-time = "2026-06-07T21:07:07.873Z" },
- { url = "https://files.pythonhosted.org/packages/3e/61/a0c0a8f327a9c52095cdd8e312391b00d3ed64ab6c72bb5c33d8ec251cf7/aiohttp-3.14.1-cp312-cp312-win32.whl", hash = "sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4", size = 452771, upload-time = "2026-06-07T21:07:09.669Z" },
- { url = "https://files.pythonhosted.org/packages/df/d9/ea367c75f16ac9c6cdc8febb25e8318fa21a2b1bc8d6514d4b2d890bface/aiohttp-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271", size = 479873, upload-time = "2026-06-07T21:07:11.538Z" },
- { url = "https://files.pythonhosted.org/packages/03/64/8d96784a7851156db8a4c6c3f6f91042fdf39fb15a4cc38c8b3c14833c45/aiohttp-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847", size = 448073, upload-time = "2026-06-07T21:07:13.637Z" },
- { url = "https://files.pythonhosted.org/packages/bc/97/bd137012dd97e1649162b099135a80e1fd59aaa807b2430fc448d1029aff/aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178", size = 506882, upload-time = "2026-06-07T21:07:15.501Z" },
- { url = "https://files.pythonhosted.org/packages/ef/79/e5cc690e9d922a66887ceeaca53a8ffd5a7b0be3816142b7abc433742d89/aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf", size = 515270, upload-time = "2026-06-07T21:07:17.53Z" },
- { url = "https://files.pythonhosted.org/packages/fe/22/a73ccbf9dbd6e26dda0b24d5fd5db7da92ee3383a79f47677ffb834c5c5b/aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd", size = 485841, upload-time = "2026-06-07T21:07:19.555Z" },
- { url = "https://files.pythonhosted.org/packages/3b/b9/57ed8eaf596321c2ad747bd480fb1700dbd7177c60dfc9e4c187f629662e/aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe", size = 492088, upload-time = "2026-06-07T21:07:21.581Z" },
- { url = "https://files.pythonhosted.org/packages/78/c0/5ebe5270a7c140d7c6f79dcb018640225f14d406c149e4eec04a7d82fe71/aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4", size = 501564, upload-time = "2026-06-07T21:07:23.388Z" },
- { url = "https://files.pythonhosted.org/packages/75/7f/8cdaa24fc7983865e0915153b96a9ac5bcdd3548d64c5a27d17cecccad2d/aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876", size = 751998, upload-time = "2026-06-07T21:07:25.046Z" },
- { url = "https://files.pythonhosted.org/packages/b2/f4/c4227aacfacc5cb0cc2d119b65301d177912a6842cd64e120c47af76064f/aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da", size = 510918, upload-time = "2026-06-07T21:07:27.28Z" },
- { url = "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6", size = 508657, upload-time = "2026-06-07T21:07:29.252Z" },
- { url = "https://files.pythonhosted.org/packages/e8/ed/3c0fb5c500fdd8e7ebc10d1889c04384fffa1a9163eac1356088ca9da1b1/aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96", size = 1757907, upload-time = "2026-06-07T21:07:31.03Z" },
- { url = "https://files.pythonhosted.org/packages/0b/ab/d4c924d9bd5be3050c226612413ce68cb54c70d2c31b661bfc8d9a5b6a70/aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f", size = 1737565, upload-time = "2026-06-07T21:07:33.031Z" },
- { url = "https://files.pythonhosted.org/packages/19/2a/37326821ff779084020cdc33224d20b19f42f4183a500ff92022a739eda7/aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296", size = 1799018, upload-time = "2026-06-07T21:07:35.003Z" },
- { url = "https://files.pythonhosted.org/packages/b3/4f/6e947ba73e4ce09070761c05ed3a8ceb7c21f5e46798671d8b2aac0e4626/aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa", size = 1894416, upload-time = "2026-06-07T21:07:36.956Z" },
- { url = "https://files.pythonhosted.org/packages/9d/6e/dbf1d0625dc711fb2851f4f3c3055c39ed58bae92082d8c627dbe6013736/aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451", size = 1783881, upload-time = "2026-06-07T21:07:39.063Z" },
- { url = "https://files.pythonhosted.org/packages/44/c2/5e25098a67268ed369483ae7d1a58bd0a13d03aab860d2a0e4a6eb25b046/aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c", size = 1587572, upload-time = "2026-06-07T21:07:41.058Z" },
- { url = "https://files.pythonhosted.org/packages/2a/bd/cf9cee17e140f942a3de73e658a543aa8fbf35a5fc67a9d2538d52d77f0b/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca", size = 1722137, upload-time = "2026-06-07T21:07:43.014Z" },
- { url = "https://files.pythonhosted.org/packages/89/6d/5684f8c59045c96f81a18cefbc1fbbd79d25b88f1c622f2a5c5c08fcb632/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09", size = 1755953, upload-time = "2026-06-07T21:07:45.933Z" },
- { url = "https://files.pythonhosted.org/packages/a8/40/35caf3170f8359760740a7d9aa0fff2e344bef98e1d1186f5a0f6dec17e6/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397", size = 1766479, upload-time = "2026-06-07T21:07:48.047Z" },
- { url = "https://files.pythonhosted.org/packages/6d/a1/b0c61e7a137f0d81de49a82023a6df73c3c16d6fefb0f8e4a93d21639002/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080", size = 1580077, upload-time = "2026-06-07T21:07:50.069Z" },
- { url = "https://files.pythonhosted.org/packages/0b/41/194ea4623693009fcefebef7aef63c141754f153e9cd0d39d3b9e36c175c/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345", size = 1791688, upload-time = "2026-06-07T21:07:52.106Z" },
- { url = "https://files.pythonhosted.org/packages/ba/45/4de841f005cfe1fd63e2a2fe011262c515e2a62aa6994b15947e7d717ac9/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588", size = 1761094, upload-time = "2026-06-07T21:07:54.113Z" },
- { url = "https://files.pythonhosted.org/packages/e4/ae/dbce10533d3896d544d5053939ed75b7dc31a1b0973d959b1b5ae21028d6/aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780", size = 452662, upload-time = "2026-06-07T21:07:56.06Z" },
- { url = "https://files.pythonhosted.org/packages/7b/d9/0bf1a19362c32f06229da5e7ddfcec91f93474d6307f7a2d3135e9c674dc/aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a", size = 479748, upload-time = "2026-06-07T21:07:58.319Z" },
- { url = "https://files.pythonhosted.org/packages/22/0a/62e7232dc9484fbec112ceb32efb6a624cc7994ec6e2b019286f17c4e8f2/aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8", size = 447723, upload-time = "2026-06-07T21:08:00.154Z" },
- { url = "https://files.pythonhosted.org/packages/c4/a1/5fafa04e1ca91ddb47608699d60649c1c6db3cf41c99e78fc4056f9513db/aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15", size = 508531, upload-time = "2026-06-07T21:08:02.093Z" },
- { url = "https://files.pythonhosted.org/packages/fa/2e/bfa02f699d87ffc86d5959270b28f1cb410add3ccaced8ed2e0b8a5238fc/aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8", size = 514718, upload-time = "2026-06-07T21:08:04.476Z" },
- { url = "https://files.pythonhosted.org/packages/85/a5/9594ad6289eebbc97d167c44213d557807f90e59115caad24de21ad2c3b1/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3", size = 487918, upload-time = "2026-06-07T21:08:06.377Z" },
- { url = "https://files.pythonhosted.org/packages/b4/61/16a32c36c3c49edec122a3dc811f2057df2f94d3b14aa107c8017d981618/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba", size = 494014, upload-time = "2026-06-07T21:08:08.263Z" },
- { url = "https://files.pythonhosted.org/packages/9b/89/3ebcf96ed99c05bec9c434aaac6963fd3cbab4a786ae739908a144d9ce44/aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397", size = 502398, upload-time = "2026-06-07T21:08:10.244Z" },
- { url = "https://files.pythonhosted.org/packages/fd/3d/b74870a0c2d40c355928cd5b96c7a11fa821b8a40fc41365e64479b151fb/aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448", size = 758018, upload-time = "2026-06-07T21:08:12.447Z" },
- { url = "https://files.pythonhosted.org/packages/d3/66/f42f5c984d99e49c6cff5f26f590750f2e2f7ef1fcfb99966ab5be1b632e/aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004", size = 512462, upload-time = "2026-06-07T21:08:14.624Z" },
- { url = "https://files.pythonhosted.org/packages/e9/a7/248e1aebe0c7810b0271e021a0f2a5eb6e78a051885b3c9df49f42a5802d/aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983", size = 512824, upload-time = "2026-06-07T21:08:16.572Z" },
- { url = "https://files.pythonhosted.org/packages/26/97/2aa0e5ba0727dc3bd5aaebb7ccbc510f7dfb7fb961ec87497cd496635ab1/aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe", size = 1749898, upload-time = "2026-06-07T21:08:18.635Z" },
- { url = "https://files.pythonhosted.org/packages/00/8d/e97f6c96c891d457c8479d92a514ba194d0412f981d72c70341ee18488ed/aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333", size = 1710114, upload-time = "2026-06-07T21:08:20.892Z" },
- { url = "https://files.pythonhosted.org/packages/6f/e6/aa8d7e863048c8fceb5cd6ce74017311cec3ead07847387e12265fb4444e/aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0", size = 1802541, upload-time = "2026-06-07T21:08:23.044Z" },
- { url = "https://files.pythonhosted.org/packages/83/a8/72193137de57fda4ebfae4563182d082c8856e3b6e9871d0b46f028fb369/aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a", size = 1875776, upload-time = "2026-06-07T21:08:25.288Z" },
- { url = "https://files.pythonhosted.org/packages/a0/18/938441025db6769a3464596b2410af3afde0b21eb2f204c6f766f68af4bd/aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602", size = 1760329, upload-time = "2026-06-07T21:08:27.363Z" },
- { url = "https://files.pythonhosted.org/packages/60/29/bf2496b4065e76e09fe48015aaffe5ce161d8f089b06ac6982070f653076/aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca", size = 1587293, upload-time = "2026-06-07T21:08:29.805Z" },
- { url = "https://files.pythonhosted.org/packages/49/a2/2136674d52123b1354bd05dd5753c318db47dc0c927cc70b27bab3755456/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35", size = 1714756, upload-time = "2026-06-07T21:08:32.094Z" },
- { url = "https://files.pythonhosted.org/packages/a7/b9/e5fd2e6f915503081c0f9b1e8540947037929c70c191da2e4d54b31a21a1/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844", size = 1721052, upload-time = "2026-06-07T21:08:34.167Z" },
- { url = "https://files.pythonhosted.org/packages/63/5a/2833e324a2263e104e31e2e91bc5bbee81bc499afd32203faee048a883f0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496", size = 1766888, upload-time = "2026-06-07T21:08:36.95Z" },
- { url = "https://files.pythonhosted.org/packages/57/fa/dea6511870913162f3b2e8c42a7614eb203a4540b8c2da43e0bfb0548f3c/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5", size = 1581679, upload-time = "2026-06-07T21:08:39.292Z" },
- { url = "https://files.pythonhosted.org/packages/14/bd/3cf0d55e71784b33534e9710a67d382d900598b4787fbce6cc7317f8c42a/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95", size = 1782021, upload-time = "2026-06-07T21:08:41.407Z" },
- { url = "https://files.pythonhosted.org/packages/c1/af/14bb5843eccbe234f4dfb78ab73e549d99727247e62ae5d62cbd22eaf5b0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444", size = 1742574, upload-time = "2026-06-07T21:08:43.795Z" },
- { url = "https://files.pythonhosted.org/packages/f2/1e/fbeb7af9210a67ac0f9c9bec0f8f4568497924e33137a3d5b48e1cf85f3f/aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0", size = 457773, upload-time = "2026-06-07T21:08:46.168Z" },
- { url = "https://files.pythonhosted.org/packages/f0/2b/13e8d741a9ec5db7d900c060554cf8352ab85e44e2a4469ebb9d377bda17/aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719", size = 485001, upload-time = "2026-06-07T21:08:48.401Z" },
- { url = "https://files.pythonhosted.org/packages/df/30/491acfa2c4d6c3ff59c49a14fc1b50be3241e25bbb0c84c09e2da4d11395/aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec", size = 453809, upload-time = "2026-06-07T21:08:50.7Z" },
- { url = "https://files.pythonhosted.org/packages/34/e3/19dbe1a1f4cc6230eb9e314de7fe68053b0992f9302b27d12141a0b5db53/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2", size = 793320, upload-time = "2026-06-07T21:08:52.775Z" },
- { url = "https://files.pythonhosted.org/packages/7f/20/1b7182219ba1b108430d6e4dc53d25ae02dcfcf5a045b33af4e8c5167527/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340", size = 529077, upload-time = "2026-06-07T21:08:55Z" },
- { url = "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d", size = 532476, upload-time = "2026-06-07T21:08:57.176Z" },
- { url = "https://files.pythonhosted.org/packages/7e/02/9ac85e081e53da2e061b02fa7758fe0a12d17b8ce2d1f5e6c7cb76730328/aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94", size = 1922347, upload-time = "2026-06-07T21:08:59.563Z" },
- { url = "https://files.pythonhosted.org/packages/c0/3e/d3ba07a0ab38b5389e10bec4362d21e10a4f667cba2d79ba30837b3a5059/aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc", size = 1786465, upload-time = "2026-06-07T21:09:01.909Z" },
- { url = "https://files.pythonhosted.org/packages/0b/cb/e2ee978a00cfb2df829704a69528b18154eba5939f45bc1efa8f33aee4c5/aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251", size = 1909423, upload-time = "2026-06-07T21:09:04.357Z" },
- { url = "https://files.pythonhosted.org/packages/73/5d/1430334858b1022b58ae50399a918f0bd6fe8fa7fa183598d657ff61e040/aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1", size = 2001906, upload-time = "2026-06-07T21:09:06.722Z" },
- { url = "https://files.pythonhosted.org/packages/66/4e/560c7472d3d198a23aa5c8b19a5115bf6a9b77b7d3e4bb363da320430ad2/aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3", size = 1877095, upload-time = "2026-06-07T21:09:09.011Z" },
- { url = "https://files.pythonhosted.org/packages/0d/f1/4745806578d447db4a784a8591e2dae3afdfc2bcb96f8f81271b13df6543/aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c", size = 1676222, upload-time = "2026-06-07T21:09:11.461Z" },
- { url = "https://files.pythonhosted.org/packages/6a/c9/48255813cca749a229ef0ab476004ec623728ad79a9c0840616f6c076325/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203", size = 1842922, upload-time = "2026-06-07T21:09:14.118Z" },
- { url = "https://files.pythonhosted.org/packages/3d/c0/bbd054e2bee909f529523a5af3891052606af5143c09f5f183ec3b234676/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1", size = 1825035, upload-time = "2026-06-07T21:09:16.447Z" },
- { url = "https://files.pythonhosted.org/packages/a8/ae/90395d4376deceb74e09ec26b6adf7d2015a6f8802d6d84446af860fef04/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665", size = 1849512, upload-time = "2026-06-07T21:09:18.742Z" },
- { url = "https://files.pythonhosted.org/packages/93/bd/fb25f3049957553d4ce0ba6ae480aa2f592a6985497fca590837d16c1be0/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1", size = 1668571, upload-time = "2026-06-07T21:09:21.458Z" },
- { url = "https://files.pythonhosted.org/packages/3f/22/7f73303d64dd567ff3addca90b556690ed1233a47b8f55d242fb90af3681/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d", size = 1881159, upload-time = "2026-06-07T21:09:23.813Z" },
- { url = "https://files.pythonhosted.org/packages/44/be/0474c5a8b5640e1e4aa1923430a91f4151be82e511373fe764189b89aef5/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c", size = 1841409, upload-time = "2026-06-07T21:09:26.207Z" },
- { url = "https://files.pythonhosted.org/packages/7b/3c/bb4a7cba26956cb3da4553cc2056cf67be5b5ff6e6d8fa4fbdff73bfb7ae/aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365", size = 494166, upload-time = "2026-06-07T21:09:28.505Z" },
- { url = "https://files.pythonhosted.org/packages/8a/84/ec80c2c1f66a952555a9f86df6b33af65108a6febfa0471b69013a12f807/aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9", size = 530255, upload-time = "2026-06-07T21:09:30.843Z" },
- { url = "https://files.pythonhosted.org/packages/2a/71/6e22be134a4061ada85a92951b842f2657f17d926b727f3f94c56ae963d6/aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6", size = 469640, upload-time = "2026-06-07T21:09:33.028Z" },
-]
-
-[[package]]
-name = "aiosignal"
-version = "1.4.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "frozenlist" },
+ { name = "idna" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
-]
-
-[[package]]
-name = "attrs"
-version = "25.3.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
+ { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
]
[[package]]
@@ -169,54 +33,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" },
]
-[[package]]
-name = "charset-normalizer"
-version = "3.4.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" },
- { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" },
- { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" },
- { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" },
- { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" },
- { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" },
- { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" },
- { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" },
- { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" },
- { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" },
- { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" },
- { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" },
- { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" },
- { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" },
- { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" },
- { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" },
- { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" },
- { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" },
- { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" },
- { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" },
- { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" },
- { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" },
- { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" },
- { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" },
- { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" },
- { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" },
- { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" },
- { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" },
- { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" },
- { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" },
- { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" },
- { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" },
- { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" },
- { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" },
- { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" },
- { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" },
- { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" },
- { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" },
- { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" },
- { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" },
-]
-
[[package]]
name = "click"
version = "8.4.1"
@@ -361,94 +177,92 @@ wheels = [
]
[[package]]
-name = "flake8"
-version = "7.3.0"
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "mccabe" },
- { name = "pycodestyle" },
- { name = "pyflakes" },
+ { name = "certifi" },
+ { name = "h11" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872", size = 48326, upload-time = "2025-06-20T19:31:35.838Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
]
[[package]]
-name = "frozenlist"
-version = "1.6.0"
+name = "httpx"
+version = "0.28.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ee/f4/d744cba2da59b5c1d88823cf9e8a6c74e4659e2b27604ed973be2a0bf5ab/frozenlist-1.6.0.tar.gz", hash = "sha256:b99655c32c1c8e06d111e7f41c06c29a5318cb1835df23a45518e02a47c63b68", size = 42831, upload-time = "2025-04-17T22:38:53.099Z" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/53/b5/bc883b5296ec902115c00be161da93bf661199c465ec4c483feec6ea4c32/frozenlist-1.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae8337990e7a45683548ffb2fee1af2f1ed08169284cd829cdd9a7fa7470530d", size = 160912, upload-time = "2025-04-17T22:36:17.235Z" },
- { url = "https://files.pythonhosted.org/packages/6f/93/51b058b563d0704b39c56baa222828043aafcac17fd3734bec5dbeb619b1/frozenlist-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c952f69dd524558694818a461855f35d36cc7f5c0adddce37e962c85d06eac0", size = 124315, upload-time = "2025-04-17T22:36:18.735Z" },
- { url = "https://files.pythonhosted.org/packages/c9/e0/46cd35219428d350558b874d595e132d1c17a9471a1bd0d01d518a261e7c/frozenlist-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f5fef13136c4e2dee91bfb9a44e236fff78fc2cd9f838eddfc470c3d7d90afe", size = 122230, upload-time = "2025-04-17T22:36:20.6Z" },
- { url = "https://files.pythonhosted.org/packages/d1/0f/7ad2ce928ad06d6dd26a61812b959ded573d3e9d0ee6109d96c2be7172e9/frozenlist-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:716bbba09611b4663ecbb7cd022f640759af8259e12a6ca939c0a6acd49eedba", size = 314842, upload-time = "2025-04-17T22:36:22.088Z" },
- { url = "https://files.pythonhosted.org/packages/34/76/98cbbd8a20a5c3359a2004ae5e5b216af84a150ccbad67c8f8f30fb2ea91/frozenlist-1.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7b8c4dc422c1a3ffc550b465090e53b0bf4839047f3e436a34172ac67c45d595", size = 304919, upload-time = "2025-04-17T22:36:24.247Z" },
- { url = "https://files.pythonhosted.org/packages/9a/fa/258e771ce3a44348c05e6b01dffc2bc67603fba95761458c238cd09a2c77/frozenlist-1.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b11534872256e1666116f6587a1592ef395a98b54476addb5e8d352925cb5d4a", size = 324074, upload-time = "2025-04-17T22:36:26.291Z" },
- { url = "https://files.pythonhosted.org/packages/d5/a4/047d861fd8c538210e12b208c0479912273f991356b6bdee7ea8356b07c9/frozenlist-1.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c6eceb88aaf7221f75be6ab498dc622a151f5f88d536661af3ffc486245a626", size = 321292, upload-time = "2025-04-17T22:36:27.909Z" },
- { url = "https://files.pythonhosted.org/packages/c0/25/cfec8af758b4525676cabd36efcaf7102c1348a776c0d1ad046b8a7cdc65/frozenlist-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62c828a5b195570eb4b37369fcbbd58e96c905768d53a44d13044355647838ff", size = 301569, upload-time = "2025-04-17T22:36:29.448Z" },
- { url = "https://files.pythonhosted.org/packages/87/2f/0c819372fa9f0c07b153124bf58683b8d0ca7bb73ea5ccde9b9ef1745beb/frozenlist-1.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1c6bd2c6399920c9622362ce95a7d74e7f9af9bfec05fff91b8ce4b9647845a", size = 313625, upload-time = "2025-04-17T22:36:31.55Z" },
- { url = "https://files.pythonhosted.org/packages/50/5f/f0cf8b0fdedffdb76b3745aa13d5dbe404d63493cc211ce8250f2025307f/frozenlist-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49ba23817781e22fcbd45fd9ff2b9b8cdb7b16a42a4851ab8025cae7b22e96d0", size = 312523, upload-time = "2025-04-17T22:36:33.078Z" },
- { url = "https://files.pythonhosted.org/packages/e1/6c/38c49108491272d3e84125bbabf2c2d0b304899b52f49f0539deb26ad18d/frozenlist-1.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:431ef6937ae0f853143e2ca67d6da76c083e8b1fe3df0e96f3802fd37626e606", size = 322657, upload-time = "2025-04-17T22:36:34.688Z" },
- { url = "https://files.pythonhosted.org/packages/bd/4b/3bd3bad5be06a9d1b04b1c22be80b5fe65b502992d62fab4bdb25d9366ee/frozenlist-1.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9d124b38b3c299ca68433597ee26b7819209cb8a3a9ea761dfe9db3a04bba584", size = 303414, upload-time = "2025-04-17T22:36:36.363Z" },
- { url = "https://files.pythonhosted.org/packages/5b/89/7e225a30bef6e85dbfe22622c24afe932e9444de3b40d58b1ea589a14ef8/frozenlist-1.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:118e97556306402e2b010da1ef21ea70cb6d6122e580da64c056b96f524fbd6a", size = 320321, upload-time = "2025-04-17T22:36:38.16Z" },
- { url = "https://files.pythonhosted.org/packages/22/72/7e3acef4dd9e86366cb8f4d8f28e852c2b7e116927e9722b31a6f71ea4b0/frozenlist-1.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fb3b309f1d4086b5533cf7bbcf3f956f0ae6469664522f1bde4feed26fba60f1", size = 323975, upload-time = "2025-04-17T22:36:40.289Z" },
- { url = "https://files.pythonhosted.org/packages/d8/85/e5da03d20507e13c66ce612c9792b76811b7a43e3320cce42d95b85ac755/frozenlist-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54dece0d21dce4fdb188a1ffc555926adf1d1c516e493c2914d7c370e454bc9e", size = 316553, upload-time = "2025-04-17T22:36:42.045Z" },
- { url = "https://files.pythonhosted.org/packages/ac/8e/6c609cbd0580ae8a0661c408149f196aade7d325b1ae7adc930501b81acb/frozenlist-1.6.0-cp311-cp311-win32.whl", hash = "sha256:654e4ba1d0b2154ca2f096bed27461cf6160bc7f504a7f9a9ef447c293caf860", size = 115511, upload-time = "2025-04-17T22:36:44.067Z" },
- { url = "https://files.pythonhosted.org/packages/f2/13/a84804cfde6de12d44ed48ecbf777ba62b12ff09e761f76cdd1ff9e14bb1/frozenlist-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e911391bffdb806001002c1f860787542f45916c3baf764264a52765d5a5603", size = 120863, upload-time = "2025-04-17T22:36:45.465Z" },
- { url = "https://files.pythonhosted.org/packages/9c/8a/289b7d0de2fbac832ea80944d809759976f661557a38bb8e77db5d9f79b7/frozenlist-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c5b9e42ace7d95bf41e19b87cec8f262c41d3510d8ad7514ab3862ea2197bfb1", size = 160193, upload-time = "2025-04-17T22:36:47.382Z" },
- { url = "https://files.pythonhosted.org/packages/19/80/2fd17d322aec7f430549f0669f599997174f93ee17929ea5b92781ec902c/frozenlist-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ca9973735ce9f770d24d5484dcb42f68f135351c2fc81a7a9369e48cf2998a29", size = 123831, upload-time = "2025-04-17T22:36:49.401Z" },
- { url = "https://files.pythonhosted.org/packages/99/06/f5812da431273f78c6543e0b2f7de67dfd65eb0a433978b2c9c63d2205e4/frozenlist-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ac40ec76041c67b928ca8aaffba15c2b2ee3f5ae8d0cb0617b5e63ec119ca25", size = 121862, upload-time = "2025-04-17T22:36:51.899Z" },
- { url = "https://files.pythonhosted.org/packages/d0/31/9e61c6b5fc493cf24d54881731204d27105234d09878be1a5983182cc4a5/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b7a8a3180dfb280eb044fdec562f9b461614c0ef21669aea6f1d3dac6ee576", size = 316361, upload-time = "2025-04-17T22:36:53.402Z" },
- { url = "https://files.pythonhosted.org/packages/9d/55/22ca9362d4f0222324981470fd50192be200154d51509ee6eb9baa148e96/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c444d824e22da6c9291886d80c7d00c444981a72686e2b59d38b285617cb52c8", size = 307115, upload-time = "2025-04-17T22:36:55.016Z" },
- { url = "https://files.pythonhosted.org/packages/ae/39/4fff42920a57794881e7bb3898dc7f5f539261711ea411b43bba3cde8b79/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb52c8166499a8150bfd38478248572c924c003cbb45fe3bcd348e5ac7c000f9", size = 322505, upload-time = "2025-04-17T22:36:57.12Z" },
- { url = "https://files.pythonhosted.org/packages/55/f2/88c41f374c1e4cf0092a5459e5f3d6a1e17ed274c98087a76487783df90c/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b35298b2db9c2468106278537ee529719228950a5fdda686582f68f247d1dc6e", size = 322666, upload-time = "2025-04-17T22:36:58.735Z" },
- { url = "https://files.pythonhosted.org/packages/75/51/034eeb75afdf3fd03997856195b500722c0b1a50716664cde64e28299c4b/frozenlist-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d108e2d070034f9d57210f22fefd22ea0d04609fc97c5f7f5a686b3471028590", size = 302119, upload-time = "2025-04-17T22:37:00.512Z" },
- { url = "https://files.pythonhosted.org/packages/2b/a6/564ecde55ee633270a793999ef4fd1d2c2b32b5a7eec903b1012cb7c5143/frozenlist-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1be9111cb6756868ac242b3c2bd1f09d9aea09846e4f5c23715e7afb647103", size = 316226, upload-time = "2025-04-17T22:37:02.102Z" },
- { url = "https://files.pythonhosted.org/packages/f1/c8/6c0682c32377f402b8a6174fb16378b683cf6379ab4d2827c580892ab3c7/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:94bb451c664415f02f07eef4ece976a2c65dcbab9c2f1705b7031a3a75349d8c", size = 312788, upload-time = "2025-04-17T22:37:03.578Z" },
- { url = "https://files.pythonhosted.org/packages/b6/b8/10fbec38f82c5d163ca1750bfff4ede69713badf236a016781cf1f10a0f0/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d1a686d0b0949182b8faddea596f3fc11f44768d1f74d4cad70213b2e139d821", size = 325914, upload-time = "2025-04-17T22:37:05.213Z" },
- { url = "https://files.pythonhosted.org/packages/62/ca/2bf4f3a1bd40cdedd301e6ecfdbb291080d5afc5f9ce350c0739f773d6b9/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea8e59105d802c5a38bdbe7362822c522230b3faba2aa35c0fa1765239b7dd70", size = 305283, upload-time = "2025-04-17T22:37:06.985Z" },
- { url = "https://files.pythonhosted.org/packages/09/64/20cc13ccf94abc2a1f482f74ad210703dc78a590d0b805af1c9aa67f76f9/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:abc4e880a9b920bc5020bf6a431a6bb40589d9bca3975c980495f63632e8382f", size = 319264, upload-time = "2025-04-17T22:37:08.618Z" },
- { url = "https://files.pythonhosted.org/packages/20/ff/86c6a2bbe98cfc231519f5e6d712a0898488ceac804a917ce014f32e68f6/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a79713adfe28830f27a3c62f6b5406c37376c892b05ae070906f07ae4487046", size = 326482, upload-time = "2025-04-17T22:37:10.196Z" },
- { url = "https://files.pythonhosted.org/packages/2f/da/8e381f66367d79adca245d1d71527aac774e30e291d41ef161ce2d80c38e/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0318c2068e217a8f5e3b85e35899f5a19e97141a45bb925bb357cfe1daf770", size = 318248, upload-time = "2025-04-17T22:37:12.284Z" },
- { url = "https://files.pythonhosted.org/packages/39/24/1a1976563fb476ab6f0fa9fefaac7616a4361dbe0461324f9fd7bf425dbe/frozenlist-1.6.0-cp312-cp312-win32.whl", hash = "sha256:853ac025092a24bb3bf09ae87f9127de9fe6e0c345614ac92536577cf956dfcc", size = 115161, upload-time = "2025-04-17T22:37:13.902Z" },
- { url = "https://files.pythonhosted.org/packages/80/2e/fb4ed62a65f8cd66044706b1013f0010930d8cbb0729a2219561ea075434/frozenlist-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bdfe2d7e6c9281c6e55523acd6c2bf77963cb422fdc7d142fb0cb6621b66878", size = 120548, upload-time = "2025-04-17T22:37:15.326Z" },
- { url = "https://files.pythonhosted.org/packages/6f/e5/04c7090c514d96ca00887932417f04343ab94904a56ab7f57861bf63652d/frozenlist-1.6.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1d7fb014fe0fbfee3efd6a94fc635aeaa68e5e1720fe9e57357f2e2c6e1a647e", size = 158182, upload-time = "2025-04-17T22:37:16.837Z" },
- { url = "https://files.pythonhosted.org/packages/e9/8f/60d0555c61eec855783a6356268314d204137f5e0c53b59ae2fc28938c99/frozenlist-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01bcaa305a0fdad12745502bfd16a1c75b14558dabae226852f9159364573117", size = 122838, upload-time = "2025-04-17T22:37:18.352Z" },
- { url = "https://files.pythonhosted.org/packages/5a/a7/d0ec890e3665b4b3b7c05dc80e477ed8dc2e2e77719368e78e2cd9fec9c8/frozenlist-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b314faa3051a6d45da196a2c495e922f987dc848e967d8cfeaee8a0328b1cd4", size = 120980, upload-time = "2025-04-17T22:37:19.857Z" },
- { url = "https://files.pythonhosted.org/packages/cc/19/9b355a5e7a8eba903a008579964192c3e427444752f20b2144b10bb336df/frozenlist-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da62fecac21a3ee10463d153549d8db87549a5e77eefb8c91ac84bb42bb1e4e3", size = 305463, upload-time = "2025-04-17T22:37:21.328Z" },
- { url = "https://files.pythonhosted.org/packages/9c/8d/5b4c758c2550131d66935ef2fa700ada2461c08866aef4229ae1554b93ca/frozenlist-1.6.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1eb89bf3454e2132e046f9599fbcf0a4483ed43b40f545551a39316d0201cd1", size = 297985, upload-time = "2025-04-17T22:37:23.55Z" },
- { url = "https://files.pythonhosted.org/packages/48/2c/537ec09e032b5865715726b2d1d9813e6589b571d34d01550c7aeaad7e53/frozenlist-1.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18689b40cb3936acd971f663ccb8e2589c45db5e2c5f07e0ec6207664029a9c", size = 311188, upload-time = "2025-04-17T22:37:25.221Z" },
- { url = "https://files.pythonhosted.org/packages/31/2f/1aa74b33f74d54817055de9a4961eff798f066cdc6f67591905d4fc82a84/frozenlist-1.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e67ddb0749ed066b1a03fba812e2dcae791dd50e5da03be50b6a14d0c1a9ee45", size = 311874, upload-time = "2025-04-17T22:37:26.791Z" },
- { url = "https://files.pythonhosted.org/packages/bf/f0/cfec18838f13ebf4b37cfebc8649db5ea71a1b25dacd691444a10729776c/frozenlist-1.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc5e64626e6682638d6e44398c9baf1d6ce6bc236d40b4b57255c9d3f9761f1f", size = 291897, upload-time = "2025-04-17T22:37:28.958Z" },
- { url = "https://files.pythonhosted.org/packages/ea/a5/deb39325cbbea6cd0a46db8ccd76150ae2fcbe60d63243d9df4a0b8c3205/frozenlist-1.6.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:437cfd39564744ae32ad5929e55b18ebd88817f9180e4cc05e7d53b75f79ce85", size = 305799, upload-time = "2025-04-17T22:37:30.889Z" },
- { url = "https://files.pythonhosted.org/packages/78/22/6ddec55c5243a59f605e4280f10cee8c95a449f81e40117163383829c241/frozenlist-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62dd7df78e74d924952e2feb7357d826af8d2f307557a779d14ddf94d7311be8", size = 302804, upload-time = "2025-04-17T22:37:32.489Z" },
- { url = "https://files.pythonhosted.org/packages/5d/b7/d9ca9bab87f28855063c4d202936800219e39db9e46f9fb004d521152623/frozenlist-1.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a66781d7e4cddcbbcfd64de3d41a61d6bdde370fc2e38623f30b2bd539e84a9f", size = 316404, upload-time = "2025-04-17T22:37:34.59Z" },
- { url = "https://files.pythonhosted.org/packages/a6/3a/1255305db7874d0b9eddb4fe4a27469e1fb63720f1fc6d325a5118492d18/frozenlist-1.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:482fe06e9a3fffbcd41950f9d890034b4a54395c60b5e61fae875d37a699813f", size = 295572, upload-time = "2025-04-17T22:37:36.337Z" },
- { url = "https://files.pythonhosted.org/packages/2a/f2/8d38eeee39a0e3a91b75867cc102159ecccf441deb6ddf67be96d3410b84/frozenlist-1.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e4f9373c500dfc02feea39f7a56e4f543e670212102cc2eeb51d3a99c7ffbde6", size = 307601, upload-time = "2025-04-17T22:37:37.923Z" },
- { url = "https://files.pythonhosted.org/packages/38/04/80ec8e6b92f61ef085422d7b196822820404f940950dde5b2e367bede8bc/frozenlist-1.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e69bb81de06827147b7bfbaeb284d85219fa92d9f097e32cc73675f279d70188", size = 314232, upload-time = "2025-04-17T22:37:39.669Z" },
- { url = "https://files.pythonhosted.org/packages/3a/58/93b41fb23e75f38f453ae92a2f987274c64637c450285577bd81c599b715/frozenlist-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7613d9977d2ab4a9141dde4a149f4357e4065949674c5649f920fec86ecb393e", size = 308187, upload-time = "2025-04-17T22:37:41.662Z" },
- { url = "https://files.pythonhosted.org/packages/6a/a2/e64df5c5aa36ab3dee5a40d254f3e471bb0603c225f81664267281c46a2d/frozenlist-1.6.0-cp313-cp313-win32.whl", hash = "sha256:4def87ef6d90429f777c9d9de3961679abf938cb6b7b63d4a7eb8a268babfce4", size = 114772, upload-time = "2025-04-17T22:37:43.132Z" },
- { url = "https://files.pythonhosted.org/packages/a0/77/fead27441e749b2d574bb73d693530d59d520d4b9e9679b8e3cb779d37f2/frozenlist-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:37a8a52c3dfff01515e9bbbee0e6063181362f9de3db2ccf9bc96189b557cbfd", size = 119847, upload-time = "2025-04-17T22:37:45.118Z" },
- { url = "https://files.pythonhosted.org/packages/df/bd/cc6d934991c1e5d9cafda83dfdc52f987c7b28343686aef2e58a9cf89f20/frozenlist-1.6.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:46138f5a0773d064ff663d273b309b696293d7a7c00a0994c5c13a5078134b64", size = 174937, upload-time = "2025-04-17T22:37:46.635Z" },
- { url = "https://files.pythonhosted.org/packages/f2/a2/daf945f335abdbfdd5993e9dc348ef4507436936ab3c26d7cfe72f4843bf/frozenlist-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f88bc0a2b9c2a835cb888b32246c27cdab5740059fb3688852bf91e915399b91", size = 136029, upload-time = "2025-04-17T22:37:48.192Z" },
- { url = "https://files.pythonhosted.org/packages/51/65/4c3145f237a31247c3429e1c94c384d053f69b52110a0d04bfc8afc55fb2/frozenlist-1.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:777704c1d7655b802c7850255639672e90e81ad6fa42b99ce5ed3fbf45e338dd", size = 134831, upload-time = "2025-04-17T22:37:50.485Z" },
- { url = "https://files.pythonhosted.org/packages/77/38/03d316507d8dea84dfb99bdd515ea245628af964b2bf57759e3c9205cc5e/frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ef8d41764c7de0dcdaf64f733a27352248493a85a80661f3c678acd27e31f2", size = 392981, upload-time = "2025-04-17T22:37:52.558Z" },
- { url = "https://files.pythonhosted.org/packages/37/02/46285ef9828f318ba400a51d5bb616ded38db8466836a9cfa39f3903260b/frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:da5cb36623f2b846fb25009d9d9215322318ff1c63403075f812b3b2876c8506", size = 371999, upload-time = "2025-04-17T22:37:54.092Z" },
- { url = "https://files.pythonhosted.org/packages/0d/64/1212fea37a112c3c5c05bfb5f0a81af4836ce349e69be75af93f99644da9/frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbb56587a16cf0fb8acd19e90ff9924979ac1431baea8681712716a8337577b0", size = 392200, upload-time = "2025-04-17T22:37:55.951Z" },
- { url = "https://files.pythonhosted.org/packages/81/ce/9a6ea1763e3366e44a5208f76bf37c76c5da570772375e4d0be85180e588/frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6154c3ba59cda3f954c6333025369e42c3acd0c6e8b6ce31eb5c5b8116c07e0", size = 390134, upload-time = "2025-04-17T22:37:57.633Z" },
- { url = "https://files.pythonhosted.org/packages/bc/36/939738b0b495b2c6d0c39ba51563e453232813042a8d908b8f9544296c29/frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e8246877afa3f1ae5c979fe85f567d220f86a50dc6c493b9b7d8191181ae01e", size = 365208, upload-time = "2025-04-17T22:37:59.742Z" },
- { url = "https://files.pythonhosted.org/packages/b4/8b/939e62e93c63409949c25220d1ba8e88e3960f8ef6a8d9ede8f94b459d27/frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0f6cce16306d2e117cf9db71ab3a9e8878a28176aeaf0dbe35248d97b28d0c", size = 385548, upload-time = "2025-04-17T22:38:01.416Z" },
- { url = "https://files.pythonhosted.org/packages/62/38/22d2873c90102e06a7c5a3a5b82ca47e393c6079413e8a75c72bff067fa8/frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1b8e8cd8032ba266f91136d7105706ad57770f3522eac4a111d77ac126a25a9b", size = 391123, upload-time = "2025-04-17T22:38:03.049Z" },
- { url = "https://files.pythonhosted.org/packages/44/78/63aaaf533ee0701549500f6d819be092c6065cb5c577edb70c09df74d5d0/frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e2ada1d8515d3ea5378c018a5f6d14b4994d4036591a52ceaf1a1549dec8e1ad", size = 394199, upload-time = "2025-04-17T22:38:04.776Z" },
- { url = "https://files.pythonhosted.org/packages/54/45/71a6b48981d429e8fbcc08454dc99c4c2639865a646d549812883e9c9dd3/frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:cdb2c7f071e4026c19a3e32b93a09e59b12000751fc9b0b7758da899e657d215", size = 373854, upload-time = "2025-04-17T22:38:06.576Z" },
- { url = "https://files.pythonhosted.org/packages/3f/f3/dbf2a5e11736ea81a66e37288bf9f881143a7822b288a992579ba1b4204d/frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:03572933a1969a6d6ab509d509e5af82ef80d4a5d4e1e9f2e1cdd22c77a3f4d2", size = 395412, upload-time = "2025-04-17T22:38:08.197Z" },
- { url = "https://files.pythonhosted.org/packages/b3/f1/c63166806b331f05104d8ea385c4acd511598568b1f3e4e8297ca54f2676/frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:77effc978947548b676c54bbd6a08992759ea6f410d4987d69feea9cd0919911", size = 394936, upload-time = "2025-04-17T22:38:10.056Z" },
- { url = "https://files.pythonhosted.org/packages/ef/ea/4f3e69e179a430473eaa1a75ff986526571215fefc6b9281cdc1f09a4eb8/frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a2bda8be77660ad4089caf2223fdbd6db1858462c4b85b67fbfa22102021e497", size = 391459, upload-time = "2025-04-17T22:38:11.826Z" },
- { url = "https://files.pythonhosted.org/packages/d3/c3/0fc2c97dea550df9afd072a37c1e95421652e3206bbeaa02378b24c2b480/frozenlist-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:a4d96dc5bcdbd834ec6b0f91027817214216b5b30316494d2b1aebffb87c534f", size = 128797, upload-time = "2025-04-17T22:38:14.013Z" },
- { url = "https://files.pythonhosted.org/packages/ae/f5/79c9320c5656b1965634fe4be9c82b12a3305bdbc58ad9cb941131107b20/frozenlist-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e18036cb4caa17ea151fd5f3d70be9d354c99eb8cf817a3ccde8a7873b074348", size = 134709, upload-time = "2025-04-17T22:38:15.551Z" },
- { url = "https://files.pythonhosted.org/packages/71/3e/b04a0adda73bd52b390d730071c0d577073d3d26740ee1bad25c3ad0f37b/frozenlist-1.6.0-py3-none-any.whl", hash = "sha256:535eec9987adb04701266b92745d6cdcef2e77669299359c3009c3404dd5d191", size = 12404, upload-time = "2025-04-17T22:38:51.668Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[[package]]
+name = "hypothesis"
+version = "6.156.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "sortedcontainers" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/57/4b/d376c0382fc716878790177deb88cc8b73d3a0218ae74de6e14493f7dc74/hypothesis-6.156.3.tar.gz", hash = "sha256:0c68209d611a17d9092a74d4a7c945256b8c7288e4e2b8a8a3c3be716a284365", size = 476259, upload-time = "2026-07-08T11:27:23.758Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f0/f5/2838f39dcf725c766cee1c3f077f71c027279082ba8c91eab69c916d4e92/hypothesis-6.156.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:49b8a2ccad35987f536dab81cdee12ea53ab5e87fae079cfb2517f47bde11c59", size = 749193, upload-time = "2026-07-08T11:27:20.607Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/db/4a7661d29ea88d42e0e0544c8d0b54f56e4ccb391b1c0ad97421b3100889/hypothesis-6.156.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:91a48e40a4fab58f454b42fcab21306488637ae3a6fbf757f7d044e29306119d", size = 743707, upload-time = "2026-07-08T11:26:18.443Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/a9/ee98adf01d7d92b0cae5855eef1f9df7ae294154643cf29d64b4a1b65e83/hypothesis-6.156.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b23da0553cd12f448211d1e94274351978b0a1cfa62b603a97e289d8e3432b9a", size = 1070975, upload-time = "2026-07-08T11:26:29.681Z" },
+ { url = "https://files.pythonhosted.org/packages/40/8f/cc6ddf1062e0ca3cb499582d25de6713521ef448d109526a81f27eb3eef7/hypothesis-6.156.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcc75a2bf4e250bcb67d74b2a423e149adf69b6730fd9de78d97494d7d4146d4", size = 1120657, upload-time = "2026-07-08T11:26:22.521Z" },
+ { url = "https://files.pythonhosted.org/packages/26/a0/e3478fea1242d4fcd1c5e20bf6fb8db80cfef27b4407995e7e9f7452148d/hypothesis-6.156.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d5a453ae95e471e70de86fc07eda86d096c47fa9059b83b26316b5c0e54e6fcd", size = 1245183, upload-time = "2026-07-08T11:27:17.085Z" },
+ { url = "https://files.pythonhosted.org/packages/73/00/cb6fb0c2430960de30a3927432569aaba30db80b28c513abdabfd06fe8b0/hypothesis-6.156.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5fb3bbf324030a850adc17c26c09ef9856bf73f19e27dfb3b2a7c72f6ee05c9", size = 1287894, upload-time = "2026-07-08T11:27:10.517Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/ff/abc3922baf5f03864b3b9fab334be0a05702060ad0ca90ffeafbc890bb4d/hypothesis-6.156.3-cp311-cp311-win_amd64.whl", hash = "sha256:56a84fa7172c3166f4ceaa44ecb72715ed2be59f5b1ae49a27fff2c4cb6cc251", size = 640180, upload-time = "2026-07-08T11:26:45.899Z" },
+ { url = "https://files.pythonhosted.org/packages/52/37/8f1d7ed73656d56d94b8da1d0ee429bab70015e78c33933b1b41f41958a9/hypothesis-6.156.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f009db55dc3227ed1040dc69f446fa672a64d240408856a34419cd841cfc7b9b", size = 749042, upload-time = "2026-07-08T11:27:12.126Z" },
+ { url = "https://files.pythonhosted.org/packages/90/db/5be0f96e830e376d38d1cb2b9a0d55ce0e714aa4992692be5311f820a157/hypothesis-6.156.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e58baa63416d4ad5b5722f683dd85205b00d6b1aed42914eda5f3f5c36ec5c4", size = 741867, upload-time = "2026-07-08T11:27:08.89Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/70/4e96a883f1f71cdb4c626ce8e818279be97ab4cafcae7ec288d79a48028f/hypothesis-6.156.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3974fdbacfb37ea6a7c503e3e355992f1ae19658ac920661492d03863ffa0c58", size = 1069806, upload-time = "2026-07-08T11:26:52.58Z" },
+ { url = "https://files.pythonhosted.org/packages/69/a8/c1071a89cd981a0f9d22a5723a79253ec4ff68f60d196b6aaaaea38b5b74/hypothesis-6.156.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55948a48d348a448acd33b908cfb2c3e88a4560b3d5e6d38bfb2650ea389e69b", size = 1119589, upload-time = "2026-07-08T11:26:39.81Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/2c/27336f452eddeceaf173e7ea3b34383e6febe872958483253cb3e2989db2/hypothesis-6.156.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dfe4bce2bd2770f2d11ec2dee3469221939eb109ee28a91649fd7f27700ff263", size = 1243866, upload-time = "2026-07-08T11:26:12.252Z" },
+ { url = "https://files.pythonhosted.org/packages/27/22/b9b67469777fe1359d694b92903bd2d516b58bf85915045461aae84fa093/hypothesis-6.156.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:592c67d32ee58026556ad26ddbf76a873f5b0c9d0a0104f73db9db0dfba32f18", size = 1286420, upload-time = "2026-07-08T11:26:19.802Z" },
+ { url = "https://files.pythonhosted.org/packages/36/36/60f8451ac90b1550feb7f7f1a858742beb31746465dcc370cfb675d53b06/hypothesis-6.156.3-cp312-cp312-win_amd64.whl", hash = "sha256:d39c149673b9d86be6cb9df01d1a4e8081f26e8093eabc957d6769b8b3afa6d8", size = 637647, upload-time = "2026-07-08T11:27:15.438Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/b8/9d7dce42c9534bd9d3ddfa2bb95a8efa82fb0b9a7a89bc14fcd9fac10368/hypothesis-6.156.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:775d70e3cf5c0cd83239b62ab60d2ddbbddd026bba57aa6deeeaed6aa83f5002", size = 749455, upload-time = "2026-07-08T11:26:47.428Z" },
+ { url = "https://files.pythonhosted.org/packages/02/81/6b2d101825302b8200e88b0d6e4b0e0ca93a8966097669614c33d61265b7/hypothesis-6.156.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f0f2acd5b9a462e0d2589b7600c563c39808a8683c2d614d1caaabeb1c67c062", size = 742058, upload-time = "2026-07-08T11:26:23.942Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/5a/342f103a6ec6fb77897f2030f00075d4d84d4afbfb7944cddca334cf5a98/hypothesis-6.156.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fbe0888b4ab8253ca44b763faa56d37a10d602480ecc2f03a09d96b3a1bf8", size = 1069965, upload-time = "2026-07-08T11:26:31.233Z" },
+ { url = "https://files.pythonhosted.org/packages/84/cb/86a44d644c28251fc6f2799bc8c5d97358bf00f7417a18eb0783cc597d77/hypothesis-6.156.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70eb849033695e5b81f0241019751d7b60ecea248c993f5e1536a1bd0caa6d7", size = 1119954, upload-time = "2026-07-08T11:26:55.917Z" },
+ { url = "https://files.pythonhosted.org/packages/68/99/ec84b29ec0f9bc646fb98655c76d4ced5e44309f26b86fc58b20c9d0634e/hypothesis-6.156.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0e2eb13d32f5dfeacd59979b9acf8e647d4d6f5b4b0a18b277db59b0ec7994eb", size = 1244030, upload-time = "2026-07-08T11:26:33.846Z" },
+ { url = "https://files.pythonhosted.org/packages/54/15/74a7c54493763707325e67be90aba13e144b6296224fb1a1907d22bf1452/hypothesis-6.156.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64b606f915bb84b880b479c31fed1b283aab8b0d5c59e6ba2c314e9a35c686f4", size = 1286706, upload-time = "2026-07-08T11:26:51.02Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/41/275cbcacc49c22e5e717a7217a0b1accfaae6fefefce8af39b4fae5a13a2/hypothesis-6.156.3-cp313-cp313-win_amd64.whl", hash = "sha256:a68d2d46442e48f90844d939fb372d96f96972017b4314c7418d82f20c9f1aa3", size = 637935, upload-time = "2026-07-08T11:26:13.557Z" },
+ { url = "https://files.pythonhosted.org/packages/52/d1/d106f75214f7abc28abfcc4ae5a87cc7b445dfe7dd738d1b86d079a61741/hypothesis-6.156.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d5883bd0e7e1a54a478553cc1c57dbd14b751562f5134abe4742ba1d7267a14b", size = 749486, upload-time = "2026-07-08T11:26:59.432Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/84/84d1cbe3b2812eba795b2137b579582f1189256d996d27ee42a974edb240/hypothesis-6.156.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5bc9b4258403ebdc01121c6cc9cb4a3967ca5a569a5168a80c34828b3d6ab264", size = 742264, upload-time = "2026-07-08T11:26:16.003Z" },
+ { url = "https://files.pythonhosted.org/packages/94/28/ede93daa4fe869aa42abcaaba9da14024d61ed313ac6c8373634b1359185/hypothesis-6.156.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6d73e6f15ec5e412ab4aca148a2673033a1728072a4d33b600f8f5d84af819", size = 1070142, upload-time = "2026-07-08T11:27:22.149Z" },
+ { url = "https://files.pythonhosted.org/packages/55/59/8f595b2f2a594ab7834a588bbcd11ed053cb054a5bad399015f4df6be3ae/hypothesis-6.156.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4f7029436f51e98e6a5d78cb1ecab1ef5a0f3517dbab003429b8a65e47f9a41", size = 1120144, upload-time = "2026-07-08T11:26:38.368Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/de/3bbdf04a66e09d730048d5e82722df6fd1047187c02c2764dd9d19423353/hypothesis-6.156.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:67d1d3053d077b0715a50d92decf578742aa2ab4cec713a56e722abd33361cca", size = 1244300, upload-time = "2026-07-08T11:26:14.746Z" },
+ { url = "https://files.pythonhosted.org/packages/36/37/dd0fac3b7042a37a284f055461500018656a80bfcca246124f253772a99a/hypothesis-6.156.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:83389a53144ce61c6789cc0a43fefe26c257dcb8b23ccd9291db024b8ade3652", size = 1287218, upload-time = "2026-07-08T11:26:49.066Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/26/5310edd49abaa73a8fa41733fd9874781c9d4d94f03566231a2784de291e/hypothesis-6.156.3-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:0f3367fbaedc5527ef3ff717006f94db79a19473d7d0a5ecce0f0de926ed6143", size = 586422, upload-time = "2026-07-08T11:26:44.006Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/58/877f1c8aeaadced677f73f00ee00ffb22f0e93f052114d74c87cbb8742fd/hypothesis-6.156.3-cp314-cp314-win_amd64.whl", hash = "sha256:5ab613fde3d4324fae8c6f8cf217d5f463a82be0e9dee4f17d952230d0094612", size = 637731, upload-time = "2026-07-08T11:27:02.437Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/c1/0d31764d9370f32cdaa1eb565fe617cbfb4e223efd0bff8433bcd2f4666e/hypothesis-6.156.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:93d45959fc889a63a66fff0923dfd25dda53ee181eebec81003ffbf5cd7c86f8", size = 747516, upload-time = "2026-07-08T11:26:17.282Z" },
+ { url = "https://files.pythonhosted.org/packages/31/e5/a10345872f80688545c625a7c93f529aba2a0dfa8a6a5d18a0995c61aaf2/hypothesis-6.156.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0b58648a7f9705b98371ba6515da2f0415c440cb24fef34ee48857ae57740ef6", size = 740877, upload-time = "2026-07-08T11:26:41.19Z" },
+ { url = "https://files.pythonhosted.org/packages/33/1d/434962713972eeb3f643ffd77b39f18a9f6867d8f07424447bb651bb8934/hypothesis-6.156.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95bd12f151cb79d55b7b9d3cd64c3fe7506c27d3fd54fac8cba2e7d847292da1", size = 1069163, upload-time = "2026-07-08T11:27:05.683Z" },
+ { url = "https://files.pythonhosted.org/packages/96/d6/a9d52d6a830d0fc79af35ef46f678ed3f7fc0c8e186ec41c386aa9a1bff8/hypothesis-6.156.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67e53f029e7c31471e6de06bcb0c05f8f08630817c14c49e99d0d3e198082cf0", size = 1119238, upload-time = "2026-07-08T11:26:36.96Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/f7/c228a4228304243845883f2feeda46c2f7dacbe0dc20ffae758bc6bbf5ef/hypothesis-6.156.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2470f9745bbe7fe98c5eeaa2f5e74ebdfed46d401efc7d82f0cd6ab3da8d9408", size = 1243071, upload-time = "2026-07-08T11:27:13.763Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/4c/b6ab46567e501b6b74cc98557c65afc55f6388e5ea4939ec9cd5e3da3b0b/hypothesis-6.156.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:05370d67210ce822eea53060ea723d1b70cde8c2bab5a5b10d557a9b81f51944", size = 1285531, upload-time = "2026-07-08T11:26:09.812Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/c5/939fb46bd62082379c34321fe315808a5f4afd4b1d78e3719e8bb36dda53/hypothesis-6.156.3-cp314-cp314t-win_amd64.whl", hash = "sha256:39cae9b690c49793bdce45daed45f9f37a38ab1360b74a328458ad56caac74f6", size = 637850, upload-time = "2026-07-08T11:26:54.49Z" },
+ { url = "https://files.pythonhosted.org/packages/52/35/9c5d61a968ace9853a8121d20126fc9c8bbe09ca050a06a427a6254152a3/hypothesis-6.156.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e62c0782e6cead74c0c931bd78526ed9b8114a14b16ad631cbe5a59b33e5628a", size = 749744, upload-time = "2026-07-08T11:27:07.376Z" },
+ { url = "https://files.pythonhosted.org/packages/70/51/937fcd17a9e56fc0f681f1ca822e3edeadcb2b984e86ff71218a6b26e647/hypothesis-6.156.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:06f8d858326bca887241145842da378423c4f6274e90fe2631a22fac107cc033", size = 744333, upload-time = "2026-07-08T11:26:26.963Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/c1/13ead61ebed8d0321fd8f5afb347e587cf738326e4feb8288803f799b467/hypothesis-6.156.3-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f815d099de262fbb11dee666534c7c808158aca5489808183253ffe5323657", size = 1071370, upload-time = "2026-07-08T11:26:25.363Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/e4/5f0a6d8fda7e818893fccd35eb08c930c52251a36a461dedb886da56b5aa/hypothesis-6.156.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc45ee9649f0803cdd3258b2ab59f7a083670d21105eb73967237911d86f6820", size = 1121413, upload-time = "2026-07-08T11:27:19.01Z" },
+ { url = "https://files.pythonhosted.org/packages/34/c9/6249ed5dff9848c6b446b9e7cffc052b3c6882d05f7dda8c574874133218/hypothesis-6.156.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:838622aaebce6113111990014f9941bfb6d3481c135d93c4ae6dcc78a0d523c9", size = 640781, upload-time = "2026-07-08T11:27:04.058Z" },
]
[[package]]
@@ -462,11 +276,11 @@ wheels = [
[[package]]
name = "idna"
-version = "3.15"
+version = "3.10"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", size = 199245, upload-time = "2026-05-12T22:45:57.011Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", size = 72340, upload-time = "2026-05-12T22:45:55.733Z" },
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
]
[[package]]
@@ -538,133 +352,51 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" },
]
-[[package]]
-name = "mccabe"
-version = "0.7.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" },
-]
-
[[package]]
name = "meraki"
-version = "3.3.0"
+version = "4.3.0b1"
source = { editable = "." }
dependencies = [
- { name = "aiohttp" },
- { name = "requests" },
+ { name = "httpx" },
]
[package.dev-dependencies]
dev = [
- { name = "flake8" },
+ { name = "hypothesis" },
{ name = "pre-commit" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
+ { name = "pytest-benchmark" },
{ name = "pytest-cov" },
- { name = "responses" },
+ { name = "pytest-json-report" },
+ { name = "respx" },
{ name = "ruff" },
{ name = "towncrier" },
]
generator = [
+ { name = "httpx" },
{ name = "jinja2" },
]
[package.metadata]
-requires-dist = [
- { name = "aiohttp", specifier = ">=3.13.5,<4" },
- { name = "requests", specifier = ">=2.33.1,<3" },
-]
+requires-dist = [{ name = "httpx", specifier = ">=0.28,<1" }]
[package.metadata.requires-dev]
dev = [
- { name = "flake8", specifier = ">=7.0,<8" },
+ { name = "hypothesis", specifier = ">=6.122.0,<7" },
{ name = "pre-commit", specifier = ">=4.6.0" },
{ name = "pytest", specifier = ">=8.3.5,<10" },
{ name = "pytest-asyncio", specifier = ">=1.0,<2" },
+ { name = "pytest-benchmark", specifier = ">=2.0.0" },
{ name = "pytest-cov", specifier = ">=7.1.0,<8" },
- { name = "responses", specifier = ">=0.25,<1" },
+ { name = "pytest-json-report", specifier = ">=1.5.0" },
+ { name = "respx", specifier = ">=0.23.1,<1" },
{ name = "ruff", specifier = ">=0.15.12" },
{ name = "towncrier", specifier = ">=24.8.0" },
]
-generator = [{ name = "jinja2", specifier = "==3.1.6" }]
-
-[[package]]
-name = "multidict"
-version = "6.4.4"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" },
- { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" },
- { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" },
- { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" },
- { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" },
- { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" },
- { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" },
- { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" },
- { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" },
- { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" },
- { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" },
- { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" },
- { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" },
- { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" },
- { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" },
- { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" },
- { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" },
- { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" },
- { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" },
- { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" },
- { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" },
- { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" },
- { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" },
- { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" },
- { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" },
- { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" },
- { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" },
- { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" },
- { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" },
- { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" },
- { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" },
- { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" },
- { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" },
- { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" },
- { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" },
- { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" },
- { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" },
- { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" },
- { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" },
- { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" },
- { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" },
- { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" },
- { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" },
- { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" },
- { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" },
- { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" },
- { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" },
- { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" },
- { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" },
- { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" },
- { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" },
- { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" },
- { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" },
- { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" },
- { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" },
- { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" },
- { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" },
- { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" },
- { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" },
- { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" },
- { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" },
- { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" },
- { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" },
- { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" },
- { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" },
- { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" },
- { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" },
- { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" },
- { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" },
+generator = [
+ { name = "httpx", specifier = ">=0.28,<1" },
+ { name = "jinja2", specifier = "==3.1.6" },
]
[[package]]
@@ -720,94 +452,12 @@ wheels = [
]
[[package]]
-name = "propcache"
-version = "0.3.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/07/c8/fdc6686a986feae3541ea23dcaa661bd93972d3940460646c6bb96e21c40/propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", size = 43651, upload-time = "2025-03-26T03:06:12.05Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/90/0f/5a5319ee83bd651f75311fcb0c492c21322a7fc8f788e4eef23f44243427/propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", size = 80243, upload-time = "2025-03-26T03:04:01.912Z" },
- { url = "https://files.pythonhosted.org/packages/ce/84/3db5537e0879942783e2256616ff15d870a11d7ac26541336fe1b673c818/propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", size = 46503, upload-time = "2025-03-26T03:04:03.704Z" },
- { url = "https://files.pythonhosted.org/packages/e2/c8/b649ed972433c3f0d827d7f0cf9ea47162f4ef8f4fe98c5f3641a0bc63ff/propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", size = 45934, upload-time = "2025-03-26T03:04:05.257Z" },
- { url = "https://files.pythonhosted.org/packages/59/f9/4c0a5cf6974c2c43b1a6810c40d889769cc8f84cea676cbe1e62766a45f8/propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", size = 233633, upload-time = "2025-03-26T03:04:07.044Z" },
- { url = "https://files.pythonhosted.org/packages/e7/64/66f2f4d1b4f0007c6e9078bd95b609b633d3957fe6dd23eac33ebde4b584/propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", size = 241124, upload-time = "2025-03-26T03:04:08.676Z" },
- { url = "https://files.pythonhosted.org/packages/aa/bf/7b8c9fd097d511638fa9b6af3d986adbdf567598a567b46338c925144c1b/propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", size = 240283, upload-time = "2025-03-26T03:04:10.172Z" },
- { url = "https://files.pythonhosted.org/packages/fa/c9/e85aeeeaae83358e2a1ef32d6ff50a483a5d5248bc38510d030a6f4e2816/propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", size = 232498, upload-time = "2025-03-26T03:04:11.616Z" },
- { url = "https://files.pythonhosted.org/packages/8e/66/acb88e1f30ef5536d785c283af2e62931cb934a56a3ecf39105887aa8905/propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", size = 221486, upload-time = "2025-03-26T03:04:13.102Z" },
- { url = "https://files.pythonhosted.org/packages/f5/f9/233ddb05ffdcaee4448508ee1d70aa7deff21bb41469ccdfcc339f871427/propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", size = 222675, upload-time = "2025-03-26T03:04:14.658Z" },
- { url = "https://files.pythonhosted.org/packages/98/b8/eb977e28138f9e22a5a789daf608d36e05ed93093ef12a12441030da800a/propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", size = 215727, upload-time = "2025-03-26T03:04:16.207Z" },
- { url = "https://files.pythonhosted.org/packages/89/2d/5f52d9c579f67b8ee1edd9ec073c91b23cc5b7ff7951a1e449e04ed8fdf3/propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", size = 217878, upload-time = "2025-03-26T03:04:18.11Z" },
- { url = "https://files.pythonhosted.org/packages/7a/fd/5283e5ed8a82b00c7a989b99bb6ea173db1ad750bf0bf8dff08d3f4a4e28/propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", size = 230558, upload-time = "2025-03-26T03:04:19.562Z" },
- { url = "https://files.pythonhosted.org/packages/90/38/ab17d75938ef7ac87332c588857422ae126b1c76253f0f5b1242032923ca/propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", size = 233754, upload-time = "2025-03-26T03:04:21.065Z" },
- { url = "https://files.pythonhosted.org/packages/06/5d/3b921b9c60659ae464137508d3b4c2b3f52f592ceb1964aa2533b32fcf0b/propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", size = 226088, upload-time = "2025-03-26T03:04:22.718Z" },
- { url = "https://files.pythonhosted.org/packages/54/6e/30a11f4417d9266b5a464ac5a8c5164ddc9dd153dfa77bf57918165eb4ae/propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", size = 40859, upload-time = "2025-03-26T03:04:24.039Z" },
- { url = "https://files.pythonhosted.org/packages/1d/3a/8a68dd867da9ca2ee9dfd361093e9cb08cb0f37e5ddb2276f1b5177d7731/propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", size = 45153, upload-time = "2025-03-26T03:04:25.211Z" },
- { url = "https://files.pythonhosted.org/packages/41/aa/ca78d9be314d1e15ff517b992bebbed3bdfef5b8919e85bf4940e57b6137/propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", size = 80430, upload-time = "2025-03-26T03:04:26.436Z" },
- { url = "https://files.pythonhosted.org/packages/1a/d8/f0c17c44d1cda0ad1979af2e593ea290defdde9eaeb89b08abbe02a5e8e1/propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", size = 46637, upload-time = "2025-03-26T03:04:27.932Z" },
- { url = "https://files.pythonhosted.org/packages/ae/bd/c1e37265910752e6e5e8a4c1605d0129e5b7933c3dc3cf1b9b48ed83b364/propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", size = 46123, upload-time = "2025-03-26T03:04:30.659Z" },
- { url = "https://files.pythonhosted.org/packages/d4/b0/911eda0865f90c0c7e9f0415d40a5bf681204da5fd7ca089361a64c16b28/propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", size = 243031, upload-time = "2025-03-26T03:04:31.977Z" },
- { url = "https://files.pythonhosted.org/packages/0a/06/0da53397c76a74271621807265b6eb61fb011451b1ddebf43213df763669/propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", size = 249100, upload-time = "2025-03-26T03:04:33.45Z" },
- { url = "https://files.pythonhosted.org/packages/f1/eb/13090e05bf6b963fc1653cdc922133ced467cb4b8dab53158db5a37aa21e/propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", size = 250170, upload-time = "2025-03-26T03:04:35.542Z" },
- { url = "https://files.pythonhosted.org/packages/3b/4c/f72c9e1022b3b043ec7dc475a0f405d4c3e10b9b1d378a7330fecf0652da/propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", size = 245000, upload-time = "2025-03-26T03:04:37.501Z" },
- { url = "https://files.pythonhosted.org/packages/e8/fd/970ca0e22acc829f1adf5de3724085e778c1ad8a75bec010049502cb3a86/propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", size = 230262, upload-time = "2025-03-26T03:04:39.532Z" },
- { url = "https://files.pythonhosted.org/packages/c4/42/817289120c6b9194a44f6c3e6b2c3277c5b70bbad39e7df648f177cc3634/propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", size = 236772, upload-time = "2025-03-26T03:04:41.109Z" },
- { url = "https://files.pythonhosted.org/packages/7c/9c/3b3942b302badd589ad6b672da3ca7b660a6c2f505cafd058133ddc73918/propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", size = 231133, upload-time = "2025-03-26T03:04:42.544Z" },
- { url = "https://files.pythonhosted.org/packages/98/a1/75f6355f9ad039108ff000dfc2e19962c8dea0430da9a1428e7975cf24b2/propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", size = 230741, upload-time = "2025-03-26T03:04:44.06Z" },
- { url = "https://files.pythonhosted.org/packages/67/0c/3e82563af77d1f8731132166da69fdfd95e71210e31f18edce08a1eb11ea/propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", size = 244047, upload-time = "2025-03-26T03:04:45.983Z" },
- { url = "https://files.pythonhosted.org/packages/f7/50/9fb7cca01532a08c4d5186d7bb2da6c4c587825c0ae134b89b47c7d62628/propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5", size = 246467, upload-time = "2025-03-26T03:04:47.699Z" },
- { url = "https://files.pythonhosted.org/packages/a9/02/ccbcf3e1c604c16cc525309161d57412c23cf2351523aedbb280eb7c9094/propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", size = 241022, upload-time = "2025-03-26T03:04:49.195Z" },
- { url = "https://files.pythonhosted.org/packages/db/19/e777227545e09ca1e77a6e21274ae9ec45de0f589f0ce3eca2a41f366220/propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", size = 40647, upload-time = "2025-03-26T03:04:50.595Z" },
- { url = "https://files.pythonhosted.org/packages/24/bb/3b1b01da5dd04c77a204c84e538ff11f624e31431cfde7201d9110b092b1/propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", size = 44784, upload-time = "2025-03-26T03:04:51.791Z" },
- { url = "https://files.pythonhosted.org/packages/58/60/f645cc8b570f99be3cf46714170c2de4b4c9d6b827b912811eff1eb8a412/propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", size = 77865, upload-time = "2025-03-26T03:04:53.406Z" },
- { url = "https://files.pythonhosted.org/packages/6f/d4/c1adbf3901537582e65cf90fd9c26fde1298fde5a2c593f987112c0d0798/propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", size = 45452, upload-time = "2025-03-26T03:04:54.624Z" },
- { url = "https://files.pythonhosted.org/packages/d1/b5/fe752b2e63f49f727c6c1c224175d21b7d1727ce1d4873ef1c24c9216830/propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", size = 44800, upload-time = "2025-03-26T03:04:55.844Z" },
- { url = "https://files.pythonhosted.org/packages/62/37/fc357e345bc1971e21f76597028b059c3d795c5ca7690d7a8d9a03c9708a/propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", size = 225804, upload-time = "2025-03-26T03:04:57.158Z" },
- { url = "https://files.pythonhosted.org/packages/0d/f1/16e12c33e3dbe7f8b737809bad05719cff1dccb8df4dafbcff5575002c0e/propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", size = 230650, upload-time = "2025-03-26T03:04:58.61Z" },
- { url = "https://files.pythonhosted.org/packages/3e/a2/018b9f2ed876bf5091e60153f727e8f9073d97573f790ff7cdf6bc1d1fb8/propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", size = 234235, upload-time = "2025-03-26T03:05:00.599Z" },
- { url = "https://files.pythonhosted.org/packages/45/5f/3faee66fc930dfb5da509e34c6ac7128870631c0e3582987fad161fcb4b1/propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", size = 228249, upload-time = "2025-03-26T03:05:02.11Z" },
- { url = "https://files.pythonhosted.org/packages/62/1e/a0d5ebda5da7ff34d2f5259a3e171a94be83c41eb1e7cd21a2105a84a02e/propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", size = 214964, upload-time = "2025-03-26T03:05:03.599Z" },
- { url = "https://files.pythonhosted.org/packages/db/a0/d72da3f61ceab126e9be1f3bc7844b4e98c6e61c985097474668e7e52152/propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", size = 222501, upload-time = "2025-03-26T03:05:05.107Z" },
- { url = "https://files.pythonhosted.org/packages/18/6d/a008e07ad7b905011253adbbd97e5b5375c33f0b961355ca0a30377504ac/propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", size = 217917, upload-time = "2025-03-26T03:05:06.59Z" },
- { url = "https://files.pythonhosted.org/packages/98/37/02c9343ffe59e590e0e56dc5c97d0da2b8b19fa747ebacf158310f97a79a/propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", size = 217089, upload-time = "2025-03-26T03:05:08.1Z" },
- { url = "https://files.pythonhosted.org/packages/53/1b/d3406629a2c8a5666d4674c50f757a77be119b113eedd47b0375afdf1b42/propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", size = 228102, upload-time = "2025-03-26T03:05:09.982Z" },
- { url = "https://files.pythonhosted.org/packages/cd/a7/3664756cf50ce739e5f3abd48febc0be1a713b1f389a502ca819791a6b69/propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", size = 230122, upload-time = "2025-03-26T03:05:11.408Z" },
- { url = "https://files.pythonhosted.org/packages/35/36/0bbabaacdcc26dac4f8139625e930f4311864251276033a52fd52ff2a274/propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", size = 226818, upload-time = "2025-03-26T03:05:12.909Z" },
- { url = "https://files.pythonhosted.org/packages/cc/27/4e0ef21084b53bd35d4dae1634b6d0bad35e9c58ed4f032511acca9d4d26/propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", size = 40112, upload-time = "2025-03-26T03:05:14.289Z" },
- { url = "https://files.pythonhosted.org/packages/a6/2c/a54614d61895ba6dd7ac8f107e2b2a0347259ab29cbf2ecc7b94fa38c4dc/propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", size = 44034, upload-time = "2025-03-26T03:05:15.616Z" },
- { url = "https://files.pythonhosted.org/packages/5a/a8/0a4fd2f664fc6acc66438370905124ce62e84e2e860f2557015ee4a61c7e/propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", size = 82613, upload-time = "2025-03-26T03:05:16.913Z" },
- { url = "https://files.pythonhosted.org/packages/4d/e5/5ef30eb2cd81576256d7b6caaa0ce33cd1d2c2c92c8903cccb1af1a4ff2f/propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", size = 47763, upload-time = "2025-03-26T03:05:18.607Z" },
- { url = "https://files.pythonhosted.org/packages/87/9a/87091ceb048efeba4d28e903c0b15bcc84b7c0bf27dc0261e62335d9b7b8/propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", size = 47175, upload-time = "2025-03-26T03:05:19.85Z" },
- { url = "https://files.pythonhosted.org/packages/3e/2f/854e653c96ad1161f96194c6678a41bbb38c7947d17768e8811a77635a08/propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", size = 292265, upload-time = "2025-03-26T03:05:21.654Z" },
- { url = "https://files.pythonhosted.org/packages/40/8d/090955e13ed06bc3496ba4a9fb26c62e209ac41973cb0d6222de20c6868f/propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", size = 294412, upload-time = "2025-03-26T03:05:23.147Z" },
- { url = "https://files.pythonhosted.org/packages/39/e6/d51601342e53cc7582449e6a3c14a0479fab2f0750c1f4d22302e34219c6/propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", size = 294290, upload-time = "2025-03-26T03:05:24.577Z" },
- { url = "https://files.pythonhosted.org/packages/3b/4d/be5f1a90abc1881884aa5878989a1acdafd379a91d9c7e5e12cef37ec0d7/propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", size = 282926, upload-time = "2025-03-26T03:05:26.459Z" },
- { url = "https://files.pythonhosted.org/packages/57/2b/8f61b998c7ea93a2b7eca79e53f3e903db1787fca9373af9e2cf8dc22f9d/propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", size = 267808, upload-time = "2025-03-26T03:05:28.188Z" },
- { url = "https://files.pythonhosted.org/packages/11/1c/311326c3dfce59c58a6098388ba984b0e5fb0381ef2279ec458ef99bd547/propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", size = 290916, upload-time = "2025-03-26T03:05:29.757Z" },
- { url = "https://files.pythonhosted.org/packages/4b/74/91939924b0385e54dc48eb2e4edd1e4903ffd053cf1916ebc5347ac227f7/propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", size = 262661, upload-time = "2025-03-26T03:05:31.472Z" },
- { url = "https://files.pythonhosted.org/packages/c2/d7/e6079af45136ad325c5337f5dd9ef97ab5dc349e0ff362fe5c5db95e2454/propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", size = 264384, upload-time = "2025-03-26T03:05:32.984Z" },
- { url = "https://files.pythonhosted.org/packages/b7/d5/ba91702207ac61ae6f1c2da81c5d0d6bf6ce89e08a2b4d44e411c0bbe867/propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", size = 291420, upload-time = "2025-03-26T03:05:34.496Z" },
- { url = "https://files.pythonhosted.org/packages/58/70/2117780ed7edcd7ba6b8134cb7802aada90b894a9810ec56b7bb6018bee7/propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", size = 290880, upload-time = "2025-03-26T03:05:36.256Z" },
- { url = "https://files.pythonhosted.org/packages/4a/1f/ecd9ce27710021ae623631c0146719280a929d895a095f6d85efb6a0be2e/propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", size = 287407, upload-time = "2025-03-26T03:05:37.799Z" },
- { url = "https://files.pythonhosted.org/packages/3e/66/2e90547d6b60180fb29e23dc87bd8c116517d4255240ec6d3f7dc23d1926/propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", size = 42573, upload-time = "2025-03-26T03:05:39.193Z" },
- { url = "https://files.pythonhosted.org/packages/cb/8f/50ad8599399d1861b4d2b6b45271f0ef6af1b09b0a2386a46dbaf19c9535/propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", size = 46757, upload-time = "2025-03-26T03:05:40.811Z" },
- { url = "https://files.pythonhosted.org/packages/b8/d3/c3cb8f1d6ae3b37f83e1de806713a9b3642c5895f0215a62e1a4bd6e5e34/propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", size = 12376, upload-time = "2025-03-26T03:06:10.5Z" },
-]
-
-[[package]]
-name = "pycodestyle"
-version = "2.14.0"
+name = "py-cpuinfo"
+version = "9.0.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783", size = 39472, upload-time = "2025-06-20T18:49:48.75Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d", size = 31594, upload-time = "2025-06-20T18:49:47.491Z" },
-]
-
-[[package]]
-name = "pyflakes"
-version = "3.4.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/45/dc/fd034dc20b4b264b3d015808458391acbf9df40b1e54750ef175d39180b1/pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58", size = 64669, upload-time = "2025-06-20T18:45:27.834Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" },
]
[[package]]
@@ -848,6 +498,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" },
]
+[[package]]
+name = "pytest-benchmark"
+version = "5.2.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "py-cpuinfo" },
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/24/34/9f732b76456d64faffbef6232f1f9dbec7a7c4999ff46282fa418bd1af66/pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779", size = 341340, upload-time = "2025-11-09T18:48:43.215Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/33/29/e756e715a48959f1c0045342088d7ca9762a2f509b945f362a316e9412b7/pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803", size = 45255, upload-time = "2025-11-09T18:48:39.765Z" },
+]
+
[[package]]
name = "pytest-cov"
version = "7.1.0"
@@ -862,6 +525,31 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" },
]
+[[package]]
+name = "pytest-json-report"
+version = "1.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+ { name = "pytest-metadata" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4f/d3/765dae9712fcd68d820338908c1337e077d5fdadccd5cacf95b9b0bea278/pytest-json-report-1.5.0.tar.gz", hash = "sha256:2dde3c647851a19b5f3700729e8310a6e66efb2077d674f27ddea3d34dc615de", size = 21241, upload-time = "2022-03-15T21:03:10.2Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/35/d07400c715bf8a88aa0c1ee9c9eb6050ca7fe5b39981f0eea773feeb0681/pytest_json_report-1.5.0-py3-none-any.whl", hash = "sha256:9897b68c910b12a2e48dd849f9a284b2c79a732a8a9cb398452ddd23d3c8c325", size = 13222, upload-time = "2022-03-15T21:03:08.65Z" },
+]
+
+[[package]]
+name = "pytest-metadata"
+version = "3.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a6/85/8c969f8bec4e559f8f2b958a15229a35495f5b4ce499f6b865eac54b878d/pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8", size = 9952, upload-time = "2024-02-12T19:38:44.887Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/43/7e7b2ec865caa92f67b8f0e9231a798d102724ca4c0e1f414316be1c1ef2/pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", size = 11428, upload-time = "2024-02-12T19:38:42.531Z" },
+]
+
[[package]]
name = "python-discovery"
version = "1.2.2"
@@ -931,32 +619,15 @@ wheels = [
]
[[package]]
-name = "requests"
-version = "2.34.2"
+name = "respx"
+version = "0.23.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "certifi" },
- { name = "charset-normalizer" },
- { name = "idna" },
- { name = "urllib3" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
-]
-
-[[package]]
-name = "responses"
-version = "0.26.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "pyyaml" },
- { name = "requests" },
- { name = "urllib3" },
+ { name = "httpx" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f0/1a/4af3e6d659394b809838490b144e4ab8d7ed3b9fecc7ca78f5d2f79b1a3d/responses-0.26.2.tar.gz", hash = "sha256:9c9259b46a8349197edebf43cfa68a87e1a2802ef503ff8b2fecbabc0b45afd8", size = 84030, upload-time = "2026-07-03T16:44:50.325Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/98/4e55c9c486404ec12373708d015ebce157966965a5ebe7f28ff2c784d41b/respx-0.23.1.tar.gz", hash = "sha256:242dcc6ce6b5b9bf621f5870c82a63997e8e82bc7c947f9ffe272b8f3dd5a780", size = 29243, upload-time = "2026-04-08T14:37:16.008Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl", hash = "sha256:6fdfeabd58e5ec473b98dfe02e6d46d3173bd8dd573eff2ccccf1a05a5135364", size = 35609, upload-time = "2026-07-03T16:44:49.1Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/4a/221da6ca167db45693d8d26c7dc79ccfc978a440251bf6721c9aaf251ac0/respx-0.23.1-py2.py3-none-any.whl", hash = "sha256:b18004b029935384bccfa6d7d9d74b4ec9af73a081cc28600fffc0447f4b8c1a", size = 25557, upload-time = "2026-04-08T14:37:14.613Z" },
]
[[package]]
@@ -984,6 +655,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
]
+[[package]]
+name = "sortedcontainers"
+version = "2.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
+]
+
[[package]]
name = "tomli"
version = "2.4.1"
@@ -1060,15 +740,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" },
]
-[[package]]
-name = "urllib3"
-version = "2.7.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
-]
-
[[package]]
name = "virtualenv"
version = "21.3.0"
@@ -1083,85 +754,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/3f/8b/6331f7a7fe70131c3
wheels = [
{ url = "https://files.pythonhosted.org/packages/4b/eb/03bfb1299d4c4510329e470f13f9a4ce793df7fcb5a2fd3510f911066f61/virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7", size = 7594690, upload-time = "2026-04-27T17:05:55.468Z" },
]
-
-[[package]]
-name = "yarl"
-version = "1.20.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "idna" },
- { name = "multidict" },
- { name = "propcache" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/62/51/c0edba5219027f6eab262e139f73e2417b0f4efffa23bf562f6e18f76ca5/yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307", size = 185258, upload-time = "2025-04-17T00:45:14.661Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/60/82/a59d8e21b20ffc836775fa7daedac51d16bb8f3010c4fcb495c4496aa922/yarl-1.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdb5204d17cb32b2de2d1e21c7461cabfacf17f3645e4b9039f210c5d3378bf3", size = 145178, upload-time = "2025-04-17T00:42:04.511Z" },
- { url = "https://files.pythonhosted.org/packages/ba/81/315a3f6f95947cfbf37c92d6fbce42a1a6207b6c38e8c2b452499ec7d449/yarl-1.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eaddd7804d8e77d67c28d154ae5fab203163bd0998769569861258e525039d2a", size = 96859, upload-time = "2025-04-17T00:42:06.43Z" },
- { url = "https://files.pythonhosted.org/packages/ad/17/9b64e575583158551b72272a1023cdbd65af54fe13421d856b2850a6ddb7/yarl-1.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:634b7ba6b4a85cf67e9df7c13a7fb2e44fa37b5d34501038d174a63eaac25ee2", size = 94647, upload-time = "2025-04-17T00:42:07.976Z" },
- { url = "https://files.pythonhosted.org/packages/2c/29/8f291e7922a58a21349683f6120a85701aeefaa02e9f7c8a2dc24fe3f431/yarl-1.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d409e321e4addf7d97ee84162538c7258e53792eb7c6defd0c33647d754172e", size = 355788, upload-time = "2025-04-17T00:42:09.902Z" },
- { url = "https://files.pythonhosted.org/packages/26/6d/b4892c80b805c42c228c6d11e03cafabf81662d371b0853e7f0f513837d5/yarl-1.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ea52f7328a36960ba3231c6677380fa67811b414798a6e071c7085c57b6d20a9", size = 344613, upload-time = "2025-04-17T00:42:11.768Z" },
- { url = "https://files.pythonhosted.org/packages/d7/0e/517aa28d3f848589bae9593717b063a544b86ba0a807d943c70f48fcf3bb/yarl-1.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8703517b924463994c344dcdf99a2d5ce9eca2b6882bb640aa555fb5efc706a", size = 370953, upload-time = "2025-04-17T00:42:13.983Z" },
- { url = "https://files.pythonhosted.org/packages/5f/9b/5bd09d2f1ad6e6f7c2beae9e50db78edd2cca4d194d227b958955573e240/yarl-1.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:077989b09ffd2f48fb2d8f6a86c5fef02f63ffe6b1dd4824c76de7bb01e4f2e2", size = 369204, upload-time = "2025-04-17T00:42:16.386Z" },
- { url = "https://files.pythonhosted.org/packages/9c/85/d793a703cf4bd0d4cd04e4b13cc3d44149470f790230430331a0c1f52df5/yarl-1.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0acfaf1da020253f3533526e8b7dd212838fdc4109959a2c53cafc6db611bff2", size = 358108, upload-time = "2025-04-17T00:42:18.622Z" },
- { url = "https://files.pythonhosted.org/packages/6f/54/b6c71e13549c1f6048fbc14ce8d930ac5fb8bafe4f1a252e621a24f3f1f9/yarl-1.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4230ac0b97ec5eeb91d96b324d66060a43fd0d2a9b603e3327ed65f084e41f8", size = 346610, upload-time = "2025-04-17T00:42:20.9Z" },
- { url = "https://files.pythonhosted.org/packages/a0/1a/d6087d58bdd0d8a2a37bbcdffac9d9721af6ebe50d85304d9f9b57dfd862/yarl-1.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6a1e6ae21cdd84011c24c78d7a126425148b24d437b5702328e4ba640a8902", size = 365378, upload-time = "2025-04-17T00:42:22.926Z" },
- { url = "https://files.pythonhosted.org/packages/02/84/e25ddff4cbc001dbc4af76f8d41a3e23818212dd1f0a52044cbc60568872/yarl-1.20.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:86de313371ec04dd2531f30bc41a5a1a96f25a02823558ee0f2af0beaa7ca791", size = 356919, upload-time = "2025-04-17T00:42:25.145Z" },
- { url = "https://files.pythonhosted.org/packages/04/76/898ae362353bf8f64636495d222c8014c8e5267df39b1a9fe1e1572fb7d0/yarl-1.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dd59c9dd58ae16eaa0f48c3d0cbe6be8ab4dc7247c3ff7db678edecbaf59327f", size = 364248, upload-time = "2025-04-17T00:42:27.475Z" },
- { url = "https://files.pythonhosted.org/packages/1b/b0/9d9198d83a622f1c40fdbf7bd13b224a6979f2e1fc2cf50bfb1d8773c495/yarl-1.20.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a0bc5e05f457b7c1994cc29e83b58f540b76234ba6b9648a4971ddc7f6aa52da", size = 378418, upload-time = "2025-04-17T00:42:29.333Z" },
- { url = "https://files.pythonhosted.org/packages/c7/ce/1f50c1cc594cf5d3f5bf4a9b616fca68680deaec8ad349d928445ac52eb8/yarl-1.20.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c9471ca18e6aeb0e03276b5e9b27b14a54c052d370a9c0c04a68cefbd1455eb4", size = 383850, upload-time = "2025-04-17T00:42:31.668Z" },
- { url = "https://files.pythonhosted.org/packages/89/1e/a59253a87b35bfec1a25bb5801fb69943330b67cfd266278eb07e0609012/yarl-1.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40ed574b4df723583a26c04b298b283ff171bcc387bc34c2683235e2487a65a5", size = 381218, upload-time = "2025-04-17T00:42:33.523Z" },
- { url = "https://files.pythonhosted.org/packages/85/b0/26f87df2b3044b0ef1a7cf66d321102bdca091db64c5ae853fcb2171c031/yarl-1.20.0-cp311-cp311-win32.whl", hash = "sha256:db243357c6c2bf3cd7e17080034ade668d54ce304d820c2a58514a4e51d0cfd6", size = 86606, upload-time = "2025-04-17T00:42:35.873Z" },
- { url = "https://files.pythonhosted.org/packages/33/46/ca335c2e1f90446a77640a45eeb1cd8f6934f2c6e4df7db0f0f36ef9f025/yarl-1.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c12cd754d9dbd14204c328915e23b0c361b88f3cffd124129955e60a4fbfcfb", size = 93374, upload-time = "2025-04-17T00:42:37.586Z" },
- { url = "https://files.pythonhosted.org/packages/c3/e8/3efdcb83073df978bb5b1a9cc0360ce596680e6c3fac01f2a994ccbb8939/yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f", size = 147089, upload-time = "2025-04-17T00:42:39.602Z" },
- { url = "https://files.pythonhosted.org/packages/60/c3/9e776e98ea350f76f94dd80b408eaa54e5092643dbf65fd9babcffb60509/yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e", size = 97706, upload-time = "2025-04-17T00:42:41.469Z" },
- { url = "https://files.pythonhosted.org/packages/0c/5b/45cdfb64a3b855ce074ae607b9fc40bc82e7613b94e7612b030255c93a09/yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e", size = 95719, upload-time = "2025-04-17T00:42:43.666Z" },
- { url = "https://files.pythonhosted.org/packages/2d/4e/929633b249611eeed04e2f861a14ed001acca3ef9ec2a984a757b1515889/yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33", size = 343972, upload-time = "2025-04-17T00:42:45.391Z" },
- { url = "https://files.pythonhosted.org/packages/49/fd/047535d326c913f1a90407a3baf7ff535b10098611eaef2c527e32e81ca1/yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58", size = 339639, upload-time = "2025-04-17T00:42:47.552Z" },
- { url = "https://files.pythonhosted.org/packages/48/2f/11566f1176a78f4bafb0937c0072410b1b0d3640b297944a6a7a556e1d0b/yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f", size = 353745, upload-time = "2025-04-17T00:42:49.406Z" },
- { url = "https://files.pythonhosted.org/packages/26/17/07dfcf034d6ae8837b33988be66045dd52f878dfb1c4e8f80a7343f677be/yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae", size = 354178, upload-time = "2025-04-17T00:42:51.588Z" },
- { url = "https://files.pythonhosted.org/packages/15/45/212604d3142d84b4065d5f8cab6582ed3d78e4cc250568ef2a36fe1cf0a5/yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018", size = 349219, upload-time = "2025-04-17T00:42:53.674Z" },
- { url = "https://files.pythonhosted.org/packages/e6/e0/a10b30f294111c5f1c682461e9459935c17d467a760c21e1f7db400ff499/yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672", size = 337266, upload-time = "2025-04-17T00:42:55.49Z" },
- { url = "https://files.pythonhosted.org/packages/33/a6/6efa1d85a675d25a46a167f9f3e80104cde317dfdf7f53f112ae6b16a60a/yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8", size = 360873, upload-time = "2025-04-17T00:42:57.895Z" },
- { url = "https://files.pythonhosted.org/packages/77/67/c8ab718cb98dfa2ae9ba0f97bf3cbb7d45d37f13fe1fbad25ac92940954e/yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7", size = 360524, upload-time = "2025-04-17T00:43:00.094Z" },
- { url = "https://files.pythonhosted.org/packages/bd/e8/c3f18660cea1bc73d9f8a2b3ef423def8dadbbae6c4afabdb920b73e0ead/yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594", size = 365370, upload-time = "2025-04-17T00:43:02.242Z" },
- { url = "https://files.pythonhosted.org/packages/c9/99/33f3b97b065e62ff2d52817155a89cfa030a1a9b43fee7843ef560ad9603/yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6", size = 373297, upload-time = "2025-04-17T00:43:04.189Z" },
- { url = "https://files.pythonhosted.org/packages/3d/89/7519e79e264a5f08653d2446b26d4724b01198a93a74d2e259291d538ab1/yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1", size = 378771, upload-time = "2025-04-17T00:43:06.609Z" },
- { url = "https://files.pythonhosted.org/packages/3a/58/6c460bbb884abd2917c3eef6f663a4a873f8dc6f498561fc0ad92231c113/yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b", size = 375000, upload-time = "2025-04-17T00:43:09.01Z" },
- { url = "https://files.pythonhosted.org/packages/3b/2a/dd7ed1aa23fea996834278d7ff178f215b24324ee527df53d45e34d21d28/yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64", size = 86355, upload-time = "2025-04-17T00:43:11.311Z" },
- { url = "https://files.pythonhosted.org/packages/ca/c6/333fe0338305c0ac1c16d5aa7cc4841208d3252bbe62172e0051006b5445/yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c", size = 92904, upload-time = "2025-04-17T00:43:13.087Z" },
- { url = "https://files.pythonhosted.org/packages/0f/6f/514c9bff2900c22a4f10e06297714dbaf98707143b37ff0bcba65a956221/yarl-1.20.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2137810a20b933b1b1b7e5cf06a64c3ed3b4747b0e5d79c9447c00db0e2f752f", size = 145030, upload-time = "2025-04-17T00:43:15.083Z" },
- { url = "https://files.pythonhosted.org/packages/4e/9d/f88da3fa319b8c9c813389bfb3463e8d777c62654c7168e580a13fadff05/yarl-1.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:447c5eadd750db8389804030d15f43d30435ed47af1313303ed82a62388176d3", size = 96894, upload-time = "2025-04-17T00:43:17.372Z" },
- { url = "https://files.pythonhosted.org/packages/cd/57/92e83538580a6968b2451d6c89c5579938a7309d4785748e8ad42ddafdce/yarl-1.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42fbe577272c203528d402eec8bf4b2d14fd49ecfec92272334270b850e9cd7d", size = 94457, upload-time = "2025-04-17T00:43:19.431Z" },
- { url = "https://files.pythonhosted.org/packages/e9/ee/7ee43bd4cf82dddd5da97fcaddb6fa541ab81f3ed564c42f146c83ae17ce/yarl-1.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18e321617de4ab170226cd15006a565d0fa0d908f11f724a2c9142d6b2812ab0", size = 343070, upload-time = "2025-04-17T00:43:21.426Z" },
- { url = "https://files.pythonhosted.org/packages/4a/12/b5eccd1109e2097bcc494ba7dc5de156e41cf8309fab437ebb7c2b296ce3/yarl-1.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4345f58719825bba29895011e8e3b545e6e00257abb984f9f27fe923afca2501", size = 337739, upload-time = "2025-04-17T00:43:23.634Z" },
- { url = "https://files.pythonhosted.org/packages/7d/6b/0eade8e49af9fc2585552f63c76fa59ef469c724cc05b29519b19aa3a6d5/yarl-1.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d9b980d7234614bc4674468ab173ed77d678349c860c3af83b1fffb6a837ddc", size = 351338, upload-time = "2025-04-17T00:43:25.695Z" },
- { url = "https://files.pythonhosted.org/packages/45/cb/aaaa75d30087b5183c7b8a07b4fb16ae0682dd149a1719b3a28f54061754/yarl-1.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af4baa8a445977831cbaa91a9a84cc09debb10bc8391f128da2f7bd070fc351d", size = 353636, upload-time = "2025-04-17T00:43:27.876Z" },
- { url = "https://files.pythonhosted.org/packages/98/9d/d9cb39ec68a91ba6e66fa86d97003f58570327d6713833edf7ad6ce9dde5/yarl-1.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123393db7420e71d6ce40d24885a9e65eb1edefc7a5228db2d62bcab3386a5c0", size = 348061, upload-time = "2025-04-17T00:43:29.788Z" },
- { url = "https://files.pythonhosted.org/packages/72/6b/103940aae893d0cc770b4c36ce80e2ed86fcb863d48ea80a752b8bda9303/yarl-1.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab47acc9332f3de1b39e9b702d9c916af7f02656b2a86a474d9db4e53ef8fd7a", size = 334150, upload-time = "2025-04-17T00:43:31.742Z" },
- { url = "https://files.pythonhosted.org/packages/ef/b2/986bd82aa222c3e6b211a69c9081ba46484cffa9fab2a5235e8d18ca7a27/yarl-1.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4a34c52ed158f89876cba9c600b2c964dfc1ca52ba7b3ab6deb722d1d8be6df2", size = 362207, upload-time = "2025-04-17T00:43:34.099Z" },
- { url = "https://files.pythonhosted.org/packages/14/7c/63f5922437b873795d9422cbe7eb2509d4b540c37ae5548a4bb68fd2c546/yarl-1.20.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:04d8cfb12714158abf2618f792c77bc5c3d8c5f37353e79509608be4f18705c9", size = 361277, upload-time = "2025-04-17T00:43:36.202Z" },
- { url = "https://files.pythonhosted.org/packages/81/83/450938cccf732466953406570bdb42c62b5ffb0ac7ac75a1f267773ab5c8/yarl-1.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7dc63ad0d541c38b6ae2255aaa794434293964677d5c1ec5d0116b0e308031f5", size = 364990, upload-time = "2025-04-17T00:43:38.551Z" },
- { url = "https://files.pythonhosted.org/packages/b4/de/af47d3a47e4a833693b9ec8e87debb20f09d9fdc9139b207b09a3e6cbd5a/yarl-1.20.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d02b591a64e4e6ca18c5e3d925f11b559c763b950184a64cf47d74d7e41877", size = 374684, upload-time = "2025-04-17T00:43:40.481Z" },
- { url = "https://files.pythonhosted.org/packages/62/0b/078bcc2d539f1faffdc7d32cb29a2d7caa65f1a6f7e40795d8485db21851/yarl-1.20.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95fc9876f917cac7f757df80a5dda9de59d423568460fe75d128c813b9af558e", size = 382599, upload-time = "2025-04-17T00:43:42.463Z" },
- { url = "https://files.pythonhosted.org/packages/74/a9/4fdb1a7899f1fb47fd1371e7ba9e94bff73439ce87099d5dd26d285fffe0/yarl-1.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb769ae5760cd1c6a712135ee7915f9d43f11d9ef769cb3f75a23e398a92d384", size = 378573, upload-time = "2025-04-17T00:43:44.797Z" },
- { url = "https://files.pythonhosted.org/packages/fd/be/29f5156b7a319e4d2e5b51ce622b4dfb3aa8d8204cd2a8a339340fbfad40/yarl-1.20.0-cp313-cp313-win32.whl", hash = "sha256:70e0c580a0292c7414a1cead1e076c9786f685c1fc4757573d2967689b370e62", size = 86051, upload-time = "2025-04-17T00:43:47.076Z" },
- { url = "https://files.pythonhosted.org/packages/52/56/05fa52c32c301da77ec0b5f63d2d9605946fe29defacb2a7ebd473c23b81/yarl-1.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:4c43030e4b0af775a85be1fa0433119b1565673266a70bf87ef68a9d5ba3174c", size = 92742, upload-time = "2025-04-17T00:43:49.193Z" },
- { url = "https://files.pythonhosted.org/packages/d4/2f/422546794196519152fc2e2f475f0e1d4d094a11995c81a465faf5673ffd/yarl-1.20.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b6c4c3d0d6a0ae9b281e492b1465c72de433b782e6b5001c8e7249e085b69051", size = 163575, upload-time = "2025-04-17T00:43:51.533Z" },
- { url = "https://files.pythonhosted.org/packages/90/fc/67c64ddab6c0b4a169d03c637fb2d2a212b536e1989dec8e7e2c92211b7f/yarl-1.20.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8681700f4e4df891eafa4f69a439a6e7d480d64e52bf460918f58e443bd3da7d", size = 106121, upload-time = "2025-04-17T00:43:53.506Z" },
- { url = "https://files.pythonhosted.org/packages/6d/00/29366b9eba7b6f6baed7d749f12add209b987c4cfbfa418404dbadc0f97c/yarl-1.20.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:84aeb556cb06c00652dbf87c17838eb6d92cfd317799a8092cee0e570ee11229", size = 103815, upload-time = "2025-04-17T00:43:55.41Z" },
- { url = "https://files.pythonhosted.org/packages/28/f4/a2a4c967c8323c03689383dff73396281ced3b35d0ed140580825c826af7/yarl-1.20.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f166eafa78810ddb383e930d62e623d288fb04ec566d1b4790099ae0f31485f1", size = 408231, upload-time = "2025-04-17T00:43:57.825Z" },
- { url = "https://files.pythonhosted.org/packages/0f/a1/66f7ffc0915877d726b70cc7a896ac30b6ac5d1d2760613603b022173635/yarl-1.20.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5d3d6d14754aefc7a458261027a562f024d4f6b8a798adb472277f675857b1eb", size = 390221, upload-time = "2025-04-17T00:44:00.526Z" },
- { url = "https://files.pythonhosted.org/packages/41/15/cc248f0504610283271615e85bf38bc014224122498c2016d13a3a1b8426/yarl-1.20.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a8f64df8ed5d04c51260dbae3cc82e5649834eebea9eadfd829837b8093eb00", size = 411400, upload-time = "2025-04-17T00:44:02.853Z" },
- { url = "https://files.pythonhosted.org/packages/5c/af/f0823d7e092bfb97d24fce6c7269d67fcd1aefade97d0a8189c4452e4d5e/yarl-1.20.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9949eaf05b4d30e93e4034a7790634bbb41b8be2d07edd26754f2e38e491de", size = 411714, upload-time = "2025-04-17T00:44:04.904Z" },
- { url = "https://files.pythonhosted.org/packages/83/70/be418329eae64b9f1b20ecdaac75d53aef098797d4c2299d82ae6f8e4663/yarl-1.20.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c366b254082d21cc4f08f522ac201d0d83a8b8447ab562732931d31d80eb2a5", size = 404279, upload-time = "2025-04-17T00:44:07.721Z" },
- { url = "https://files.pythonhosted.org/packages/19/f5/52e02f0075f65b4914eb890eea1ba97e6fd91dd821cc33a623aa707b2f67/yarl-1.20.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91bc450c80a2e9685b10e34e41aef3d44ddf99b3a498717938926d05ca493f6a", size = 384044, upload-time = "2025-04-17T00:44:09.708Z" },
- { url = "https://files.pythonhosted.org/packages/6a/36/b0fa25226b03d3f769c68d46170b3e92b00ab3853d73127273ba22474697/yarl-1.20.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c2aa4387de4bc3a5fe158080757748d16567119bef215bec643716b4fbf53f9", size = 416236, upload-time = "2025-04-17T00:44:11.734Z" },
- { url = "https://files.pythonhosted.org/packages/cb/3a/54c828dd35f6831dfdd5a79e6c6b4302ae2c5feca24232a83cb75132b205/yarl-1.20.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d2cbca6760a541189cf87ee54ff891e1d9ea6406079c66341008f7ef6ab61145", size = 402034, upload-time = "2025-04-17T00:44:13.975Z" },
- { url = "https://files.pythonhosted.org/packages/10/97/c7bf5fba488f7e049f9ad69c1b8fdfe3daa2e8916b3d321aa049e361a55a/yarl-1.20.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:798a5074e656f06b9fad1a162be5a32da45237ce19d07884d0b67a0aa9d5fdda", size = 407943, upload-time = "2025-04-17T00:44:16.052Z" },
- { url = "https://files.pythonhosted.org/packages/fd/a4/022d2555c1e8fcff08ad7f0f43e4df3aba34f135bff04dd35d5526ce54ab/yarl-1.20.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f106e75c454288472dbe615accef8248c686958c2e7dd3b8d8ee2669770d020f", size = 423058, upload-time = "2025-04-17T00:44:18.547Z" },
- { url = "https://files.pythonhosted.org/packages/4c/f6/0873a05563e5df29ccf35345a6ae0ac9e66588b41fdb7043a65848f03139/yarl-1.20.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3b60a86551669c23dc5445010534d2c5d8a4e012163218fc9114e857c0586fdd", size = 423792, upload-time = "2025-04-17T00:44:20.639Z" },
- { url = "https://files.pythonhosted.org/packages/9e/35/43fbbd082708fa42e923f314c24f8277a28483d219e049552e5007a9aaca/yarl-1.20.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e429857e341d5e8e15806118e0294f8073ba9c4580637e59ab7b238afca836f", size = 422242, upload-time = "2025-04-17T00:44:22.851Z" },
- { url = "https://files.pythonhosted.org/packages/ed/f7/f0f2500cf0c469beb2050b522c7815c575811627e6d3eb9ec7550ddd0bfe/yarl-1.20.0-cp313-cp313t-win32.whl", hash = "sha256:65a4053580fe88a63e8e4056b427224cd01edfb5f951498bfefca4052f0ce0ac", size = 93816, upload-time = "2025-04-17T00:44:25.491Z" },
- { url = "https://files.pythonhosted.org/packages/3f/93/f73b61353b2a699d489e782c3f5998b59f974ec3156a2050a52dfd7e8946/yarl-1.20.0-cp313-cp313t-win_amd64.whl", hash = "sha256:53b2da3a6ca0a541c1ae799c349788d480e5144cac47dba0266c7cb6c76151fe", size = 101093, upload-time = "2025-04-17T00:44:27.418Z" },
- { url = "https://files.pythonhosted.org/packages/ea/1f/70c57b3d7278e94ed22d85e09685d3f0a38ebdd8c5c73b65ba4c0d0fe002/yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124", size = 46124, upload-time = "2025-04-17T00:45:12.199Z" },
-]