diff --git a/docs/generation-report.md b/docs/generation-report.md index e7964ad..d9a22bc 100644 --- a/docs/generation-report.md +++ b/docs/generation-report.md @@ -1,5 +1,11 @@ # Generation Report +## 2026-05-27 | Library v3.1.0b3 | API 1.70.0-beta.3 + + +No Python keyword parameter conflicts detected. + + ## 2026-05-20 | Library v3.1.0b2 | API 1.70.0-beta.2 diff --git a/meraki/__init__.py b/meraki/__init__.py index ae7603a..77505a4 100644 --- a/meraki/__init__.py +++ b/meraki/__init__.py @@ -52,7 +52,7 @@ from meraki._version import __version__ # noqa: F401 from datetime import datetime -__api_version__ = "1.70.0-beta.2" +__api_version__ = "1.70.0-beta.3" __all__ = [ "APIError", diff --git a/meraki/_version.py b/meraki/_version.py index 0e91551..ae9bf83 100644 --- a/meraki/_version.py +++ b/meraki/_version.py @@ -1 +1 @@ -__version__ = "3.1.0b2" +__version__ = "3.1.0b3" diff --git a/meraki/aio/api/appliance.py b/meraki/aio/api/appliance.py index 728acb2..a6a6e85 100644 --- a/meraki/aio/api/appliance.py +++ b/meraki/aio/api/appliance.py @@ -40,10 +40,10 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs): kwargs.update(locals()) - if "speed" in kwargs: + 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: + 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}''' @@ -94,10 +94,10 @@ def updateDeviceApplianceInterfacesPort(self, serial: str, number: str, **kwargs kwargs.update(locals()) - if "speed" in kwargs: + 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: + 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}''' @@ -1282,6 +1282,7 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs): - 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()) @@ -1303,6 +1304,7 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs): "accessPolicy", "peerSgtCapable", "adaptivePolicyGroupId", + "sgt", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -2600,40 +2602,23 @@ def disableNetworkApplianceUmbrellaProtection(self, networkId: str): return self._session.delete(metadata, resource) - 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 excludeNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs): + def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs): """ **Specify one or more domain names to be excluded from being routed to Cisco Umbrella.** - https://developer.cisco.com/meraki/api-v1/#!exclude-network-appliance-umbrella-domains + https://developer.cisco.com/meraki/api-v1/#!exclusions-network-appliance-umbrella-domains - networkId (string): Network ID - - domains (array): Array of domain names + - domains (array): Domain names to exclude from Umbrella DNS routing (e.g., 'example.com', 'corp.example.org'). Standard FQDNs only — wildcards are not supported. Values are lowercased before saving. Each call replaces the full exclusion list. """ kwargs = locals() metadata = { - "tags": ["appliance", "configure", "umbrella"], - "operation": "excludeNetworkApplianceUmbrellaDomains", + "tags": ["appliance", "configure", "umbrella", "domains"], + "operation": "exclusionsNetworkApplianceUmbrellaDomains", } networkId = urllib.parse.quote(str(networkId), safe="") - resource = f"/networks/{networkId}/appliance/umbrella/excludeDomains" + resource = f"/networks/{networkId}/appliance/umbrella/domains/exclusions" body_params = [ "domains", @@ -2645,11 +2630,28 @@ def excludeNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning( - f"excludeNetworkApplianceUmbrellaDomains: ignoring unrecognized kwargs: {invalid}" + f"exclusionsNetworkApplianceUmbrellaDomains: ignoring unrecognized kwargs: {invalid}" ) 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.** @@ -2683,7 +2685,7 @@ def policiesNetworkApplianceUmbrella(self, networkId: str, policyIds: list, **kw def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs): """ - **Add one umbrella policy to your network.** + **Add one Cisco Umbrella DNS security policy to an MX network by policy ID** https://developer.cisco.com/meraki/api-v1/#!add-network-appliance-umbrella-policies - networkId (string): Network ID @@ -2714,7 +2716,7 @@ def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kw def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs): """ - **Remove one umbrella policy from your network.** + **Remove one Cisco Umbrella DNS security policy from an MX network by policy ID** https://developer.cisco.com/meraki/api-v1/#!remove-network-appliance-umbrella-policies - networkId (string): Network ID @@ -2745,13 +2747,13 @@ def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, * return self._session.post(metadata, resource, payload) - def protectionNetworkApplianceUmbrella(self, networkId: str, enable: bool, **kwargs): + def protectionNetworkApplianceUmbrella(self, networkId: str, enabled: bool, **kwargs): """ - **Enable or disable umbrella protection for an MX network** + **Enable or disable umbrella protection for an appliance network** https://developer.cisco.com/meraki/api-v1/#!protection-network-appliance-umbrella - networkId (string): Network ID - - enable (boolean): Enable or disable umbrella protection + - enabled (boolean): Enable or disable umbrella protection """ kwargs = locals() @@ -2764,7 +2766,7 @@ def protectionNetworkApplianceUmbrella(self, networkId: str, enable: bool, **kwa resource = f"/networks/{networkId}/appliance/umbrella/protection" body_params = [ - "enable", + "enabled", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -2887,6 +2889,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg - 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. """ @@ -2935,6 +2938,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg "dhcpBootFilename", "dhcpOptions", "adaptivePolicyGroupId", + "sgt", "vrf", "uplinks", ] @@ -3043,6 +3047,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs): - 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. """ @@ -3095,6 +3100,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs): "ipv6", "mandatoryDhcp", "adaptivePolicyGroupId", + "sgt", "vrf", "uplinks", ] @@ -3245,6 +3251,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw - 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 """ @@ -3267,6 +3274,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw "hubs", "subnets", "peerSgtCapable", + "sgt", "subnet", "hostTranslations", ] @@ -3451,6 +3459,71 @@ def getOrganizationApplianceDevicesInterfacesPortsByDevice(self, organizationId: return self._session.get(metadata, resource, params) + def getOrganizationApplianceDevicesPortsTransceiversReadingsHistoryByDevice( + self, organizationId: str, total_pages=1, direction="next", **kwargs + ): + """ + **Return time-series digital optical monitoring (DOM) readings for ports on each DOM-enabled Catalyst appliance in an organization.** + https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-devices-ports-transceivers-readings-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 + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10. 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. + - 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 appliance serial. + - portIds (array): Optional parameter to filter usage by port ID. + """ + + kwargs.update(locals()) + + metadata = { + "tags": ["appliance", "monitor", "devices", "ports", "transceivers", "readings", "history", "byDevice"], + "operation": "getOrganizationApplianceDevicesPortsTransceiversReadingsHistoryByDevice", + } + organizationId = urllib.parse.quote(str(organizationId), safe="") + resource = f"/organizations/{organizationId}/appliance/devices/ports/transceivers/readings/history/byDevice" + + 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"getOrganizationApplianceDevicesPortsTransceiversReadingsHistoryByDevice: ignoring unrecognized kwargs: {invalid}" + ) + + return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApplianceDevicesRedundancyByNetwork( self, organizationId: str, total_pages=1, direction="next", **kwargs ): @@ -4229,6 +4302,66 @@ def getOrganizationApplianceFirewallMulticastForwardingByNetwork( return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApplianceInterfacesPacketsOverviewsByDevice( + self, organizationId: str, total_pages=1, direction="next", **kwargs + ): + """ + **Returns packet counter overviews for all interfaces on Secure Routers in the organization, including totals and average rates by packet type over the requested timespan.** + https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-interfaces-packets-overviews-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 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 1 day. + - 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. + - networkIds (array): Optional parameter to filter Secure Routers in the provided networks + - serials (array): Optional parameter to filter Secure Routers by their serial numbers + """ + + kwargs.update(locals()) + + metadata = { + "tags": ["appliance", "monitor", "interfaces", "packets", "overviews", "byDevice"], + "operation": "getOrganizationApplianceInterfacesPacketsOverviewsByDevice", + } + organizationId = urllib.parse.quote(str(organizationId), safe="") + resource = f"/organizations/{organizationId}/appliance/interfaces/packets/overviews/byDevice" + + 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"getOrganizationApplianceInterfacesPacketsOverviewsByDevice: ignoring unrecognized kwargs: {invalid}" + ) + + return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApplianceRoutingVrfsSettings(self, organizationId: str): """ **Return the VRF setting for an organization.** diff --git a/meraki/aio/api/campusGateway.py b/meraki/aio/api/campusGateway.py index 2f602c1..90e053a 100644 --- a/meraki/aio/api/campusGateway.py +++ b/meraki/aio/api/campusGateway.py @@ -408,6 +408,7 @@ def getOrganizationCampusGatewayClustersNetworksOverviews( - 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'. @@ -440,6 +441,7 @@ def getOrganizationCampusGatewayClustersNetworksOverviews( "clusterIds", "siteIds", "networkIds", + "tunnelingSources", "search", "sortBy", "sortOrder", @@ -453,6 +455,7 @@ def getOrganizationCampusGatewayClustersNetworksOverviews( "clusterIds", "siteIds", "networkIds", + "tunnelingSources", ] for k, v in kwargs.items(): if k.strip() in array_params: diff --git a/meraki/aio/api/devices.py b/meraki/aio/api/devices.py index 3d4f22a..1b77816 100644 --- a/meraki/aio/api/devices.py +++ b/meraki/aio/api/devices.py @@ -862,25 +862,27 @@ def getDeviceLiveToolsPingDevice(self, serial: str, id: str): return self._session.get(metadata, resource) - def createDeviceLiveToolsPortStatus(self, serial: str, **kwargs): + def createDeviceLiveToolsPortsCycle(self, serial: str, ports: list, **kwargs): """ - **Enqueue a job to retrieve port status for a device** - https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-port-status + **Enqueue a job to perform a cycle port for the device on the specified ports** + https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-cycle - serial (string): Serial + - ports (array): A list of ports to cycle. For Catalyst switches, IOS interface names are also supported, such as "GigabitEthernet1/0/8", "Gi1/0/8", or even "1/0/8". - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret """ kwargs.update(locals()) metadata = { - "tags": ["devices", "liveTools", "portStatus"], - "operation": "createDeviceLiveToolsPortStatus", + "tags": ["devices", "liveTools", "ports", "cycle"], + "operation": "createDeviceLiveToolsPortsCycle", } serial = urllib.parse.quote(str(serial), safe="") - resource = f"/devices/{serial}/liveTools/portStatus" + resource = f"/devices/{serial}/liveTools/ports/cycle" body_params = [ + "ports", "callback", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -889,50 +891,48 @@ def createDeviceLiveToolsPortStatus(self, serial: 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"createDeviceLiveToolsPortStatus: ignoring unrecognized kwargs: {invalid}") + self._session._logger.warning(f"createDeviceLiveToolsPortsCycle: ignoring unrecognized kwargs: {invalid}") return self._session.post(metadata, resource, payload) - def getDeviceLiveToolsPortStatus(self, serial: str, portStatusId: str): + def getDeviceLiveToolsPortsCycle(self, serial: str, id: str): """ - **Return a port status live tool job.** - https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-port-status + **Return a cycle port live tool job.** + https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ports-cycle - serial (string): Serial - - portStatusId (string): Port status ID + - id (string): ID """ metadata = { - "tags": ["devices", "liveTools", "portStatus"], - "operation": "getDeviceLiveToolsPortStatus", + "tags": ["devices", "liveTools", "ports", "cycle"], + "operation": "getDeviceLiveToolsPortsCycle", } serial = urllib.parse.quote(str(serial), safe="") - portStatusId = urllib.parse.quote(str(portStatusId), safe="") - resource = f"/devices/{serial}/liveTools/portStatus/{portStatusId}" + id = urllib.parse.quote(str(id), safe="") + resource = f"/devices/{serial}/liveTools/ports/cycle/{id}" return self._session.get(metadata, resource) - def createDeviceLiveToolsPortsCycle(self, serial: str, ports: list, **kwargs): + def createDeviceLiveToolsPortsStatus(self, serial: str, **kwargs): """ - **Enqueue a job to perform a cycle port for the device on the specified ports** - https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-cycle + **Enqueue a job to retrieve port status for a device** + https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-status - serial (string): Serial - - ports (array): A list of ports to cycle. For Catalyst switches, IOS interface names are also supported, such as "GigabitEthernet1/0/8", "Gi1/0/8", or even "1/0/8". - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret """ kwargs.update(locals()) metadata = { - "tags": ["devices", "liveTools", "ports", "cycle"], - "operation": "createDeviceLiveToolsPortsCycle", + "tags": ["devices", "liveTools", "ports", "status"], + "operation": "createDeviceLiveToolsPortsStatus", } serial = urllib.parse.quote(str(serial), safe="") - resource = f"/devices/{serial}/liveTools/ports/cycle" + resource = f"/devices/{serial}/liveTools/ports/status" body_params = [ - "ports", "callback", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -941,26 +941,26 @@ def createDeviceLiveToolsPortsCycle(self, serial: str, ports: list, **kwargs): all_params = [] + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: - self._session._logger.warning(f"createDeviceLiveToolsPortsCycle: ignoring unrecognized kwargs: {invalid}") + self._session._logger.warning(f"createDeviceLiveToolsPortsStatus: ignoring unrecognized kwargs: {invalid}") return self._session.post(metadata, resource, payload) - def getDeviceLiveToolsPortsCycle(self, serial: str, id: str): + def getDeviceLiveToolsPortsStatus(self, serial: str, jobId: str): """ - **Return a cycle port live tool job.** - https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ports-cycle + **Return a port status live tool job.** + https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ports-status - serial (string): Serial - - id (string): ID + - jobId (string): Job ID """ metadata = { - "tags": ["devices", "liveTools", "ports", "cycle"], - "operation": "getDeviceLiveToolsPortsCycle", + "tags": ["devices", "liveTools", "ports", "status"], + "operation": "getDeviceLiveToolsPortsStatus", } serial = urllib.parse.quote(str(serial), safe="") - id = urllib.parse.quote(str(id), safe="") - resource = f"/devices/{serial}/liveTools/ports/cycle/{id}" + jobId = urllib.parse.quote(str(jobId), safe="") + resource = f"/devices/{serial}/liveTools/ports/status/{jobId}" return self._session.get(metadata, resource) @@ -1047,7 +1047,7 @@ def createDeviceLiveToolsRoutingTable(self, serial: str, **kwargs): def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs): """ - **Enqueue a job to perform a routing table lookup request for the device** + **Enqueue a job to perform a routing table lookup request for a device** https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table-lookup - serial (string): Serial @@ -1108,7 +1108,7 @@ def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs): def getDeviceLiveToolsRoutingTableLookup(self, serial: str, id: str): """ - **Return a routing table live tool lookup job.** + **Return a routing table live tool lookup job for a device** https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-routing-table-lookup - serial (string): Serial @@ -1127,7 +1127,7 @@ def getDeviceLiveToolsRoutingTableLookup(self, serial: str, id: str): def createDeviceLiveToolsRoutingTableSummary(self, serial: str, **kwargs): """ - **Enqueue a job to perform a routing table summary request for the device** + **Enqueue a routing table summary job for a device** https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table-summary - serial (string): Serial @@ -1160,7 +1160,7 @@ def createDeviceLiveToolsRoutingTableSummary(self, serial: str, **kwargs): def getDeviceLiveToolsRoutingTableSummary(self, serial: str, id: str): """ - **Return a routing table live tool summary job.** + **Return the status and result of a routing table summary job** https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-routing-table-summary - serial (string): Serial diff --git a/meraki/aio/api/organizations.py b/meraki/aio/api/organizations.py index cb29bed..9be8b7a 100644 --- a/meraki/aio/api/organizations.py +++ b/meraki/aio/api/organizations.py @@ -3691,6 +3691,23 @@ def deleteOrganizationAuthRadiusServer(self, organizationId: str, serverId: str) 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** diff --git a/meraki/aio/api/secureConnect.py b/meraki/aio/api/secureConnect.py index dfec273..4700317 100644 --- a/meraki/aio/api/secureConnect.py +++ b/meraki/aio/api/secureConnect.py @@ -887,19 +887,19 @@ def getOrganizationSecureConnectRemoteAccessLogsExports( return self._session.get_pages(metadata, resource, params, total_pages, direction) - def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, from_: int, to: int, **kwargs): + def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, **kwargs): """ - **Creates a export for a provided timestamp interval.** + **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 - - from (integer): The start of the interval, must be within the past 30 days. - - to (integer): The end of the interval, must not exceed the current date. + - 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 = locals() - if "from_" in kwargs: - kwargs["from"] = kwargs.pop("from_") + kwargs.update(locals()) metadata = { "tags": ["secureConnect", "configure", "remoteAccessLogsExports"], @@ -909,6 +909,8 @@ def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports" body_params = [ + "t0", + "t1", "from", "to", ] diff --git a/meraki/aio/api/sm.py b/meraki/aio/api/sm.py index 1ac166f..263da77 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** diff --git a/meraki/aio/api/switch.py b/meraki/aio/api/switch.py index ba0c021..746bbca 100644 --- a/meraki/aio/api/switch.py +++ b/meraki/aio/api/switch.py @@ -1515,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()) @@ -1529,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} diff --git a/meraki/aio/api/users.py b/meraki/aio/api/users.py index c75cffd..c65a5ec 100644 --- a/meraki/aio/api/users.py +++ b/meraki/aio/api/users.py @@ -252,7 +252,7 @@ def createOrganizationIamUsersIdp(self, organizationId: str, name: str, type: st 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: + 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}''' @@ -688,7 +688,7 @@ def updateOrganizationIamUsersIdp(self, organizationId: str, id: str, **kwargs): kwargs.update(locals()) - if "syncType" in kwargs: + 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}''' diff --git a/meraki/aio/api/wireless.py b/meraki/aio/api/wireless.py index ff37088..d33b5d8 100644 --- a/meraki/aio/api/wireless.py +++ b/meraki/aio/api/wireless.py @@ -3432,7 +3432,7 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw return self._session.put(metadata, resource, payload) - def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, number: str, static: dict, **kwargs): + 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 @@ -3440,9 +3440,10 @@ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, numbe - networkId (string): Network ID - number (string): Number - static (object): Static client exclusion status + - dynamic (object): Dynamic client exclusion configuration """ - kwargs = locals() + kwargs.update(locals()) metadata = { "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion"], @@ -3454,6 +3455,7 @@ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, numbe body_params = [ "static", + "dynamic", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -3471,7 +3473,7 @@ def updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Set the static client exclusion list for the given SSID** + **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 @@ -3508,7 +3510,7 @@ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Add a list of MAC addresses to the static client exclusion list for the given SSID** + **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 @@ -3545,7 +3547,7 @@ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Delete a list of MAC addresses from the static client exclusion list for the given SSID** + **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 @@ -6039,6 +6041,7 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor - 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. - 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. @@ -6054,6 +6057,11 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor 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", "successfulConnects", "insights", "byNetwork"], @@ -6069,6 +6077,7 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor "bands", "contributor", "subContributor", + "insights", "t0", "t1", "timespan", @@ -6099,82 +6108,6 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor return self._session.get_pages(metadata, resource, params, total_pages, direction) - def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsV2ByNetwork( - self, organizationId: str, total_pages=1, direction="next", **kwargs - ): - """ - **Provides root-cause diagnostics for wireless successful connects experience by network.** - https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-insights-v-2-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): Restrict RCA to a single contributor (assoc, auth, dhcp, dns). If omitted, all contributors are considered. - - subContributor (string): Restrict RCA to a single sub-contributor (failure reason). If omitted, all sub-contributors are considered. - - 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}''' - ) - - metadata = { - "tags": ["wireless", "configure", "experience", "successfulConnects", "insightsV2", "byNetwork"], - "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsV2ByNetwork", - } - organizationId = urllib.parse.quote(str(organizationId), safe="") - resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/insightsV2/byNetwork" - - query_params = [ - "networkIds", - "serials", - "ssidNumbers", - "bands", - "contributor", - "subContributor", - "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"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsV2ByNetwork: 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 ): diff --git a/meraki/api/appliance.py b/meraki/api/appliance.py index 8d21afb..f20e932 100644 --- a/meraki/api/appliance.py +++ b/meraki/api/appliance.py @@ -40,10 +40,10 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs): kwargs.update(locals()) - if "speed" in kwargs: + 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: + 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}''' @@ -94,10 +94,10 @@ def updateDeviceApplianceInterfacesPort(self, serial: str, number: str, **kwargs kwargs.update(locals()) - if "speed" in kwargs: + 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: + 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}''' @@ -1282,6 +1282,7 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs): - 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()) @@ -1303,6 +1304,7 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs): "accessPolicy", "peerSgtCapable", "adaptivePolicyGroupId", + "sgt", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -2600,40 +2602,23 @@ def disableNetworkApplianceUmbrellaProtection(self, networkId: str): return self._session.delete(metadata, resource) - 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 excludeNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs): + def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs): """ **Specify one or more domain names to be excluded from being routed to Cisco Umbrella.** - https://developer.cisco.com/meraki/api-v1/#!exclude-network-appliance-umbrella-domains + https://developer.cisco.com/meraki/api-v1/#!exclusions-network-appliance-umbrella-domains - networkId (string): Network ID - - domains (array): Array of domain names + - domains (array): Domain names to exclude from Umbrella DNS routing (e.g., 'example.com', 'corp.example.org'). Standard FQDNs only — wildcards are not supported. Values are lowercased before saving. Each call replaces the full exclusion list. """ kwargs = locals() metadata = { - "tags": ["appliance", "configure", "umbrella"], - "operation": "excludeNetworkApplianceUmbrellaDomains", + "tags": ["appliance", "configure", "umbrella", "domains"], + "operation": "exclusionsNetworkApplianceUmbrellaDomains", } networkId = urllib.parse.quote(str(networkId), safe="") - resource = f"/networks/{networkId}/appliance/umbrella/excludeDomains" + resource = f"/networks/{networkId}/appliance/umbrella/domains/exclusions" body_params = [ "domains", @@ -2645,11 +2630,28 @@ def excludeNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning( - f"excludeNetworkApplianceUmbrellaDomains: ignoring unrecognized kwargs: {invalid}" + f"exclusionsNetworkApplianceUmbrellaDomains: ignoring unrecognized kwargs: {invalid}" ) 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.** @@ -2683,7 +2685,7 @@ def policiesNetworkApplianceUmbrella(self, networkId: str, policyIds: list, **kw def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs): """ - **Add one umbrella policy to your network.** + **Add one Cisco Umbrella DNS security policy to an MX network by policy ID** https://developer.cisco.com/meraki/api-v1/#!add-network-appliance-umbrella-policies - networkId (string): Network ID @@ -2714,7 +2716,7 @@ def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kw def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs): """ - **Remove one umbrella policy from your network.** + **Remove one Cisco Umbrella DNS security policy from an MX network by policy ID** https://developer.cisco.com/meraki/api-v1/#!remove-network-appliance-umbrella-policies - networkId (string): Network ID @@ -2745,13 +2747,13 @@ def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, * return self._session.post(metadata, resource, payload) - def protectionNetworkApplianceUmbrella(self, networkId: str, enable: bool, **kwargs): + def protectionNetworkApplianceUmbrella(self, networkId: str, enabled: bool, **kwargs): """ - **Enable or disable umbrella protection for an MX network** + **Enable or disable umbrella protection for an appliance network** https://developer.cisco.com/meraki/api-v1/#!protection-network-appliance-umbrella - networkId (string): Network ID - - enable (boolean): Enable or disable umbrella protection + - enabled (boolean): Enable or disable umbrella protection """ kwargs = locals() @@ -2764,7 +2766,7 @@ def protectionNetworkApplianceUmbrella(self, networkId: str, enable: bool, **kwa resource = f"/networks/{networkId}/appliance/umbrella/protection" body_params = [ - "enable", + "enabled", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -2887,6 +2889,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg - 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. """ @@ -2935,6 +2938,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg "dhcpBootFilename", "dhcpOptions", "adaptivePolicyGroupId", + "sgt", "vrf", "uplinks", ] @@ -3043,6 +3047,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs): - 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. """ @@ -3095,6 +3100,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs): "ipv6", "mandatoryDhcp", "adaptivePolicyGroupId", + "sgt", "vrf", "uplinks", ] @@ -3245,6 +3251,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw - 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 """ @@ -3267,6 +3274,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw "hubs", "subnets", "peerSgtCapable", + "sgt", "subnet", "hostTranslations", ] @@ -3451,6 +3459,71 @@ def getOrganizationApplianceDevicesInterfacesPortsByDevice(self, organizationId: return self._session.get(metadata, resource, params) + def getOrganizationApplianceDevicesPortsTransceiversReadingsHistoryByDevice( + self, organizationId: str, total_pages=1, direction="next", **kwargs + ): + """ + **Return time-series digital optical monitoring (DOM) readings for ports on each DOM-enabled Catalyst appliance in an organization.** + https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-devices-ports-transceivers-readings-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 + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 10. 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. + - 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 appliance serial. + - portIds (array): Optional parameter to filter usage by port ID. + """ + + kwargs.update(locals()) + + metadata = { + "tags": ["appliance", "monitor", "devices", "ports", "transceivers", "readings", "history", "byDevice"], + "operation": "getOrganizationApplianceDevicesPortsTransceiversReadingsHistoryByDevice", + } + organizationId = urllib.parse.quote(str(organizationId), safe="") + resource = f"/organizations/{organizationId}/appliance/devices/ports/transceivers/readings/history/byDevice" + + 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"getOrganizationApplianceDevicesPortsTransceiversReadingsHistoryByDevice: ignoring unrecognized kwargs: {invalid}" + ) + + return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApplianceDevicesRedundancyByNetwork( self, organizationId: str, total_pages=1, direction="next", **kwargs ): @@ -4229,6 +4302,66 @@ def getOrganizationApplianceFirewallMulticastForwardingByNetwork( return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApplianceInterfacesPacketsOverviewsByDevice( + self, organizationId: str, total_pages=1, direction="next", **kwargs + ): + """ + **Returns packet counter overviews for all interfaces on Secure Routers in the organization, including totals and average rates by packet type over the requested timespan.** + https://developer.cisco.com/meraki/api-v1/#!get-organization-appliance-interfaces-packets-overviews-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 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 1 day. + - 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. + - networkIds (array): Optional parameter to filter Secure Routers in the provided networks + - serials (array): Optional parameter to filter Secure Routers by their serial numbers + """ + + kwargs.update(locals()) + + metadata = { + "tags": ["appliance", "monitor", "interfaces", "packets", "overviews", "byDevice"], + "operation": "getOrganizationApplianceInterfacesPacketsOverviewsByDevice", + } + organizationId = urllib.parse.quote(str(organizationId), safe="") + resource = f"/organizations/{organizationId}/appliance/interfaces/packets/overviews/byDevice" + + 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"getOrganizationApplianceInterfacesPacketsOverviewsByDevice: ignoring unrecognized kwargs: {invalid}" + ) + + return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApplianceRoutingVrfsSettings(self, organizationId: str): """ **Return the VRF setting for an organization.** diff --git a/meraki/api/batch/appliance.py b/meraki/api/batch/appliance.py index d70c204..eac132d 100644 --- a/meraki/api/batch/appliance.py +++ b/meraki/api/batch/appliance.py @@ -22,10 +22,10 @@ def createDeviceApplianceInterfacesPortsUpdate(self, serial: str, **kwargs): kwargs.update(locals()) - if "speed" in kwargs: + 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: + 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}''' @@ -68,10 +68,10 @@ def updateDeviceApplianceInterfacesPort(self, serial: str, number: str, **kwargs kwargs.update(locals()) - if "speed" in kwargs: + 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: + 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}''' @@ -385,6 +385,7 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs): - 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()) @@ -402,6 +403,7 @@ def updateNetworkAppliancePort(self, networkId: str, portId: str, **kwargs): "accessPolicy", "peerSgtCapable", "adaptivePolicyGroupId", + "sgt", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} action = { @@ -997,45 +999,45 @@ def disableNetworkApplianceUmbrellaProtection(self, networkId: str): } return action - def enableNetworkApplianceUmbrellaProtection(self, networkId: str): + def exclusionsNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs): """ - **Enable umbrella protection for an MX network** - https://developer.cisco.com/meraki/api-v1/#!enable-network-appliance-umbrella-protection + **Specify one or more domain names to be excluded from being routed to Cisco Umbrella.** + https://developer.cisco.com/meraki/api-v1/#!exclusions-network-appliance-umbrella-domains - networkId (string): Network ID + - domains (array): Domain names to exclude from Umbrella DNS routing (e.g., 'example.com', 'corp.example.org'). Standard FQDNs only — wildcards are not supported. Values are lowercased before saving. Each call replaces the full exclusion list. """ + kwargs = locals() + networkId = urllib.parse.quote(networkId, safe="") - resource = f"/networks/{networkId}/appliance/umbrella/enableProtection" + resource = f"/networks/{networkId}/appliance/umbrella/domains/exclusions" + body_params = [ + "domains", + ] + 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 excludeNetworkApplianceUmbrellaDomains(self, networkId: str, domains: list, **kwargs): + def enableNetworkApplianceUmbrellaProtection(self, networkId: str): """ - **Specify one or more domain names to be excluded from being routed to Cisco Umbrella.** - https://developer.cisco.com/meraki/api-v1/#!exclude-network-appliance-umbrella-domains + **Enable umbrella protection for an MX network** + https://developer.cisco.com/meraki/api-v1/#!enable-network-appliance-umbrella-protection - networkId (string): Network ID - - domains (array): Array of domain names """ - kwargs = locals() - networkId = urllib.parse.quote(networkId, safe="") - resource = f"/networks/{networkId}/appliance/umbrella/excludeDomains" + resource = f"/networks/{networkId}/appliance/umbrella/enableProtection" - body_params = [ - "domains", - ] - 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 @@ -1066,7 +1068,7 @@ def policiesNetworkApplianceUmbrella(self, networkId: str, policyIds: list, **kw def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs): """ - **Add one umbrella policy to your network.** + **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.** https://developer.cisco.com/meraki/api-v1/#!add-network-appliance-umbrella-policies - networkId (string): Network ID @@ -1091,7 +1093,7 @@ def addNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kw def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, **kwargs): """ - **Remove one umbrella policy from your network.** + **Remove one Cisco Umbrella DNS security policy from an MX network by policy ID. Returns 204 No Content on success. Behavior when the policy is not currently applied depends on the Cisco Umbrella API response.** https://developer.cisco.com/meraki/api-v1/#!remove-network-appliance-umbrella-policies - networkId (string): Network ID @@ -1114,13 +1116,13 @@ def removeNetworkApplianceUmbrellaPolicies(self, networkId: str, policy: dict, * } return action - def protectionNetworkApplianceUmbrella(self, networkId: str, enable: bool, **kwargs): + def protectionNetworkApplianceUmbrella(self, networkId: str, enabled: bool, **kwargs): """ - **Enable or disable umbrella protection for an MX network. When disabling, the umbrella property will be omitted from the response.** + **Enable or disable umbrella protection for an appliance network. When 'enabled' is false, 'umbrella.organization.id' and 'umbrella.origin.id' are null in the response.** https://developer.cisco.com/meraki/api-v1/#!protection-network-appliance-umbrella - networkId (string): Network ID - - enable (boolean): Enable or disable umbrella protection + - enabled (boolean): Enable or disable umbrella protection """ kwargs = locals() @@ -1129,7 +1131,7 @@ def protectionNetworkApplianceUmbrella(self, networkId: str, enable: bool, **kwa resource = f"/networks/{networkId}/appliance/umbrella/protection" body_params = [ - "enable", + "enabled", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} action = { @@ -1188,6 +1190,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg - 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. """ @@ -1232,6 +1235,7 @@ def createNetworkApplianceVlan(self, networkId: str, id: str, name: str, **kwarg "dhcpBootFilename", "dhcpOptions", "adaptivePolicyGroupId", + "sgt", "vrf", "uplinks", ] @@ -1296,6 +1300,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs): - 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. """ @@ -1344,6 +1349,7 @@ def updateNetworkApplianceVlan(self, networkId: str, vlanId: str, **kwargs): "ipv6", "mandatoryDhcp", "adaptivePolicyGroupId", + "sgt", "vrf", "uplinks", ] @@ -1444,6 +1450,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw - 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 """ @@ -1462,6 +1469,7 @@ def updateNetworkApplianceVpnSiteToSiteVpn(self, networkId: str, mode: str, **kw "hubs", "subnets", "peerSgtCapable", + "sgt", "subnet", "hostTranslations", ] diff --git a/meraki/api/batch/devices.py b/meraki/api/batch/devices.py index e444d87..c3c5b13 100644 --- a/meraki/api/batch/devices.py +++ b/meraki/api/batch/devices.py @@ -188,10 +188,10 @@ def createDeviceLiveToolsLedsBlink(self, serial: str, duration: int, **kwargs): } return action - def createDeviceLiveToolsPortStatus(self, serial: str, **kwargs): + def createDeviceLiveToolsPortsStatus(self, serial: str, **kwargs): """ **Enqueue a job to retrieve port status for a device. 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-device-live-tools-port-status + https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-status - serial (string): Serial - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret @@ -200,7 +200,7 @@ def createDeviceLiveToolsPortStatus(self, serial: str, **kwargs): kwargs.update(locals()) serial = urllib.parse.quote(serial, safe="") - resource = f"/devices/{serial}/liveTools/portStatus" + resource = f"/devices/{serial}/liveTools/ports/status" body_params = [ "callback", @@ -240,7 +240,7 @@ def createDeviceLiveToolsReboot(self, serial: str, **kwargs): def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs): """ - **Enqueue a job to perform a routing table lookup request for the device. Only Cisco routers are supported. Any combination of search filters can be applied.** + **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.** https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table-lookup - serial (string): Serial @@ -293,7 +293,7 @@ def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs): def createDeviceLiveToolsRoutingTableSummary(self, serial: str, **kwargs): """ - **Enqueue a job to perform a routing table summary request for the device. Only Cisco routers are supported.** + **Enqueue a routing table summary job for a device. The job fetches summary data such as route counts by VRF and protocol. Only Cisco Secure Routers are supported.** https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table-summary - serial (string): Serial diff --git a/meraki/api/batch/sm.py b/meraki/api/batch/sm.py index 784dd96..738e149 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(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(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(networkId, safe="") + scriptId = urllib.parse.quote(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(networkId, safe="") + scriptId = urllib.parse.quote(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** diff --git a/meraki/api/batch/switch.py b/meraki/api/batch/switch.py index cca6ece..71d3516 100644 --- a/meraki/api/batch/switch.py +++ b/meraki/api/batch/switch.py @@ -862,6 +862,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()) @@ -872,6 +873,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} action = { diff --git a/meraki/api/batch/users.py b/meraki/api/batch/users.py index b8dfbfd..a194ca6 100644 --- a/meraki/api/batch/users.py +++ b/meraki/api/batch/users.py @@ -137,7 +137,7 @@ def createOrganizationIamUsersIdp(self, organizationId: str, name: str, type: st 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: + 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}''' @@ -315,7 +315,7 @@ def updateOrganizationIamUsersIdp(self, organizationId: str, id: str, **kwargs): kwargs.update(locals()) - if "syncType" in kwargs: + 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}''' diff --git a/meraki/api/batch/wireless.py b/meraki/api/batch/wireless.py index e7ba6a1..ca73d36 100644 --- a/meraki/api/batch/wireless.py +++ b/meraki/api/batch/wireless.py @@ -1393,7 +1393,7 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw } return action - def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, number: str, static: dict, **kwargs): + 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 @@ -1401,9 +1401,10 @@ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, numbe - networkId (string): Network ID - number (string): Number - static (object): Static client exclusion status + - dynamic (object): Dynamic client exclusion configuration """ - kwargs = locals() + kwargs.update(locals()) networkId = urllib.parse.quote(networkId, safe="") number = urllib.parse.quote(number, safe="") @@ -1411,6 +1412,7 @@ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, numbe body_params = [ "static", + "dynamic", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} action = { @@ -1424,7 +1426,7 @@ def updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Set the static client exclusion list for the given SSID** + **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 @@ -1453,7 +1455,7 @@ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Add a list of MAC addresses to the static client exclusion list for the given SSID** + **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 @@ -1482,7 +1484,7 @@ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Delete a list of MAC addresses from the static client exclusion list for the given SSID** + **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 diff --git a/meraki/api/campusGateway.py b/meraki/api/campusGateway.py index e2a279d..cc456d9 100644 --- a/meraki/api/campusGateway.py +++ b/meraki/api/campusGateway.py @@ -408,6 +408,7 @@ def getOrganizationCampusGatewayClustersNetworksOverviews( - 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'. @@ -440,6 +441,7 @@ def getOrganizationCampusGatewayClustersNetworksOverviews( "clusterIds", "siteIds", "networkIds", + "tunnelingSources", "search", "sortBy", "sortOrder", @@ -453,6 +455,7 @@ def getOrganizationCampusGatewayClustersNetworksOverviews( "clusterIds", "siteIds", "networkIds", + "tunnelingSources", ] for k, v in kwargs.items(): if k.strip() in array_params: diff --git a/meraki/api/devices.py b/meraki/api/devices.py index b3e059c..e1f5909 100644 --- a/meraki/api/devices.py +++ b/meraki/api/devices.py @@ -862,25 +862,27 @@ def getDeviceLiveToolsPingDevice(self, serial: str, id: str): return self._session.get(metadata, resource) - def createDeviceLiveToolsPortStatus(self, serial: str, **kwargs): + def createDeviceLiveToolsPortsCycle(self, serial: str, ports: list, **kwargs): """ - **Enqueue a job to retrieve port status for a device** - https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-port-status + **Enqueue a job to perform a cycle port for the device on the specified ports** + https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-cycle - serial (string): Serial + - ports (array): A list of ports to cycle. For Catalyst switches, IOS interface names are also supported, such as "GigabitEthernet1/0/8", "Gi1/0/8", or even "1/0/8". - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret """ kwargs.update(locals()) metadata = { - "tags": ["devices", "liveTools", "portStatus"], - "operation": "createDeviceLiveToolsPortStatus", + "tags": ["devices", "liveTools", "ports", "cycle"], + "operation": "createDeviceLiveToolsPortsCycle", } serial = urllib.parse.quote(str(serial), safe="") - resource = f"/devices/{serial}/liveTools/portStatus" + resource = f"/devices/{serial}/liveTools/ports/cycle" body_params = [ + "ports", "callback", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -889,50 +891,48 @@ def createDeviceLiveToolsPortStatus(self, serial: 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"createDeviceLiveToolsPortStatus: ignoring unrecognized kwargs: {invalid}") + self._session._logger.warning(f"createDeviceLiveToolsPortsCycle: ignoring unrecognized kwargs: {invalid}") return self._session.post(metadata, resource, payload) - def getDeviceLiveToolsPortStatus(self, serial: str, portStatusId: str): + def getDeviceLiveToolsPortsCycle(self, serial: str, id: str): """ - **Return a port status live tool job.** - https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-port-status + **Return a cycle port live tool job.** + https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ports-cycle - serial (string): Serial - - portStatusId (string): Port status ID + - id (string): ID """ metadata = { - "tags": ["devices", "liveTools", "portStatus"], - "operation": "getDeviceLiveToolsPortStatus", + "tags": ["devices", "liveTools", "ports", "cycle"], + "operation": "getDeviceLiveToolsPortsCycle", } serial = urllib.parse.quote(str(serial), safe="") - portStatusId = urllib.parse.quote(str(portStatusId), safe="") - resource = f"/devices/{serial}/liveTools/portStatus/{portStatusId}" + id = urllib.parse.quote(str(id), safe="") + resource = f"/devices/{serial}/liveTools/ports/cycle/{id}" return self._session.get(metadata, resource) - def createDeviceLiveToolsPortsCycle(self, serial: str, ports: list, **kwargs): + def createDeviceLiveToolsPortsStatus(self, serial: str, **kwargs): """ - **Enqueue a job to perform a cycle port for the device on the specified ports** - https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-cycle + **Enqueue a job to retrieve port status for a device** + https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-ports-status - serial (string): Serial - - ports (array): A list of ports to cycle. For Catalyst switches, IOS interface names are also supported, such as "GigabitEthernet1/0/8", "Gi1/0/8", or even "1/0/8". - callback (object): Details for the callback. Please include either an httpServerId OR url and sharedSecret """ kwargs.update(locals()) metadata = { - "tags": ["devices", "liveTools", "ports", "cycle"], - "operation": "createDeviceLiveToolsPortsCycle", + "tags": ["devices", "liveTools", "ports", "status"], + "operation": "createDeviceLiveToolsPortsStatus", } serial = urllib.parse.quote(str(serial), safe="") - resource = f"/devices/{serial}/liveTools/ports/cycle" + resource = f"/devices/{serial}/liveTools/ports/status" body_params = [ - "ports", "callback", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -941,26 +941,26 @@ def createDeviceLiveToolsPortsCycle(self, serial: str, ports: list, **kwargs): all_params = [] + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: - self._session._logger.warning(f"createDeviceLiveToolsPortsCycle: ignoring unrecognized kwargs: {invalid}") + self._session._logger.warning(f"createDeviceLiveToolsPortsStatus: ignoring unrecognized kwargs: {invalid}") return self._session.post(metadata, resource, payload) - def getDeviceLiveToolsPortsCycle(self, serial: str, id: str): + def getDeviceLiveToolsPortsStatus(self, serial: str, jobId: str): """ - **Return a cycle port live tool job.** - https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ports-cycle + **Return a port status live tool job.** + https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-ports-status - serial (string): Serial - - id (string): ID + - jobId (string): Job ID """ metadata = { - "tags": ["devices", "liveTools", "ports", "cycle"], - "operation": "getDeviceLiveToolsPortsCycle", + "tags": ["devices", "liveTools", "ports", "status"], + "operation": "getDeviceLiveToolsPortsStatus", } serial = urllib.parse.quote(str(serial), safe="") - id = urllib.parse.quote(str(id), safe="") - resource = f"/devices/{serial}/liveTools/ports/cycle/{id}" + jobId = urllib.parse.quote(str(jobId), safe="") + resource = f"/devices/{serial}/liveTools/ports/status/{jobId}" return self._session.get(metadata, resource) @@ -1047,7 +1047,7 @@ def createDeviceLiveToolsRoutingTable(self, serial: str, **kwargs): def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs): """ - **Enqueue a job to perform a routing table lookup request for the device** + **Enqueue a job to perform a routing table lookup request for a device** https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table-lookup - serial (string): Serial @@ -1108,7 +1108,7 @@ def createDeviceLiveToolsRoutingTableLookup(self, serial: str, **kwargs): def getDeviceLiveToolsRoutingTableLookup(self, serial: str, id: str): """ - **Return a routing table live tool lookup job.** + **Return a routing table live tool lookup job for a device** https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-routing-table-lookup - serial (string): Serial @@ -1127,7 +1127,7 @@ def getDeviceLiveToolsRoutingTableLookup(self, serial: str, id: str): def createDeviceLiveToolsRoutingTableSummary(self, serial: str, **kwargs): """ - **Enqueue a job to perform a routing table summary request for the device** + **Enqueue a routing table summary job for a device** https://developer.cisco.com/meraki/api-v1/#!create-device-live-tools-routing-table-summary - serial (string): Serial @@ -1160,7 +1160,7 @@ def createDeviceLiveToolsRoutingTableSummary(self, serial: str, **kwargs): def getDeviceLiveToolsRoutingTableSummary(self, serial: str, id: str): """ - **Return a routing table live tool summary job.** + **Return the status and result of a routing table summary job** https://developer.cisco.com/meraki/api-v1/#!get-device-live-tools-routing-table-summary - serial (string): Serial diff --git a/meraki/api/organizations.py b/meraki/api/organizations.py index a7bbcac..080ddf3 100644 --- a/meraki/api/organizations.py +++ b/meraki/api/organizations.py @@ -3691,6 +3691,23 @@ def deleteOrganizationAuthRadiusServer(self, organizationId: str, serverId: str) 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** diff --git a/meraki/api/secureConnect.py b/meraki/api/secureConnect.py index a3a6f7f..75a773a 100644 --- a/meraki/api/secureConnect.py +++ b/meraki/api/secureConnect.py @@ -887,19 +887,19 @@ def getOrganizationSecureConnectRemoteAccessLogsExports( return self._session.get_pages(metadata, resource, params, total_pages, direction) - def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, from_: int, to: int, **kwargs): + def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: str, **kwargs): """ - **Creates a export for a provided timestamp interval.** + **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 - - from (integer): The start of the interval, must be within the past 30 days. - - to (integer): The end of the interval, must not exceed the current date. + - 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 = locals() - if "from_" in kwargs: - kwargs["from"] = kwargs.pop("from_") + kwargs.update(locals()) metadata = { "tags": ["secureConnect", "configure", "remoteAccessLogsExports"], @@ -909,6 +909,8 @@ def createOrganizationSecureConnectRemoteAccessLogsExport(self, organizationId: resource = f"/organizations/{organizationId}/secureConnect/remoteAccessLogsExports" body_params = [ + "t0", + "t1", "from", "to", ] diff --git a/meraki/api/sm.py b/meraki/api/sm.py index af8fcfa..e4f811c 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** diff --git a/meraki/api/switch.py b/meraki/api/switch.py index 58727fd..ca432ea 100644 --- a/meraki/api/switch.py +++ b/meraki/api/switch.py @@ -1515,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()) @@ -1529,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} diff --git a/meraki/api/users.py b/meraki/api/users.py index 7efa68e..f48c8b5 100644 --- a/meraki/api/users.py +++ b/meraki/api/users.py @@ -252,7 +252,7 @@ def createOrganizationIamUsersIdp(self, organizationId: str, name: str, type: st 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: + 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}''' @@ -688,7 +688,7 @@ def updateOrganizationIamUsersIdp(self, organizationId: str, id: str, **kwargs): kwargs.update(locals()) - if "syncType" in kwargs: + 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}''' diff --git a/meraki/api/wireless.py b/meraki/api/wireless.py index e14d3ea..e87ed42 100644 --- a/meraki/api/wireless.py +++ b/meraki/api/wireless.py @@ -3432,7 +3432,7 @@ def updateNetworkWirelessSsidOpenRoaming(self, networkId: str, number: str, **kw return self._session.put(metadata, resource, payload) - def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, number: str, static: dict, **kwargs): + 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 @@ -3440,9 +3440,10 @@ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, numbe - networkId (string): Network ID - number (string): Number - static (object): Static client exclusion status + - dynamic (object): Dynamic client exclusion configuration """ - kwargs = locals() + kwargs.update(locals()) metadata = { "tags": ["wireless", "configure", "ssids", "policies", "clientExclusion"], @@ -3454,6 +3455,7 @@ def updateNetworkWirelessSsidPoliciesClientExclusion(self, networkId: str, numbe body_params = [ "static", + "dynamic", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} @@ -3471,7 +3473,7 @@ def updateNetworkWirelessSsidPoliciesClientExclusionStaticExclusions( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Set the static client exclusion list for the given SSID** + **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 @@ -3508,7 +3510,7 @@ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkAdd( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Add a list of MAC addresses to the static client exclusion list for the given SSID** + **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 @@ -3545,7 +3547,7 @@ def createNetworkWirelessSsidPoliciesClientExclusionStaticExclusionsBulkRemove( self, networkId: str, number: str, macs: list, **kwargs ): """ - **Delete a list of MAC addresses from the static client exclusion list for the given SSID** + **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 @@ -6039,6 +6041,7 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor - 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. - 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. @@ -6054,6 +6057,11 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor 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", "successfulConnects", "insights", "byNetwork"], @@ -6069,6 +6077,7 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor "bands", "contributor", "subContributor", + "insights", "t0", "t1", "timespan", @@ -6099,82 +6108,6 @@ def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsByNetwor return self._session.get_pages(metadata, resource, params, total_pages, direction) - def getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsV2ByNetwork( - self, organizationId: str, total_pages=1, direction="next", **kwargs - ): - """ - **Provides root-cause diagnostics for wireless successful connects experience by network.** - https://developer.cisco.com/meraki/api-v1/#!get-organization-assurance-wireless-experience-successful-connects-insights-v-2-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): Restrict RCA to a single contributor (assoc, auth, dhcp, dns). If omitted, all contributors are considered. - - subContributor (string): Restrict RCA to a single sub-contributor (failure reason). If omitted, all sub-contributors are considered. - - 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}''' - ) - - metadata = { - "tags": ["wireless", "configure", "experience", "successfulConnects", "insightsV2", "byNetwork"], - "operation": "getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsV2ByNetwork", - } - organizationId = urllib.parse.quote(str(organizationId), safe="") - resource = f"/organizations/{organizationId}/assurance/wireless/experience/successfulConnects/insightsV2/byNetwork" - - query_params = [ - "networkIds", - "serials", - "ssidNumbers", - "bands", - "contributor", - "subContributor", - "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"getOrganizationAssuranceWirelessExperienceSuccessfulConnectsInsightsV2ByNetwork: 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 ): diff --git a/pyproject.toml b/pyproject.toml index 61c50c6..738b1a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "meraki" -version = "3.1.0b2" +version = "3.1.0b3" description = "Cisco Meraki Dashboard API library" authors = [ {name = "Cisco Meraki", email = "api-feedback@meraki.net"} diff --git a/uv.lock b/uv.lock index 3d0791b..299e347 100644 --- a/uv.lock +++ b/uv.lock @@ -521,7 +521,7 @@ wheels = [ [[package]] name = "meraki" -version = "3.1.0b2" +version = "3.1.0b3" source = { editable = "." } dependencies = [ { name = "aiohttp" },