diff --git a/examples/aio_ips2firewall.py b/examples/aio_ips2firewall.py new file mode 100644 index 00000000..105045ea --- /dev/null +++ b/examples/aio_ips2firewall.py @@ -0,0 +1,119 @@ +import csv +from datetime import datetime, timedelta +import os +import asyncio +import argparse +import ipaddress +from typing import Dict,List +import sys + +import meraki.aio + +# Either input your API key below, or set an environment variable +# for example, in Terminal on macOS: export MERAKI_DASHBOARD_API_KEY=66839003d2861bc302b292eb66d3b247709f2d0d +api_key = "" + +def removeSmallAmounts( ip_counts:Dict[str,int], filter:int): + ret = ip_counts.copy() + for k,v in ip_counts.items(): + if v < filter: + ret.pop(k) + + return ret + +async def analyzeOrganization(aiomeraki: meraki.aio.AsyncDashboardAPI, orgId:str, days:int) -> Dict[str,int]: + ret = {} + timespan = days * 24 * 60 * 60 + events = await aiomeraki.security_events.getOrganizationSecurityEvents(orgId, timespan=timespan,total_pages=-1) + for e in events: + ip, port = e["srcIp"].rsplit(":",1) + ip = ip.strip("[]") # remove brackets in case of ipv6 + if not ipaddress.ip_address(ip).is_private: # dont block private ip addresses on the public ip of the firewall + ret[ip] = ret.get(ip, 0) + 1 + + return ret + +async def updateFirewallrules(aiomeraki: meraki.aio.AsyncDashboardAPI, networkId:str, ip_list:List[str]): + rules = await aiomeraki.mx_l7_firewall.getNetworkL7FirewallRules(networkId) + + rules=rules["rules"] + #get the currently blocked ip ranges + current_blocks = [x["value"] for x in rules if x["type"] == "ipRange"] + + new_blocks = current_blocks + list(set(ip_list)-set(current_blocks)) + new_blocks = sorted(new_blocks) + + #generate new rules based on the list of total ip ranges to block + rules_to_add = [{"policy":"deny", "type":"ipRange", "value":x} for x in new_blocks] + + #remove all currently blocked ip ranges + rules = [x for x in rules if x["type"] != "ipRange"] + + rules = rules + rules_to_add + + await aiomeraki.mx_l7_firewall.updateNetworkL7FirewallRules(networkId,rules=rules) + +async def main(): + + parser = argparse.ArgumentParser(description='Block IP Addresses based on security events') + parser.add_argument('-o','--organization', type=str, nargs='+', dest="organizations", required=True, + help='the name/id of the organization(s) you want to analyze/secure') + parser.add_argument("-f",'--filter', dest='filter', type=int, default=5, + help='how often must an attack be listed before it gets blocked') + parser.add_argument("-s",'--save', dest='save', action='store_true', + help='write the blocklist to all networks in the organization.') + parser.add_argument("-d",'--days', dest='days', default=31, type=int, + help='How many days should be analyzed.') + + if len(sys.argv) < 3: + parser.print_help() + return + + try: + args = parser.parse_args() + if args.days >= 365: + print("days must be < 365") + parser.print_help() + return + except SystemExit: + return + except: + print("could not parse arguments") + parser.print_help() + return + + # Instantiate a Meraki dashboard API session + # NOTE: you have to use "async with" so that the session will be closed correctly at the end of the usage + async with meraki.aio.AsyncDashboardAPI( + api_key, + base_url="https://api.meraki.com/api/v0", + log_file_prefix=__file__[:-3], + print_console=False, + ) as aiomeraki: + # Get list of organizations to which API key has access + organizations = await aiomeraki.organizations.getOrganizations() + for x in organizations: + if x["id"] in args.organizations or x["name"] in args.organizations: + print(f"Analyzing organization {x['name']}") + result = await analyzeOrganization(aiomeraki, x["id"], args.days) + result = removeSmallAmounts(result, args.filter) + sum = 0 + + for k,v in result.items(): + print(f"{k} attacked {v} times.") + sum = sum + v + print(f"Total attacks: {sum} from {len(result)} different IP adresses") + + #apply the found ip ranges to the firewall + if args.save: + for n in await aiomeraki.networks.getOrganizationNetworks(x["id"]): + print(f"Updating Network {n['name']}") + await updateFirewallrules(aiomeraki,n["id"], result.keys()) + + print("Script complete!") + + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) + diff --git a/examples/aio_org_wide_clients.py b/examples/aio_org_wide_clients.py new file mode 100644 index 00000000..e41118f1 --- /dev/null +++ b/examples/aio_org_wide_clients.py @@ -0,0 +1,137 @@ +import csv +from datetime import datetime +import os +import asyncio + +import meraki.aio + +# Either input your API key below, or set an environment variable +# for example, in Terminal on macOS: export MERAKI_DASHBOARD_API_KEY=093b24e85df15a3e66f1fc359f4c48493eaa1b73 +api_key = "" + + +async def listNetworkClients(aiomeraki: meraki.aio.AsyncDashboardAPI, folder_name, network): + print(f'Finding clients in network {network["name"]}') + try: + # Get list of clients on network, filtering on timespan of last 14 days + clients = await aiomeraki.clients.getNetworkClients( + network["id"], + timespan=60 * 60 * 24 * 14, + perPage=1000, + total_pages="all", + ) + except meraki.AsyncAPIError as e: + print(f"Meraki API error: {e}") + except Exception as e: + print(f"some other error: {e}") + else: + if clients: + # Write to file + file_name = f'{network["name"]}.csv' + output_file = open( + f"{folder_name}/{file_name}", mode="w", newline="\n" + ) + field_names = clients[0].keys() + csv_writer = csv.DictWriter( + output_file, + field_names, + delimiter=",", + quotechar='"', + quoting=csv.QUOTE_ALL, + ) + csv_writer.writeheader() + csv_writer.writerows(clients) + output_file.close() + print( + f"Successfully output {len(clients)} clients' data to file {file_name}" + ) + return network["name"], field_names + return network["name"], None + + +async def listOrganization(aiomeraki: meraki.aio.AsyncDashboardAPI, org): + print(f'Analyzing organization {org["name"]}:') + org_id = org["id"] + + # Get list of networks in organization + try: + networks = await aiomeraki.networks.getOrganizationNetworks(org_id) + except meraki.AsyncAPIError as e: + print(f"Meraki API error: {e}") + return org["name"] + except Exception as e: + print(f"some other error: {e}") + return org["name"] + + # Create local folder + todays_date = f"{datetime.now():%Y-%m-%d}" + folder_name = f"Org {org_id} clients {todays_date}" + if folder_name not in os.listdir(): + os.mkdir(folder_name) + + # Iterate through networks + total = len(networks) + print(f"Iterating through {total} networks in organization {org_id}") + + # create a list of all networks in the organization so we can call them all concurrently + networkClientsTasks = [listNetworkClients(aiomeraki, folder_name, net) for net in networks] + for task in asyncio.as_completed(networkClientsTasks): + networkname, field_names = await task + print(f"finished network: {networkname}") + + # Stitch together one consolidated CSV per org + output_file = open(f"{folder_name}.csv", mode="w", newline="\n") + field_names = list(field_names) + field_names.insert(0, "Network Name") + field_names.insert(1, "Network ID") + csv_writer = csv.DictWriter( + output_file, + field_names, + delimiter=",", + quotechar='"', + quoting=csv.QUOTE_ALL, + ) + csv_writer.writeheader() + for net in networks: + file_name = f'{net["name"]}.csv' + if file_name in os.listdir(folder_name): + with open(f"{folder_name}/{file_name}") as input_file: + csv_reader = csv.DictReader( + input_file, + delimiter=",", + quotechar='"', + quoting=csv.QUOTE_ALL, + ) + next(csv_reader) + for row in csv_reader: + row["Network Name"] = net["name"] + row["Network ID"] = net["id"] + csv_writer.writerow(row) + return org["name"] + + +async def main(): + # Instantiate a Meraki dashboard API session + # NOTE: you have to use "async with" so that the session will be closed correctly at the end of the usage + async with meraki.aio.AsyncDashboardAPI( + api_key, + base_url="https://api.meraki.com/api/v0", + log_file_prefix=__file__[:-3], + print_console=False, + ) as aiomeraki: + # Get list of organizations to which API key has access + organizations = await aiomeraki.organizations.getOrganizations() + + # create a list of all organizations so we can call them all concurrently + organizationTasks = [listOrganization(aiomeraki, org) for org in organizations] + for task in asyncio.as_completed(organizationTasks): + # as_completed returns an iterator, so we just have to await the iterator and not call it + organizationName = await task + print(f"finished organization: {organizationName}") + + print("Script complete!") + + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/examples/org_wide_clients.py b/examples/org_wide_clients.py index 49046d92..23f67528 100644 --- a/examples/org_wide_clients.py +++ b/examples/org_wide_clients.py @@ -4,19 +4,25 @@ import meraki -# Either input your API key below by uncommenting line 10 and changing line 15 to api_key=api_key, +# Either input your API key below by uncommenting line 10 and changing line 16 to api_key=API_KEY, # or set an environment variable (preferred) to define your API key. The former is insecure and not recommended. # For example, in Linux/macOS: export MERAKI_DASHBOARD_API_KEY=093b24e85df15a3e66f1fc359f4c48493eaa1b73 -# api_key = '093b24e85df15a3e66f1fc359f4c48493eaa1b73' +# API_KEY = '093b24e85df15a3e66f1fc359f4c48493eaa1b73' def main(): # Instantiate a Meraki dashboard API session - dashboard = meraki.DashboardAPI(api_key=None, base_url='https://api.meraki.com/api/v0/', log_file_prefix=__file__[:-3], print_console=False) + dashboard = meraki.DashboardAPI( + api_key='', + base_url='https://api-mp.meraki.com/api/v0/', + log_file_prefix=os.path.basename(__file__)[:-3], + log_path='', + print_console=False + ) # Get list of organizations to which API key has access organizations = dashboard.organizations.getOrganizations() - + # Iterate through list of orgs for org in organizations: print(f'\nAnalyzing organization {org["name"]}:') diff --git a/meraki/__init__.py b/meraki/__init__.py index a03403bc..fea49e2b 100644 --- a/meraki/__init__.py +++ b/meraki/__init__.py @@ -9,8 +9,10 @@ from .api.admins import Admins from .api.alert_settings import AlertSettings from .api.bluetooth_clients import BluetoothClients +from .api.bluetooth_settings import BluetoothSettings from .api.camera_quality_retention_profiles import CameraQualityRetentionProfiles from .api.cameras import Cameras +from .api.change_log import ChangeLog from .api.clients import Clients from .api.config_templates import ConfigTemplates from .api.connectivity_monitoring_destinations import ConnectivityMonitoringDestinations @@ -49,6 +51,7 @@ from .api.malware_settings import MalwareSettings from .api.management_interface_settings import ManagementInterfaceSettings from .api.meraki_auth_users import MerakiAuthUsers +from .api.monitored_media_servers import MonitoredMediaServers from .api.named_tag_scope import NamedTagScope from .api.netflow_settings import NetFlowSettings from .api.networks import Networks @@ -79,9 +82,10 @@ from .api.wireless_settings import WirelessSettings from .config import ( API_KEY_ENVIRONMENT_VARIABLE, DEFAULT_BASE_URL, SINGLE_REQUEST_TIMEOUT, CERTIFICATE_PATH, WAIT_ON_RATE_LIMIT, - MAXIMUM_RETRIES, OUTPUT_LOG, LOG_FILE_PREFIX, PRINT_TO_CONSOLE, SIMULATE_API_CALLS + MAXIMUM_RETRIES, OUTPUT_LOG, LOG_PATH, LOG_FILE_PREFIX, PRINT_TO_CONSOLE, SIMULATE_API_CALLS ) +__version__ = '0.90.1' class DashboardAPI(object): """ @@ -92,17 +96,18 @@ class DashboardAPI(object): - single_request_timeout (integer): maximum number of seconds for each API call - certificate_path (string): path for TLS/SSL certificate verification if behind local proxy - wait_on_rate_limit (boolean): retry if 429 rate limit error encountered? - - maximum_retries_on_rate_limit (integer): retry up to this many times when encountering 429s or other server-side errors + - maximum_retries (integer): retry up to this many times when encountering 429s or other server-side errors - output_log (boolean): create an output log file? + - log_path (string): path to output log; by default, working directory of script if not specified - log_file_prefix (string): log file name appended with date and timestamp - - print_console (boolean): if output log used, output to console too? + - print_console (boolean): print logging output to console? - simulate (boolean): simulate POST/PUT/DELETE calls to prevent changes? """ def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, single_request_timeout=SINGLE_REQUEST_TIMEOUT, certificate_path=CERTIFICATE_PATH, wait_on_rate_limit=WAIT_ON_RATE_LIMIT, - maximum_retries=MAXIMUM_RETRIES, output_log=OUTPUT_LOG, log_file_prefix=LOG_FILE_PREFIX, - print_console=PRINT_TO_CONSOLE, simulate=SIMULATE_API_CALLS): + maximum_retries=MAXIMUM_RETRIES, output_log=OUTPUT_LOG, log_path=LOG_PATH, + log_file_prefix=LOG_FILE_PREFIX, print_console=PRINT_TO_CONSOLE, simulate=SIMULATE_API_CALLS): # Check API key api_key = api_key or os.environ.get(API_KEY_ENVIRONMENT_VARIABLE) if not api_key: @@ -110,20 +115,26 @@ def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, single_request_timeo # Configure logging self._logger = logging.getLogger(__name__) - self._log_file = f'{log_file_prefix}_log__{datetime.now():%Y-%m-%d_%H-%M-%S}.log' + if log_path and log_path[-1] != '/': + log_path += '/' + self._log_file = f'{log_path}{log_file_prefix}_log__{datetime.now():%Y-%m-%d_%H-%M-%S}.log' if output_log: logging.basicConfig( filename=self._log_file, level=logging.DEBUG, format='%(asctime)s %(name)12s: %(levelname)8s > %(message)s', datefmt='%Y-%m-%d %H:%M:%S') - if print_console: console = logging.StreamHandler() console.setLevel(logging.INFO) formatter = logging.Formatter('%(name)12s: %(levelname)8s > %(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) + elif print_console: + logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s %(name)12s: %(levelname)8s > %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') # Creates the API session self._session = RestSession( @@ -143,8 +154,10 @@ def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, single_request_timeo self.admins = Admins(self._session) self.alert_settings = AlertSettings(self._session) self.bluetooth_clients = BluetoothClients(self._session) + self.bluetooth_settings = BluetoothSettings(self._session) self.camera_quality_retention_profiles = CameraQualityRetentionProfiles(self._session) self.cameras = Cameras(self._session) + self.change_log = ChangeLog(self._session) self.clients = Clients(self._session) self.config_templates = ConfigTemplates(self._session) self.connectivity_monitoring_destinations = ConnectivityMonitoringDestinations(self._session) @@ -183,6 +196,7 @@ def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, single_request_timeo self.malware_settings = MalwareSettings(self._session) self.management_interface_settings = ManagementInterfaceSettings(self._session) self.meraki_auth_users = MerakiAuthUsers(self._session) + self.monitored_media_servers = MonitoredMediaServers(self._session) self.named_tag_scope = NamedTagScope(self._session) self.netflow_settings = NetFlowSettings(self._session) self.networks = Networks(self._session) diff --git a/meraki/aio/__init__.py b/meraki/aio/__init__.py new file mode 100644 index 00000000..06b36a4d --- /dev/null +++ b/meraki/aio/__init__.py @@ -0,0 +1,231 @@ +from datetime import datetime +import logging +import os + +from .rest_session import * +from .api.api_usage import AsyncAPIUsage +from .api.action_batches import AsyncActionBatches +from .api.admins import AsyncAdmins +from .api.alert_settings import AsyncAlertSettings +from .api.bluetooth_clients import AsyncBluetoothClients +from .api.bluetooth_settings import AsyncBluetoothSettings +from .api.camera_quality_retention_profiles import AsyncCameraQualityRetentionProfiles +from .api.cameras import AsyncCameras +from .api.change_log import AsyncChangeLog +from .api.clients import AsyncClients +from .api.config_templates import AsyncConfigTemplates +from .api.connectivity_monitoring_destinations import AsyncConnectivityMonitoringDestinations +from .api.content_filtering_categories import AsyncContentFilteringCategories +from .api.content_filtering_rules import AsyncContentFilteringRules +from .api.dashboard_branding_policies import AsyncDashboardBrandingPolicies +from .api.devices import AsyncDevices +from .api.events import AsyncEvents +from .api.firewalled_services import AsyncFirewalledServices +from .api.floorplans import AsyncFloorplans +from .api.group_policies import AsyncGroupPolicies +from .api.http_servers import AsyncHTTPServers +from .api.intrusion_settings import AsyncIntrusionSettings +from .api.licenses import AsyncLicenses +from .api.link_aggregations import AsyncLinkAggregations +from .api.mg_dhcp_settings import AsyncMGDHCPSettings +from .api.mg_lan_settings import AsyncMGLANSettings +from .api.mg_connectivity_monitoring_destinations import AsyncMGConnectivityMonitoringDestinations +from .api.mg_port_forwarding_rules import AsyncMGPortForwardingRules +from .api.mg_subnet_pool_settings import AsyncMGSubnetPoolSettings +from .api.mg_uplink_settings import AsyncMGUplinkSettings +from .api.mr_l3_firewall import AsyncMRL3Firewall +from .api.mv_sense import AsyncMVSense +from .api.mx_1_1_nat_rules import AsyncMX11NATRules +from .api.mx_1_many_nat_rules import AsyncMX1ManyNATRules +from .api.mx_l3_firewall import AsyncMXL3Firewall +from .api.mx_l7_application_categories import AsyncMXL7ApplicationCategories +from .api.mx_l7_firewall import AsyncMXL7Firewall +from .api.mx_vlan_ports import AsyncMXVLANPorts +from .api.mx_vpn_firewall import AsyncMXVPNFirewall +from .api.mx_cellular_firewall import AsyncMXCellularFirewall +from .api.mx_inbound_firewall import AsyncMXInboundFirewall +from .api.mx_port_forwarding_rules import AsyncMXPortForwardingRules +from .api.mx_static_routes import AsyncMXStaticRoutes +from .api.mx_warm_spare_settings import AsyncMXWarmSpareSettings +from .api.malware_settings import AsyncMalwareSettings +from .api.management_interface_settings import AsyncManagementInterfaceSettings +from .api.meraki_auth_users import AsyncMerakiAuthUsers +from .api.monitored_media_servers import AsyncMonitoredMediaServers +from .api.named_tag_scope import AsyncNamedTagScope +from .api.netflow_settings import AsyncNetFlowSettings +from .api.networks import AsyncNetworks +from .api.openapi_spec import AsyncOpenAPISpec +from .api.organizations import AsyncOrganizations +from .api.pii import AsyncPII +from .api.radio_settings import AsyncRadioSettings +from .api.saml_roles import AsyncSAMLRoles +from .api.sm import AsyncSM +from .api.snmp_settings import AsyncSNMPSettings +from .api.ssids import AsyncSSIDs +from .api.security_events import AsyncSecurityEvents +from .api.splash_login_attempts import AsyncSplashLoginAttempts +from .api.splash_settings import AsyncSplashSettings +from .api.switch_acls import AsyncSwitchACLs +from .api.switch_port_schedules import AsyncSwitchPortSchedules +from .api.switch_ports import AsyncSwitchPorts +from .api.switch_profiles import AsyncSwitchProfiles +from .api.switch_settings import AsyncSwitchSettings +from .api.switch_stacks import AsyncSwitchStacks +from .api.syslog_servers import AsyncSyslogServers +from .api.traffic_analysis_settings import AsyncTrafficAnalysisSettings +from .api.traffic_shaping import AsyncTrafficShaping +from .api.uplink_settings import AsyncUplinkSettings +from .api.vlans import AsyncVLANs +from .api.webhook_logs import AsyncWebhookLogs +from .api.wireless_health import AsyncWirelessHealth +from .api.wireless_settings import AsyncWirelessSettings +from ..config import ( + API_KEY_ENVIRONMENT_VARIABLE, DEFAULT_BASE_URL, SINGLE_REQUEST_TIMEOUT, CERTIFICATE_PATH, WAIT_ON_RATE_LIMIT, + MAXIMUM_RETRIES, OUTPUT_LOG, LOG_PATH, LOG_FILE_PREFIX, PRINT_TO_CONSOLE, SIMULATE_API_CALLS +) + + +class AsyncDashboardAPI: + """ + **Creates a persistent Meraki dashboard API session** + + - api_key (string): API key generated in dashboard; can also be set as an environment variable MERAKI_DASHBOARD_API_KEY + - base_url (string): preceding all endpoint resources + - single_request_timeout (integer): maximum number of seconds for each API call + - certificate_path (string): path for TLS/SSL certificate verification if behind local proxy + - wait_on_rate_limit (boolean): retry if 429 rate limit error encountered? + - maximum_retries (integer): retry up to this many times when encountering 429s or other server-side errors + - output_log (boolean): create an output log file? + - log_path (string): path to output log; by default, working directory of script if not specified + - log_file_prefix (string): log file name appended with date and timestamp + - print_console (boolean): print logging output to console? + - simulate (boolean): simulate POST/PUT/DELETE calls to prevent changes? + """ + + def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, single_request_timeout=SINGLE_REQUEST_TIMEOUT, + certificate_path=CERTIFICATE_PATH, wait_on_rate_limit=WAIT_ON_RATE_LIMIT, + maximum_retries=MAXIMUM_RETRIES, output_log=OUTPUT_LOG, log_path=LOG_PATH, + log_file_prefix=LOG_FILE_PREFIX, print_console=PRINT_TO_CONSOLE, simulate=SIMULATE_API_CALLS): + # Check API key + api_key = api_key or os.environ.get(API_KEY_ENVIRONMENT_VARIABLE) + if not api_key: + raise APIKeyError() + + # Configure logging + self._logger = logging.getLogger(__name__) + if log_path and log_path[-1] != '/': + log_path += '/' + self._log_file = f'{log_path}{log_file_prefix}_log__{datetime.now():%Y-%m-%d_%H-%M-%S}.log' + if output_log: + logging.basicConfig( + filename=self._log_file, + level=logging.DEBUG, + format='%(asctime)s %(name)12s: %(levelname)8s > %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + if print_console: + console = logging.StreamHandler() + console.setLevel(logging.INFO) + formatter = logging.Formatter('%(name)12s: %(levelname)8s > %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + elif print_console: + logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s %(name)12s: %(levelname)8s > %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + + # Creates the API session + self._session = AsyncRestSession( + logger=self._logger, + api_key=api_key, + base_url=base_url, + single_request_timeout=single_request_timeout, + certificate_path=certificate_path, + wait_on_rate_limit=wait_on_rate_limit, + maximum_retries=maximum_retries, + simulate=simulate, + ) + + # API endpoints by section + self.api_usage = AsyncAPIUsage(self._session) + self.action_batches = AsyncActionBatches(self._session) + self.admins = AsyncAdmins(self._session) + self.alert_settings = AsyncAlertSettings(self._session) + self.bluetooth_clients = AsyncBluetoothClients(self._session) + self.bluetooth_settings = AsyncBluetoothSettings(self._session) + self.camera_quality_retention_profiles = AsyncCameraQualityRetentionProfiles(self._session) + self.cameras = AsyncCameras(self._session) + self.change_log = AsyncChangeLog(self._session) + self.clients = AsyncClients(self._session) + self.config_templates = AsyncConfigTemplates(self._session) + self.connectivity_monitoring_destinations = AsyncConnectivityMonitoringDestinations(self._session) + self.content_filtering_categories = AsyncContentFilteringCategories(self._session) + self.content_filtering_rules = AsyncContentFilteringRules(self._session) + self.dashboard_branding_policies = AsyncDashboardBrandingPolicies(self._session) + self.devices = AsyncDevices(self._session) + self.events = AsyncEvents(self._session) + self.firewalled_services = AsyncFirewalledServices(self._session) + self.floorplans = AsyncFloorplans(self._session) + self.group_policies = AsyncGroupPolicies(self._session) + self.http_servers = AsyncHTTPServers(self._session) + self.intrusion_settings = AsyncIntrusionSettings(self._session) + self.licenses = AsyncLicenses(self._session) + self.link_aggregations = AsyncLinkAggregations(self._session) + self.mg_dhcp_settings = AsyncMGDHCPSettings(self._session) + self.mg_lan_settings = AsyncMGLANSettings(self._session) + self.mg_connectivity_monitoring_destinations = AsyncMGConnectivityMonitoringDestinations(self._session) + self.mg_port_forwarding_rules = AsyncMGPortForwardingRules(self._session) + self.mg_subnet_pool_settings = AsyncMGSubnetPoolSettings(self._session) + self.mg_uplink_settings = AsyncMGUplinkSettings(self._session) + self.mr_l3_firewall = AsyncMRL3Firewall(self._session) + self.mv_sense = AsyncMVSense(self._session) + self.mx_1_1_nat_rules = AsyncMX11NATRules(self._session) + self.mx_1_many_nat_rules = AsyncMX1ManyNATRules(self._session) + self.mx_l3_firewall = AsyncMXL3Firewall(self._session) + self.mx_l7_application_categories = AsyncMXL7ApplicationCategories(self._session) + self.mx_l7_firewall = AsyncMXL7Firewall(self._session) + self.mx_vlan_ports = AsyncMXVLANPorts(self._session) + self.mx_vpn_firewall = AsyncMXVPNFirewall(self._session) + self.mx_cellular_firewall = AsyncMXCellularFirewall(self._session) + self.mx_inbound_firewall = AsyncMXInboundFirewall(self._session) + self.mx_port_forwarding_rules = AsyncMXPortForwardingRules(self._session) + self.mx_static_routes = AsyncMXStaticRoutes(self._session) + self.mx_warm_spare_settings = AsyncMXWarmSpareSettings(self._session) + self.malware_settings = AsyncMalwareSettings(self._session) + self.management_interface_settings = AsyncManagementInterfaceSettings(self._session) + self.meraki_auth_users = AsyncMerakiAuthUsers(self._session) + self.monitored_media_servers = AsyncMonitoredMediaServers(self._session) + self.named_tag_scope = AsyncNamedTagScope(self._session) + self.netflow_settings = AsyncNetFlowSettings(self._session) + self.networks = AsyncNetworks(self._session) + self.openapi_spec = AsyncOpenAPISpec(self._session) + self.organizations = AsyncOrganizations(self._session) + self.pii = AsyncPII(self._session) + self.radio_settings = AsyncRadioSettings(self._session) + self.saml_roles = AsyncSAMLRoles(self._session) + self.sm = AsyncSM(self._session) + self.snmp_settings = AsyncSNMPSettings(self._session) + self.ssids = AsyncSSIDs(self._session) + self.security_events = AsyncSecurityEvents(self._session) + self.splash_login_attempts = AsyncSplashLoginAttempts(self._session) + self.splash_settings = AsyncSplashSettings(self._session) + self.switch_acls = AsyncSwitchACLs(self._session) + self.switch_port_schedules = AsyncSwitchPortSchedules(self._session) + self.switch_ports = AsyncSwitchPorts(self._session) + self.switch_profiles = AsyncSwitchProfiles(self._session) + self.switch_settings = AsyncSwitchSettings(self._session) + self.switch_stacks = AsyncSwitchStacks(self._session) + self.syslog_servers = AsyncSyslogServers(self._session) + self.traffic_analysis_settings = AsyncTrafficAnalysisSettings(self._session) + self.traffic_shaping = AsyncTrafficShaping(self._session) + self.uplink_settings = AsyncUplinkSettings(self._session) + self.vlans = AsyncVLANs(self._session) + self.webhook_logs = AsyncWebhookLogs(self._session) + self.wireless_health = AsyncWirelessHealth(self._session) + self.wireless_settings = AsyncWirelessSettings(self._session) + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self._session.close() diff --git a/meraki/aio/api/__init__.py b/meraki/aio/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/meraki/aio/api/action_batches.py b/meraki/aio/api/action_batches.py new file mode 100644 index 00000000..5dca5aab --- /dev/null +++ b/meraki/aio/api/action_batches.py @@ -0,0 +1,103 @@ +class AsyncActionBatches: + def __init__(self, session): + super().__init__() + self._session = session + + async def createOrganizationActionBatch(self, organizationId: str, actions: list, **kwargs): + """ + **Create an action batch** + https://api.meraki.com/api_docs#create-an-action-batch + + - organizationId (string) + - actions (array): A set of changes to make as part of this action (more details) + - confirmed (boolean): Set to true for immediate execution. Set to false if the action should be previewed before executing. This property cannot be unset once it is true. Defaults to false. + - synchronous (boolean): Set to true to force the batch to run synchronous. There can be at most 20 actions in synchronous batch. Defaults to false. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Action batches'], + 'operation': 'createOrganizationActionBatch', + } + resource = f'/organizations/{organizationId}/actionBatches' + + body_params = ['confirmed', 'synchronous', 'actions'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganizationActionBatches(self, organizationId: str): + """ + **Return the list of action batches in the organization** + https://api.meraki.com/api_docs#return-the-list-of-action-batches-in-the-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Action batches'], + 'operation': 'getOrganizationActionBatches', + } + resource = f'/organizations/{organizationId}/actionBatches' + + return await self._session.get(metadata, resource) + + async def getOrganizationActionBatch(self, organizationId: str, actionBatchId: str): + """ + **Return an action batch** + https://api.meraki.com/api_docs#return-an-action-batch + + - organizationId (string) + - actionBatchId (string) + """ + + metadata = { + 'tags': ['Action batches'], + 'operation': 'getOrganizationActionBatch', + } + resource = f'/organizations/{organizationId}/actionBatches/{actionBatchId}' + + return await self._session.get(metadata, resource) + + async def deleteOrganizationActionBatch(self, organizationId: str, actionBatchId: str): + """ + **Delete an action batch** + https://api.meraki.com/api_docs#delete-an-action-batch + + - organizationId (string) + - actionBatchId (string) + """ + + metadata = { + 'tags': ['Action batches'], + 'operation': 'deleteOrganizationActionBatch', + } + resource = f'/organizations/{organizationId}/actionBatches/{actionBatchId}' + + return await self._session.delete(metadata, resource) + + async def updateOrganizationActionBatch(self, organizationId: str, actionBatchId: str, **kwargs): + """ + **Update an action batch** + https://api.meraki.com/api_docs#update-an-action-batch + + - organizationId (string) + - actionBatchId (string) + - confirmed (boolean): A boolean representing whether or not the batch has been confirmed. This property cannot be unset once it is true. + - synchronous (boolean): Set to true to force the batch to run synchronous. There can be at most 20 actions in synchronous batch. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Action batches'], + 'operation': 'updateOrganizationActionBatch', + } + resource = f'/organizations/{organizationId}/actionBatches/{actionBatchId}' + + body_params = ['confirmed', 'synchronous'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/admins.py b/meraki/aio/api/admins.py new file mode 100644 index 00000000..7f1841b7 --- /dev/null +++ b/meraki/aio/api/admins.py @@ -0,0 +1,98 @@ +class AsyncAdmins: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationAdmins(self, organizationId: str): + """ + **List the dashboard administrators in this organization** + https://api.meraki.com/api_docs#list-the-dashboard-administrators-in-this-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Admins'], + 'operation': 'getOrganizationAdmins', + } + resource = f'/organizations/{organizationId}/admins' + + return await self._session.get(metadata, resource) + + async def createOrganizationAdmin(self, organizationId: str, email: str, name: str, orgAccess: str, **kwargs): + """ + **Create a new dashboard administrator** + https://api.meraki.com/api_docs#create-a-new-dashboard-administrator + + - organizationId (string) + - email (string): The email of the dashboard administrator. This attribute can not be updated. + - name (string): The name of the dashboard administrator + - orgAccess (string): The privilege of the dashboard administrator on the organization. Can be one of 'full', 'read-only', 'enterprise' or 'none' + - tags (array): The list of tags that the dashboard administrator has privileges on + - networks (array): The list of networks that the dashboard administrator has privileges on + """ + + kwargs.update(locals()) + + if 'orgAccess' in kwargs: + options = ['full', 'read-only', 'enterprise', 'none'] + assert kwargs['orgAccess'] in options, f'''"orgAccess" cannot be "{kwargs['orgAccess']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Admins'], + 'operation': 'createOrganizationAdmin', + } + resource = f'/organizations/{organizationId}/admins' + + body_params = ['email', 'name', 'orgAccess', 'tags', 'networks'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def updateOrganizationAdmin(self, organizationId: str, id: str, **kwargs): + """ + **Update an administrator** + https://api.meraki.com/api_docs#update-an-administrator + + - organizationId (string) + - id (string) + - name (string): The name of the dashboard administrator + - orgAccess (string): The privilege of the dashboard administrator on the organization. Can be one of 'full', 'read-only', 'enterprise' or 'none' + - tags (array): The list of tags that the dashboard administrator has privileges on + - networks (array): The list of networks that the dashboard administrator has privileges on + """ + + kwargs.update(locals()) + + if 'orgAccess' in kwargs: + options = ['full', 'read-only', 'enterprise', 'none'] + assert kwargs['orgAccess'] in options, f'''"orgAccess" cannot be "{kwargs['orgAccess']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Admins'], + 'operation': 'updateOrganizationAdmin', + } + resource = f'/organizations/{organizationId}/admins/{id}' + + body_params = ['name', 'orgAccess', 'tags', 'networks'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteOrganizationAdmin(self, organizationId: str, id: str): + """ + **Revoke all access for a dashboard administrator within this organization** + https://api.meraki.com/api_docs#revoke-all-access-for-a-dashboard-administrator-within-this-organization + + - organizationId (string) + - id (string) + """ + + metadata = { + 'tags': ['Admins'], + 'operation': 'deleteOrganizationAdmin', + } + resource = f'/organizations/{organizationId}/admins/{id}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/alert_settings.py b/meraki/aio/api/alert_settings.py new file mode 100644 index 00000000..3c7f52a6 --- /dev/null +++ b/meraki/aio/api/alert_settings.py @@ -0,0 +1,44 @@ +class AsyncAlertSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkAlertSettings(self, networkId: str): + """ + **Return the alert configuration for this network** + https://api.meraki.com/api_docs#return-the-alert-configuration-for-this-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Alert settings'], + 'operation': 'getNetworkAlertSettings', + } + resource = f'/networks/{networkId}/alertSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkAlertSettings(self, networkId: str, **kwargs): + """ + **Update the alert configuration for this network** + https://api.meraki.com/api_docs#update-the-alert-configuration-for-this-network + + - networkId (string) + - defaultDestinations (object): The network_wide destinations for all alerts on the network. + - alerts (array): Alert-specific configuration for each type. Only alerts that pertain to the network can be updated. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Alert settings'], + 'operation': 'updateNetworkAlertSettings', + } + resource = f'/networks/{networkId}/alertSettings' + + body_params = ['defaultDestinations', 'alerts'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/api_usage.py b/meraki/aio/api/api_usage.py new file mode 100644 index 00000000..650588ce --- /dev/null +++ b/meraki/aio/api/api_usage.py @@ -0,0 +1,64 @@ +class AsyncAPIUsage: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationApiRequests(self, organizationId: str, total_pages=1, direction='next', **kwargs): + """ + **List the API requests made by an organization** + https://api.meraki.com/api_docs#list-the-api-requests-made-by-an-organization + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 31 days. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - adminId (string): Filter the results by the ID of the admin who made the API requests + - path (string): Filter the results by the path of the API requests + - method (string): Filter the results by the method of the API requests (must be 'GET', 'PUT', 'POST' or 'DELETE') + - responseCode (integer): Filter the results by the response code of the API requests + - sourceIp (string): Filter the results by the IP address of the originating API request + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['API usage'], + 'operation': 'getOrganizationApiRequests', + } + resource = f'/organizations/{organizationId}/apiRequests' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore', 'adminId', 'path', 'method', 'responseCode', 'sourceIp'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getOrganizationApiRequestsOverview(self, organizationId: str, **kwargs): + """ + **Return an aggregated overview of API requests data** + https://api.meraki.com/api_docs#return-an-aggregated-overview-of-api-requests-data + + - organizationId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 31 days. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['API usage'], + 'operation': 'getOrganizationApiRequestsOverview', + } + resource = f'/organizations/{organizationId}/apiRequests/overview' + + query_params = ['t0', 't1', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/bluetooth_clients.py b/meraki/aio/api/bluetooth_clients.py new file mode 100644 index 00000000..6b479320 --- /dev/null +++ b/meraki/aio/api/bluetooth_clients.py @@ -0,0 +1,59 @@ +class AsyncBluetoothClients: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkBluetoothClients(self, networkId: str, total_pages=1, direction='next', **kwargs): + """ + **List the Bluetooth clients seen by APs in this network** + https://api.meraki.com/api_docs#list-the-bluetooth-clients-seen-by-aps-in-this-network + + - networkId (string) + - total_pages (integer or string): total number of pages to retrieve, -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 7 days from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 7 days. The default is 1 day. + - perPage (integer): The number of entries per page returned. Acceptable range is 5 - 1000. Default is 10. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - includeConnectivityHistory (boolean): Include the connectivity history for this client + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Bluetooth clients'], + 'operation': 'getNetworkBluetoothClients', + } + resource = f'/networks/{networkId}/bluetoothClients' + + query_params = ['t0', 'timespan', 'perPage', 'startingAfter', 'endingBefore', 'includeConnectivityHistory'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkBluetoothClient(self, networkId: str, bluetoothClientId: str, **kwargs): + """ + **Return a Bluetooth client. Bluetooth clients can be identified by their ID or their MAC.** + https://api.meraki.com/api_docs#return-a-bluetooth-client + + - networkId (string) + - bluetoothClientId (string) + - includeConnectivityHistory (boolean): Include the connectivity history for this client + - connectivityHistoryTimespan (integer): The timespan, in seconds, for the connectivityHistory data. By default 1 day, 86400, will be used. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Bluetooth clients'], + 'operation': 'getNetworkBluetoothClient', + } + resource = f'/networks/{networkId}/bluetoothClients/{bluetoothClientId}' + + query_params = ['includeConnectivityHistory', 'connectivityHistoryTimespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/bluetooth_settings.py b/meraki/aio/api/bluetooth_settings.py new file mode 100644 index 00000000..4943c346 --- /dev/null +++ b/meraki/aio/api/bluetooth_settings.py @@ -0,0 +1,92 @@ +class AsyncBluetoothSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceWirelessBluetoothSettings(self, serial: str): + """ + **Return the bluetooth settings for a wireless device** + https://api.meraki.com/api_docs#return-the-bluetooth-settings-for-a-wireless-device + + - serial (string) + """ + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'getDeviceWirelessBluetoothSettings', + } + resource = f'/devices/{serial}/wireless/bluetooth/settings' + + return await self._session.get(metadata, resource) + + async def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs): + """ + **Update the bluetooth settings for a wireless device** + https://api.meraki.com/api_docs#update-the-bluetooth-settings-for-a-wireless-device + + - serial (string) + - uuid (string): Desired UUID of the beacon. If the value is set to null it will reset to Dashboard's automatically generated value. + - major (integer): Desired major value of the beacon. If the value is set to null it will reset to Dashboard's automatically generated value. + - minor (integer): Desired minor value of the beacon. If the value is set to null it will reset to Dashboard's automatically generated value. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'updateDeviceWirelessBluetoothSettings', + } + resource = f'/devices/{serial}/wireless/bluetooth/settings' + + body_params = ['uuid', 'major', 'minor'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkBluetoothSettings(self, networkId: str): + """ + **Return the Bluetooth settings for a network. Bluetooth settings must be enabled on the network.** + https://api.meraki.com/api_docs#return-the-bluetooth-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'getNetworkBluetoothSettings', + } + resource = f'/networks/{networkId}/bluetoothSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkBluetoothSettings(self, networkId: str, **kwargs): + """ + **Update the Bluetooth settings for a network. See the docs page for Bluetooth settings.** + https://api.meraki.com/api_docs#update-the-bluetooth-settings-for-a-network + + - networkId (string) + - scanningEnabled (boolean): Whether APs will scan for Bluetooth enabled clients. (true, false) + - advertisingEnabled (boolean): Whether APs will advertise beacons. (true, false) + - uuid (string): The UUID to be used in the beacon identifier. + - majorMinorAssignmentMode (string): The way major and minor number should be assigned to nodes in the network. ('Unique', 'Non-unique') + - major (integer): The major number to be used in the beacon identifier. Only valid in 'Non-unique' mode. + - minor (integer): The minor number to be used in the beacon identifier. Only valid in 'Non-unique' mode. + """ + + kwargs.update(locals()) + + if 'majorMinorAssignmentMode' in kwargs: + options = ['Unique', 'Non-unique'] + assert kwargs['majorMinorAssignmentMode'] in options, f'''"majorMinorAssignmentMode" cannot be "{kwargs['majorMinorAssignmentMode']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'updateNetworkBluetoothSettings', + } + resource = f'/networks/{networkId}/bluetoothSettings' + + body_params = ['scanningEnabled', 'advertisingEnabled', 'uuid', 'majorMinorAssignmentMode', 'major', 'minor'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/camera_quality_retention_profiles.py b/meraki/aio/api/camera_quality_retention_profiles.py new file mode 100644 index 00000000..7ed39cb0 --- /dev/null +++ b/meraki/aio/api/camera_quality_retention_profiles.py @@ -0,0 +1,116 @@ +class AsyncCameraQualityRetentionProfiles: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkCameraQualityRetentionProfiles(self, networkId: str): + """ + **List the quality retention profiles for this network** + https://api.meraki.com/api_docs#list-the-quality-retention-profiles-for-this-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Camera quality retention profiles'], + 'operation': 'getNetworkCameraQualityRetentionProfiles', + } + resource = f'/networks/{networkId}/camera/qualityRetentionProfiles' + + return await self._session.get(metadata, resource) + + async def createNetworkCameraQualityRetentionProfile(self, networkId: str, name: str, **kwargs): + """ + **Creates new quality retention profile for this network.** + https://api.meraki.com/api_docs#creates-new-quality-retention-profile-for-this-network + + - networkId (string) + - name (string): The name of the new profile. Must be unique. This parameter is required. + - motionBasedRetentionEnabled (boolean): Deletes footage older than 3 days in which no motion was detected. Can be either true or false. Defaults to false. + - restrictedBandwidthModeEnabled (boolean): Disable features that require additional bandwidth such as Motion Recap. Can be either true or false. Defaults to false. + - audioRecordingEnabled (boolean): Whether or not to record audio. Can be either true or false. Defaults to false. + - cloudArchiveEnabled (boolean): Create redundant video backup using Cloud Archive. Can be either true or false. Defaults to false. + - motionDetectorVersion (integer): The version of the motion detector that will be used by the camera. Only applies to Gen 2 cameras. Defaults to v2. + - scheduleId (string): Schedule for which this camera will record video, or 'null' to always record. + - maxRetentionDays (integer): The maximum number of days for which the data will be stored, or 'null' to keep data until storage space runs out. If the former, it can be one of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 30, 60, 90] days + - videoSettings (object): Video quality and resolution settings for all the camera models. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Camera quality retention profiles'], + 'operation': 'createNetworkCameraQualityRetentionProfile', + } + resource = f'/networks/{networkId}/camera/qualityRetentionProfiles' + + body_params = ['name', 'motionBasedRetentionEnabled', 'restrictedBandwidthModeEnabled', 'audioRecordingEnabled', 'cloudArchiveEnabled', 'motionDetectorVersion', 'scheduleId', 'maxRetentionDays', 'videoSettings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkCameraQualityRetentionProfile(self, networkId: str, qualityRetentionProfileId: str): + """ + **Retrieve a single quality retention profile** + https://api.meraki.com/api_docs#retrieve-a-single-quality-retention-profile + + - networkId (string) + - qualityRetentionProfileId (string) + """ + + metadata = { + 'tags': ['Camera quality retention profiles'], + 'operation': 'getNetworkCameraQualityRetentionProfile', + } + resource = f'/networks/{networkId}/camera/qualityRetentionProfiles/{qualityRetentionProfileId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkCameraQualityRetentionProfile(self, networkId: str, qualityRetentionProfileId: str, **kwargs): + """ + **Update an existing quality retention profile for this network.** + https://api.meraki.com/api_docs#update-an-existing-quality-retention-profile-for-this-network + + - networkId (string) + - qualityRetentionProfileId (string) + - name (string): The name of the new profile. Must be unique. + - motionBasedRetentionEnabled (boolean): Deletes footage older than 3 days in which no motion was detected. Can be either true or false. Defaults to false. + - restrictedBandwidthModeEnabled (boolean): Disable features that require additional bandwidth such as Motion Recap. Can be either true or false. Defaults to false. + - audioRecordingEnabled (boolean): Whether or not to record audio. Can be either true or false. Defaults to false. + - cloudArchiveEnabled (boolean): Create redundant video backup using Cloud Archive. Can be either true or false. Defaults to false. + - motionDetectorVersion (integer): The version of the motion detector that will be used by the camera. Only applies to Gen 2 cameras. Defaults to v2. + - scheduleId (string): Schedule for which this camera will record video, or 'null' to always record. + - maxRetentionDays (integer): The maximum number of days for which the data will be stored, or 'null' to keep data until storage space runs out. If the former, it can be one of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 30, 60, 90] days + - videoSettings (object): Video quality and resolution settings for all the camera models. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Camera quality retention profiles'], + 'operation': 'updateNetworkCameraQualityRetentionProfile', + } + resource = f'/networks/{networkId}/camera/qualityRetentionProfiles/{qualityRetentionProfileId}' + + body_params = ['name', 'motionBasedRetentionEnabled', 'restrictedBandwidthModeEnabled', 'audioRecordingEnabled', 'cloudArchiveEnabled', 'motionDetectorVersion', 'scheduleId', 'maxRetentionDays', 'videoSettings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkCameraQualityRetentionProfile(self, networkId: str, qualityRetentionProfileId: str): + """ + **Delete an existing quality retention profile for this network.** + https://api.meraki.com/api_docs#delete-an-existing-quality-retention-profile-for-this-network + + - networkId (string) + - qualityRetentionProfileId (string) + """ + + metadata = { + 'tags': ['Camera quality retention profiles'], + 'operation': 'deleteNetworkCameraQualityRetentionProfile', + } + resource = f'/networks/{networkId}/camera/qualityRetentionProfiles/{qualityRetentionProfileId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/cameras.py b/meraki/aio/api/cameras.py new file mode 100644 index 00000000..259ba24e --- /dev/null +++ b/meraki/aio/api/cameras.py @@ -0,0 +1,118 @@ +class AsyncCameras: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceCameraQualityAndRetentionSettings(self, serial: str): + """ + **Returns quality and retention settings for the given camera** + https://api.meraki.com/api_docs#returns-quality-and-retention-settings-for-the-given-camera + + - serial (string) + """ + + metadata = { + 'tags': ['Cameras'], + 'operation': 'getDeviceCameraQualityAndRetentionSettings', + } + resource = f'/devices/{serial}/camera/qualityAndRetentionSettings' + + return await self._session.get(metadata, resource) + + async def updateDeviceCameraQualityAndRetentionSettings(self, serial: str, **kwargs): + """ + **Update quality and retention settings for the given camera** + https://api.meraki.com/api_docs#update-quality-and-retention-settings-for-the-given-camera + + - serial (string) + - profileId (string): The ID of a quality and retention profile to assign to the camera. The profile's settings will override all of the per-camera quality and retention settings. If the value of this parameter is null, any existing profile will be unassigned from the camera. + - motionBasedRetentionEnabled (boolean): Boolean indicating if motion-based retention is enabled(true) or disabled(false) on the camera + - audioRecordingEnabled (boolean): Boolean indicating if audio recording is enabled(true) or disabled(false) on the camera + - restrictedBandwidthModeEnabled (boolean): Boolean indicating if restricted bandwidth is enabled(true) or disabled(false) on the camera + - quality (string): Quality of the camera. Can be one of 'Standard', 'High' or 'Enhanced'. Not all qualities are supported by every camera model. + - resolution (string): Resolution of the camera. Can be one of '1280x720', '1920x1080', '1080x1080' or '2058x2058'. Not all resolutions are supported by every camera model. + """ + + kwargs.update(locals()) + + if 'quality' in kwargs: + options = ['Standard', 'High', 'Enhanced'] + assert kwargs['quality'] in options, f'''"quality" cannot be "{kwargs['quality']}", & must be set to one of: {options}''' + if 'resolution' in kwargs: + options = ['1280x720', '1920x1080', '1080x1080', '2058x2058'] + assert kwargs['resolution'] in options, f'''"resolution" cannot be "{kwargs['resolution']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Cameras'], + 'operation': 'updateDeviceCameraQualityAndRetentionSettings', + } + resource = f'/devices/{serial}/camera/qualityAndRetentionSettings' + + body_params = ['profileId', 'motionBasedRetentionEnabled', 'audioRecordingEnabled', 'restrictedBandwidthModeEnabled', 'quality', 'resolution'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkCameraSchedules(self, networkId: str): + """ + **Returns a list of all camera recording schedules.** + https://api.meraki.com/api_docs#returns-a-list-of-all-camera-recording-schedules + + - networkId (string) + """ + + metadata = { + 'tags': ['Cameras'], + 'operation': 'getNetworkCameraSchedules', + } + resource = f'/networks/{networkId}/camera/schedules' + + return await self._session.get(metadata, resource) + + async def generateNetworkCameraSnapshot(self, networkId: str, serial: str, **kwargs): + """ + **Generate a snapshot of what the camera sees at the specified time and return a link to that image.** + https://api.meraki.com/api_docs#generate-a-snapshot-of-what-the-camera-sees-at-the-specified-time-and-return-a-link-to-that-image + + - networkId (string) + - serial (string) + - timestamp (string): [optional] The snapshot will be taken from this time on the camera. The timestamp is expected to be in ISO 8601 format. If no timestamp is specified, we will assume current time. + - fullframe (boolean): [optional] If set to "true" the snapshot will be taken at full sensor resolution. This will error if used with timestamp. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Cameras'], + 'operation': 'generateNetworkCameraSnapshot', + } + resource = f'/networks/{networkId}/cameras/{serial}/snapshot' + + body_params = ['timestamp', 'fullframe'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkCameraVideoLink(self, networkId: str, serial: str, **kwargs): + """ + **Returns video link to the specified camera. If a timestamp is supplied, it links to that timestamp.** + https://api.meraki.com/api_docs#returns-video-link-to-the-specified-camera + + - networkId (string) + - serial (string) + - timestamp (string): [optional] The video link will start at this timestamp. The timestamp is in UNIX Epoch time (milliseconds). If no timestamp is specified, we will assume current time. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Cameras'], + 'operation': 'getNetworkCameraVideoLink', + } + resource = f'/networks/{networkId}/cameras/{serial}/videoLink' + + query_params = ['timestamp'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/change_log.py b/meraki/aio/api/change_log.py new file mode 100644 index 00000000..ed7a1f3d --- /dev/null +++ b/meraki/aio/api/change_log.py @@ -0,0 +1,37 @@ +class AsyncChangeLog: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationConfigurationChanges(self, organizationId: str, total_pages=1, direction='prev', **kwargs): + """ + **View the Change Log for your organization** + https://api.meraki.com/api_docs#view-the-change-log-for-your-organization + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "prev" (default) or "next" page + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 365 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 365 days. The default is 365 days. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 5000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - networkId (string): Filters on the given network + - adminId (string): Filters on the given Admin + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Change log'], + 'operation': 'getOrganizationConfigurationChanges', + } + resource = f'/organizations/{organizationId}/configurationChanges' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore', 'networkId', 'adminId'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + diff --git a/meraki/aio/api/clients.py b/meraki/aio/api/clients.py new file mode 100644 index 00000000..4e378f72 --- /dev/null +++ b/meraki/aio/api/clients.py @@ -0,0 +1,285 @@ +class AsyncClients: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceClients(self, serial: str, **kwargs): + """ + **List the clients of a device, up to a maximum of a month ago. The usage of each client is returned in kilobytes. If the device is a switch, the switchport is returned; otherwise the switchport field is null.** + https://api.meraki.com/api_docs#list-the-clients-of-a-device-up-to-a-maximum-of-a-month-ago + + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Clients'], + 'operation': 'getDeviceClients', + } + resource = f'/devices/{serial}/clients' + + query_params = ['t0', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkClients(self, networkId: str, total_pages=1, direction='next', **kwargs): + """ + **List the clients that have used this network in the timespan** + https://api.meraki.com/api_docs#list-the-clients-that-have-used-this-network-in-the-timespan + + - networkId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClients', + } + resource = f'/networks/{networkId}/clients' + + query_params = ['t0', 'timespan', 'perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def provisionNetworkClients(self, networkId: str, mac: str, devicePolicy: str, **kwargs): + """ + **Provisions a client with a name and policy. Clients can be provisioned before they associate to the network.** + https://api.meraki.com/api_docs#provisions-a-client-with-a-name-and-policy + + - networkId (string) + - mac (string): The MAC address of the client. Required. + - devicePolicy (string): The policy to apply to the specified client. Can be 'Group policy', 'Whitelisted', 'Blocked', 'Per connection' or 'Normal'. Required. + - name (string): The display name for the client. Optional. Limited to 255 bytes. + - groupPolicyId (string): The ID of the desired group policy to apply to the client. Required if 'devicePolicy' is set to "Group policy". Otherwise this is ignored. + - policiesBySecurityAppliance (object): An object, describing what the policy-connection association is for the security appliance. (Only relevant if the security appliance is actually within the network) + - policiesBySsid (object): An object, describing the policy-connection associations for each active SSID within the network. Keys should be the number of enabled SSIDs, mapping to an object describing the client's policy + """ + + kwargs.update(locals()) + + if 'devicePolicy' in kwargs: + options = ['Group policy', 'Whitelisted', 'Blocked', 'Per connection', 'Normal'] + assert kwargs['devicePolicy'] in options, f'''"devicePolicy" cannot be "{kwargs['devicePolicy']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Clients'], + 'operation': 'provisionNetworkClients', + } + resource = f'/networks/{networkId}/clients/provision' + + body_params = ['mac', 'name', 'devicePolicy', 'groupPolicyId', 'policiesBySecurityAppliance', 'policiesBySsid'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkClient(self, networkId: str, clientId: str): + """ + **Return the client associated with the given identifier. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#return-the-client-associated-with-the-given-identifier + + - networkId (string) + - clientId (string) + """ + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClient', + } + resource = f'/networks/{networkId}/clients/{clientId}' + + return await self._session.get(metadata, resource) + + async def getNetworkClientEvents(self, networkId: str, clientId: str, total_pages=1, direction='next', **kwargs): + """ + **Return the events associated with this client. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#return-the-events-associated-with-this-client + + - networkId (string) + - clientId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 100. Default is 100. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClientEvents', + } + resource = f'/networks/{networkId}/clients/{clientId}/events' + + query_params = ['perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkClientLatencyHistory(self, networkId: str, clientId: str, **kwargs): + """ + **Return the latency history for a client. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP. The latency data is from a sample of 2% of packets and is grouped into 4 traffic categories: background, best effort, video, voice. Within these categories the sampled packet counters are bucketed by latency in milliseconds.** + https://api.meraki.com/api_docs#return-the-latency-history-for-a-client + + - networkId (string) + - clientId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 791 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 791 days after t0. + - timespan (number): The timespan for 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 791 days. The default is 1 day. + - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 86400. The default is 86400. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClientLatencyHistory', + } + resource = f'/networks/{networkId}/clients/{clientId}/latencyHistory' + + query_params = ['t0', 't1', 'timespan', 'resolution'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkClientPolicy(self, networkId: str, clientId: str): + """ + **Return the policy assigned to a client on the network. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#return-the-policy-assigned-to-a-client-on-the-network + + - networkId (string) + - clientId (string) + """ + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClientPolicy', + } + resource = f'/networks/{networkId}/clients/{clientId}/policy' + + return await self._session.get(metadata, resource) + + async def updateNetworkClientPolicy(self, networkId: str, clientId: str, devicePolicy: str, **kwargs): + """ + **Update the policy assigned to a client on the network. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#update-the-policy-assigned-to-a-client-on-the-network + + - networkId (string) + - clientId (string) + - devicePolicy (string): The policy to assign. Can be 'Whitelisted', 'Blocked', 'Normal' or 'Group policy'. Required. + - groupPolicyId (string): [optional] If 'devicePolicy' is set to 'Group policy' this param is used to specify the group policy ID. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Clients'], + 'operation': 'updateNetworkClientPolicy', + } + resource = f'/networks/{networkId}/clients/{clientId}/policy' + + body_params = ['devicePolicy', 'groupPolicyId'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkClientSplashAuthorizationStatus(self, networkId: str, clientId: str): + """ + **Return the splash authorization for a client, for each SSID they've associated with through splash. Only enabled SSIDs with Click-through splash enabled will be included. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#return-the-splash-authorization-for-a-client-for-each-ssid-theyve-associated-with-through-splash + + - networkId (string) + - clientId (string) + """ + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClientSplashAuthorizationStatus', + } + resource = f'/networks/{networkId}/clients/{clientId}/splashAuthorizationStatus' + + return await self._session.get(metadata, resource) + + async def updateNetworkClientSplashAuthorizationStatus(self, networkId: str, clientId: str, ssids: dict): + """ + **Update a client's splash authorization. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#update-a-clients-splash-authorization + + - networkId (string) + - clientId (string) + - ssids (object): The target SSIDs. Each SSID must be enabled and must have Click-through splash enabled. For each SSID where isAuthorized is true, the expiration time will automatically be set according to the SSID's splash frequency. Not all networks support configuring all SSIDs + """ + + kwargs = locals() + + metadata = { + 'tags': ['Clients'], + 'operation': 'updateNetworkClientSplashAuthorizationStatus', + } + resource = f'/networks/{networkId}/clients/{clientId}/splashAuthorizationStatus' + + body_params = ['ssids'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkClientTrafficHistory(self, networkId: str, clientId: str, total_pages=1, direction='next', **kwargs): + """ + **Return the client's network traffic data over time. Usage data is in kilobytes. This endpoint requires detailed traffic analysis to be enabled on the Network-wide > General page. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#return-the-clients-network-traffic-data-over-time + + - networkId (string) + - clientId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClientTrafficHistory', + } + resource = f'/networks/{networkId}/clients/{clientId}/trafficHistory' + + query_params = ['perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkClientUsageHistory(self, networkId: str, clientId: str): + """ + **Return the client's daily usage history. Usage data is in kilobytes. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#return-the-clients-daily-usage-history + + - networkId (string) + - clientId (string) + """ + + metadata = { + 'tags': ['Clients'], + 'operation': 'getNetworkClientUsageHistory', + } + resource = f'/networks/{networkId}/clients/{clientId}/usageHistory' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/config_templates.py b/meraki/aio/api/config_templates.py new file mode 100644 index 00000000..50bb2a24 --- /dev/null +++ b/meraki/aio/api/config_templates.py @@ -0,0 +1,38 @@ +class AsyncConfigTemplates: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationConfigTemplates(self, organizationId: str): + """ + **List the configuration templates for this organization** + https://api.meraki.com/api_docs#list-the-configuration-templates-for-this-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Config templates'], + 'operation': 'getOrganizationConfigTemplates', + } + resource = f'/organizations/{organizationId}/configTemplates' + + return await self._session.get(metadata, resource) + + async def deleteOrganizationConfigTemplate(self, organizationId: str, configTemplateId: str): + """ + **Remove a configuration template** + https://api.meraki.com/api_docs#remove-a-configuration-template + + - organizationId (string) + - configTemplateId (string) + """ + + metadata = { + 'tags': ['Config templates'], + 'operation': 'deleteOrganizationConfigTemplate', + } + resource = f'/organizations/{organizationId}/configTemplates/{configTemplateId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/connectivity_monitoring_destinations.py b/meraki/aio/api/connectivity_monitoring_destinations.py new file mode 100644 index 00000000..c33ace2e --- /dev/null +++ b/meraki/aio/api/connectivity_monitoring_destinations.py @@ -0,0 +1,43 @@ +class AsyncConnectivityMonitoringDestinations: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkConnectivityMonitoringDestinations(self, networkId: str): + """ + **Return the connectivity testing destinations for an MX network** + https://api.meraki.com/api_docs#return-the-connectivity-testing-destinations-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Connectivity monitoring destinations'], + 'operation': 'getNetworkConnectivityMonitoringDestinations', + } + resource = f'/networks/{networkId}/connectivityMonitoringDestinations' + + return await self._session.get(metadata, resource) + + async def updateNetworkConnectivityMonitoringDestinations(self, networkId: str, **kwargs): + """ + **Update the connectivity testing destinations for an MX network** + https://api.meraki.com/api_docs#update-the-connectivity-testing-destinations-for-an-mx-network + + - networkId (string) + - destinations (array): The list of connectivity monitoring destinations + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Connectivity monitoring destinations'], + 'operation': 'updateNetworkConnectivityMonitoringDestinations', + } + resource = f'/networks/{networkId}/connectivityMonitoringDestinations' + + body_params = ['destinations'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/content_filtering_categories.py b/meraki/aio/api/content_filtering_categories.py new file mode 100644 index 00000000..adde441c --- /dev/null +++ b/meraki/aio/api/content_filtering_categories.py @@ -0,0 +1,21 @@ +class AsyncContentFilteringCategories: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkContentFilteringCategories(self, networkId: str): + """ + **List all available content filtering categories for an MX network** + https://api.meraki.com/api_docs#list-all-available-content-filtering-categories-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Content filtering categories'], + 'operation': 'getNetworkContentFilteringCategories', + } + resource = f'/networks/{networkId}/contentFiltering/categories' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/content_filtering_rules.py b/meraki/aio/api/content_filtering_rules.py new file mode 100644 index 00000000..501f9238 --- /dev/null +++ b/meraki/aio/api/content_filtering_rules.py @@ -0,0 +1,50 @@ +class AsyncContentFilteringRules: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkContentFiltering(self, networkId: str): + """ + **Return the content filtering settings for an MX network** + https://api.meraki.com/api_docs#return-the-content-filtering-settings-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Content filtering rules'], + 'operation': 'getNetworkContentFiltering', + } + resource = f'/networks/{networkId}/contentFiltering' + + return await self._session.get(metadata, resource) + + async def updateNetworkContentFiltering(self, networkId: str, **kwargs): + """ + **Update the content filtering settings for an MX network** + https://api.meraki.com/api_docs#update-the-content-filtering-settings-for-an-mx-network + + - networkId (string) + - allowedUrlPatterns (array): A whitelist of URL patterns to allow + - blockedUrlPatterns (array): A blacklist of URL patterns to block + - blockedUrlCategories (array): A list of URL categories to block + - urlCategoryListSize (string): URL category list size which is either 'topSites' or 'fullList' + """ + + kwargs.update(locals()) + + if 'urlCategoryListSize' in kwargs: + options = ['topSites', 'fullList'] + assert kwargs['urlCategoryListSize'] in options, f'''"urlCategoryListSize" cannot be "{kwargs['urlCategoryListSize']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Content filtering rules'], + 'operation': 'updateNetworkContentFiltering', + } + resource = f'/networks/{networkId}/contentFiltering' + + body_params = ['allowedUrlPatterns', 'blockedUrlPatterns', 'blockedUrlCategories', 'urlCategoryListSize'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/dashboard_branding_policies.py b/meraki/aio/api/dashboard_branding_policies.py new file mode 100644 index 00000000..d038a336 --- /dev/null +++ b/meraki/aio/api/dashboard_branding_policies.py @@ -0,0 +1,152 @@ +class AsyncDashboardBrandingPolicies: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationBrandingPolicies(self, organizationId: str): + """ + **List the branding policies of an organization** + https://api.meraki.com/api_docs#list-the-branding-policies-of-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'getOrganizationBrandingPolicies', + } + resource = f'/organizations/{organizationId}/brandingPolicies' + + return await self._session.get(metadata, resource) + + async def createOrganizationBrandingPolicy(self, organizationId: str, name: str, enabled: bool, adminSettings: dict, **kwargs): + """ + **Add a new branding policy to an organization** + https://api.meraki.com/api_docs#add-a-new-branding-policy-to-an-organization + + - organizationId (string) + - name (string): Name of the Dashboard branding policy. + - enabled (boolean): Boolean indicating whether this policy is enabled. + - adminSettings (object): Settings for describing which kinds of admins this policy applies to. + - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of + 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show + the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on + Dashboard; see the documentation for each property to see the allowed values. + Each property defaults to 'default or inherit' when not provided. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'createOrganizationBrandingPolicy', + } + resource = f'/organizations/{organizationId}/brandingPolicies' + + body_params = ['name', 'enabled', 'adminSettings', 'helpSettings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganizationBrandingPoliciesPriorities(self, organizationId: str): + """ + **Return the branding policy IDs of an organization in priority order. IDs are ordered in ascending order of priority (IDs later in the array have higher priority).** + https://api.meraki.com/api_docs#return-the-branding-policy-ids-of-an-organization-in-priority-order + + - organizationId (string) + """ + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'getOrganizationBrandingPoliciesPriorities', + } + resource = f'/organizations/{organizationId}/brandingPolicies/priorities' + + return await self._session.get(metadata, resource) + + async def updateOrganizationBrandingPoliciesPriorities(self, organizationId: str, brandingPolicyIds: list): + """ + **Update the priority ordering of an organization's branding policies.** + https://api.meraki.com/api_docs#update-the-priority-ordering-of-an-organizations-branding-policies + + - organizationId (string) + - brandingPolicyIds (array): A list of branding policy IDs arranged in ascending priority order (IDs later in the array have higher priority). + """ + + kwargs = locals() + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'updateOrganizationBrandingPoliciesPriorities', + } + resource = f'/organizations/{organizationId}/brandingPolicies/priorities' + + body_params = ['brandingPolicyIds'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str): + """ + **Return a branding policy** + https://api.meraki.com/api_docs#return-a-branding-policy + + - organizationId (string) + - brandingPolicyId (string) + """ + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'getOrganizationBrandingPolicy', + } + resource = f'/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}' + + return await self._session.get(metadata, resource) + + async def updateOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str, **kwargs): + """ + **Update a branding policy** + https://api.meraki.com/api_docs#update-a-branding-policy + + - organizationId (string) + - brandingPolicyId (string) + - name (string): Name of the Dashboard branding policy. + - enabled (boolean): Boolean indicating whether this policy is enabled. + - adminSettings (object): Settings for describing which kinds of admins this policy applies to. + - helpSettings (object): Settings for describing the modifications to various Help page features. Each property in this object accepts one of + 'default or inherit' (do not modify functionality), 'hide' (remove the section from Dashboard), or 'show' (always show + the section on Dashboard). Some properties in this object also accept custom HTML used to replace the section on + Dashboard; see the documentation for each property to see the allowed values. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'updateOrganizationBrandingPolicy', + } + resource = f'/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}' + + body_params = ['name', 'enabled', 'adminSettings', 'helpSettings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteOrganizationBrandingPolicy(self, organizationId: str, brandingPolicyId: str): + """ + **Delete a branding policy** + https://api.meraki.com/api_docs#delete-a-branding-policy + + - organizationId (string) + - brandingPolicyId (string) + """ + + metadata = { + 'tags': ['Dashboard branding policies'], + 'operation': 'deleteOrganizationBrandingPolicy', + } + resource = f'/organizations/{organizationId}/brandingPolicies/{brandingPolicyId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/devices.py b/meraki/aio/api/devices.py new file mode 100644 index 00000000..c3183c7c --- /dev/null +++ b/meraki/aio/api/devices.py @@ -0,0 +1,290 @@ +class AsyncDevices: + def __init__(self, session): + super().__init__() + self._session = session + + async def cycleDeviceSwitchPorts(self, serial: str, ports: list): + """ + **Cycle a set of switch ports** + https://api.meraki.com/api_docs#cycle-a-set-of-switch-ports + + - serial (string) + - ports (array): List of switch ports. Example: [1, 2-5, 1_MA-MOD-8X10G_1, 1_MA-MOD-8X10G_2-1_MA-MOD-8X10G_8] + """ + + kwargs = locals() + + metadata = { + 'tags': ['Devices'], + 'operation': 'cycleDeviceSwitchPorts', + } + resource = f'/devices/{serial}/switch/ports/cycle' + + body_params = ['ports'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkDevices(self, networkId: str): + """ + **List the devices in a network** + https://api.meraki.com/api_docs#list-the-devices-in-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Devices'], + 'operation': 'getNetworkDevices', + } + resource = f'/networks/{networkId}/devices' + + return await self._session.get(metadata, resource) + + async def claimNetworkDevices(self, networkId: str, **kwargs): + """ + **Claim devices into a network** + https://api.meraki.com/api_docs#claim-devices-into-a-network + + - networkId (string) + - serials (array): A list of serials of devices to claim + - serial (string): [DEPRECATED] The serial of a device to claim + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Devices'], + 'operation': 'claimNetworkDevices', + } + resource = f'/networks/{networkId}/devices/claim' + + body_params = ['serials', 'serial', 'serials'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkDevice(self, networkId: str, serial: str): + """ + **Return a single device** + https://api.meraki.com/api_docs#return-a-single-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Devices'], + 'operation': 'getNetworkDevice', + } + resource = f'/networks/{networkId}/devices/{serial}' + + return await self._session.get(metadata, resource) + + async def updateNetworkDevice(self, networkId: str, serial: str, **kwargs): + """ + **Update the attributes of a device** + https://api.meraki.com/api_docs#update-the-attributes-of-a-device + + - networkId (string) + - serial (string) + - name (string): The name of a device + - tags (string): The tags of a device + - lat (number): The latitude of a device + - lng (number): The longitude of a device + - address (string): The address of a device + - notes (string): The notes for the device. String. Limited to 255 characters. + - moveMapMarker (boolean): Whether or not to set the latitude and longitude of a device based on the new address. Only applies when lat and lng are not specified. + - switchProfileId (string): The ID of a switch profile to bind to the device (for available switch profiles, see the 'Switch Profiles' endpoint). Use null to unbind the switch device from the current profile. For a device to be bindable to a switch profile, it must (1) be a switch, and (2) belong to a network that is bound to a configuration template. + - floorPlanId (string): The floor plan to associate to this device. null disassociates the device from the floorplan. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Devices'], + 'operation': 'updateNetworkDevice', + } + resource = f'/networks/{networkId}/devices/{serial}' + + body_params = ['name', 'tags', 'lat', 'lng', 'address', 'notes', 'moveMapMarker', 'switchProfileId', 'floorPlanId'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def blinkNetworkDeviceLeds(self, networkId: str, serial: str, **kwargs): + """ + **Blink the LEDs on a device** + https://api.meraki.com/api_docs#blink-the-leds-on-a-device + + - networkId (string) + - serial (string) + - duration (integer): The duration in seconds. Must be between 5 and 120. Default is 20 seconds + - period (integer): The period in milliseconds. Must be between 100 and 1000. Default is 160 milliseconds + - duty (integer): The duty cycle as the percent active. Must be between 10 and 90. Default is 50. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Devices'], + 'operation': 'blinkNetworkDeviceLeds', + } + resource = f'/networks/{networkId}/devices/{serial}/blinkLeds' + + body_params = ['duration', 'period', 'duty'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkDeviceLldp_cdp(self, networkId: str, serial: str, **kwargs): + """ + **List LLDP and CDP information for a device** + https://api.meraki.com/api_docs#list-lldp-and-cdp-information-for-a-device + + - networkId (string) + - serial (string) + - timespan (integer): The timespan for which LLDP and CDP information will be fetched. Must be in seconds and less than or equal to a month (2592000 seconds). LLDP and CDP information is sent to the Meraki dashboard every 10 minutes. In instances where this LLDP and CDP information matches an existing entry in the Meraki dashboard, the data is updated once every two hours. Meraki recommends querying LLDP and CDP information at an interval slightly greater than two hours, to ensure that unchanged CDP / LLDP information can be queried consistently. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Devices'], + 'operation': 'getNetworkDeviceLldp_cdp', + } + resource = f'/networks/{networkId}/devices/{serial}/lldp_cdp' + + query_params = ['timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkDeviceLossAndLatencyHistory(self, networkId: str, serial: str, ip: str, **kwargs): + """ + **Get the uplink loss percentage and latency in milliseconds for a wired network device.** + https://api.meraki.com/api_docs#get-the-uplink-loss-percentage-and-latency-in-milliseconds-for-a-wired-network-device + + - networkId (string) + - serial (string) + - ip (string): The destination IP used to obtain the requested stats. This is required. + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. + - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 60, 600, 3600, 86400. The default is 60. + - uplink (string): The WAN uplink used to obtain the requested stats. Valid uplinks are wan1, wan2, cellular. The default is wan1. + """ + + kwargs.update(locals()) + + if 'uplink' in kwargs: + options = ['wan1', 'wan2', 'cellular'] + assert kwargs['uplink'] in options, f'''"uplink" cannot be "{kwargs['uplink']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Devices'], + 'operation': 'getNetworkDeviceLossAndLatencyHistory', + } + resource = f'/networks/{networkId}/devices/{serial}/lossAndLatencyHistory' + + query_params = ['t0', 't1', 'timespan', 'resolution', 'uplink', 'ip'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkDevicePerformance(self, networkId: str, serial: str): + """ + **Return the performance score for a single device. Only primary MX devices supported. If no data is available, a 204 error code is returned.** + https://api.meraki.com/api_docs#return-the-performance-score-for-a-single-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Devices'], + 'operation': 'getNetworkDevicePerformance', + } + resource = f'/networks/{networkId}/devices/{serial}/performance' + + return await self._session.get(metadata, resource) + + async def rebootNetworkDevice(self, networkId: str, serial: str): + """ + **Reboot a device** + https://api.meraki.com/api_docs#reboot-a-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Devices'], + 'operation': 'rebootNetworkDevice', + } + resource = f'/networks/{networkId}/devices/{serial}/reboot' + + return await self._session.post(metadata, resource) + + async def removeNetworkDevice(self, networkId: str, serial: str): + """ + **Remove a single device** + https://api.meraki.com/api_docs#remove-a-single-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Devices'], + 'operation': 'removeNetworkDevice', + } + resource = f'/networks/{networkId}/devices/{serial}/remove' + + return await self._session.post(metadata, resource) + + async def getNetworkDeviceUplink(self, networkId: str, serial: str): + """ + **Return the uplink information for a device.** + https://api.meraki.com/api_docs#return-the-uplink-information-for-a-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Devices'], + 'operation': 'getNetworkDeviceUplink', + } + resource = f'/networks/{networkId}/devices/{serial}/uplink' + + return await self._session.get(metadata, resource) + + async def getOrganizationDevices(self, organizationId: str, total_pages=1, direction='next', **kwargs): + """ + **List the devices in an organization** + https://api.meraki.com/api_docs#list-the-devices-in-an-organization + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - configurationUpdatedAfter (string): Filter results by whether or not the device's configuration has been updated after the given timestamp + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Devices'], + 'operation': 'getOrganizationDevices', + } + resource = f'/organizations/{organizationId}/devices' + + query_params = ['perPage', 'startingAfter', 'endingBefore', 'configurationUpdatedAfter'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + diff --git a/meraki/aio/api/events.py b/meraki/aio/api/events.py new file mode 100644 index 00000000..dd90c93c --- /dev/null +++ b/meraki/aio/api/events.py @@ -0,0 +1,64 @@ +class AsyncEvents: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkEvents(self, networkId: str, total_pages=1, direction='prev', **kwargs): + """ + **List the events for the network** + https://api.meraki.com/api_docs#list-the-events-for-the-network + + - networkId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "prev" (default) or "next" page + - productType (string): The product type to fetch events for. This parameter is required for networks with multiple device types. Valid types are wireless, appliance, switch, systemsManager, camera, and cellularGateway + - includedEventTypes (array): A list of event types. The returned events will be filtered to only include events with these types. + - excludedEventTypes (array): A list of event types. The returned events will be filtered to exclude events with these types. + - deviceMac (string): The MAC address of the Meraki device which the list of events will be filtered with + - deviceSerial (string): The serial of the Meraki device which the list of events will be filtered with + - deviceName (string): The name of the Meraki device which the list of events will be filtered with + - clientIp (string): The IP of the client which the list of events will be filtered with. Only supported for track-by-IP networks. + - clientMac (string): The MAC address of the client which the list of events will be filtered with. Only supported for track-by-MAC networks. + - clientName (string): The name, or partial name, of the client which the list of events will be filtered with + - smDeviceMac (string): The MAC address of the Systems Manager device which the list of events will be filtered with + - smDeviceName (string): The name of the Systems Manager device which the list of events will be filtered with + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 10. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Events'], + 'operation': 'getNetworkEvents', + } + resource = f'/networks/{networkId}/events' + + query_params = ['productType', 'deviceMac', 'deviceSerial', 'deviceName', 'clientIp', 'clientMac', 'clientName', 'smDeviceMac', 'smDeviceName', 'perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + array_params = ['includedEventTypes', 'excludedEventTypes'] + for (k, v) in kwargs.items(): + if k in array_params: + params[f'{k}[]'] = kwargs[f'{k}'] + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkEventsEventTypes(self, networkId: str): + """ + **List the event type to human-readable description** + https://api.meraki.com/api_docs#list-the-event-type-to-human-readable-description + + - networkId (string) + """ + + metadata = { + 'tags': ['Events'], + 'operation': 'getNetworkEventsEventTypes', + } + resource = f'/networks/{networkId}/events/eventTypes' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/firewalled_services.py b/meraki/aio/api/firewalled_services.py new file mode 100644 index 00000000..fc498946 --- /dev/null +++ b/meraki/aio/api/firewalled_services.py @@ -0,0 +1,66 @@ +class AsyncFirewalledServices: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkFirewalledServices(self, networkId: str): + """ + **List the appliance services and their accessibility rules** + https://api.meraki.com/api_docs#list-the-appliance-services-and-their-accessibility-rules + + - networkId (string) + """ + + metadata = { + 'tags': ['Firewalled services'], + 'operation': 'getNetworkFirewalledServices', + } + resource = f'/networks/{networkId}/firewalledServices' + + return await self._session.get(metadata, resource) + + async def getNetworkFirewalledService(self, networkId: str, service: str): + """ + **Return the accessibility settings of the given service ('ICMP', 'web', or 'SNMP')** + https://api.meraki.com/api_docs#return-the-accessibility-settings-of-the-given-service-icmp-web-or-snmp + + - networkId (string) + - service (string) + """ + + metadata = { + 'tags': ['Firewalled services'], + 'operation': 'getNetworkFirewalledService', + } + resource = f'/networks/{networkId}/firewalledServices/{service}' + + return await self._session.get(metadata, resource) + + async def updateNetworkFirewalledService(self, networkId: str, service: str, access: str, **kwargs): + """ + **Updates the accessibility settings for the given service ('ICMP', 'web', or 'SNMP')** + https://api.meraki.com/api_docs#updates-the-accessibility-settings-for-the-given-service-icmp-web-or-snmp + + - networkId (string) + - service (string) + - access (string): A string indicating the rule for which IPs are allowed to use the specified service. Acceptable values are "blocked" (no remote IPs can access the service), "restricted" (only whitelisted IPs can access the service), and "unrestriced" (any remote IP can access the service). This field is required + - allowedIps (array): An array of whitelisted IPs that can access the service. This field is required if "access" is set to "restricted". Otherwise this field is ignored + """ + + kwargs.update(locals()) + + if 'access' in kwargs: + options = ['blocked', 'restricted', 'unrestricted'] + assert kwargs['access'] in options, f'''"access" cannot be "{kwargs['access']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Firewalled services'], + 'operation': 'updateNetworkFirewalledService', + } + resource = f'/networks/{networkId}/firewalledServices/{service}' + + body_params = ['access', 'allowedIps'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/floorplans.py b/meraki/aio/api/floorplans.py new file mode 100644 index 00000000..b9ea96be --- /dev/null +++ b/meraki/aio/api/floorplans.py @@ -0,0 +1,112 @@ +class AsyncFloorplans: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkFloorPlans(self, networkId: str): + """ + **List the floor plans that belong to your network** + https://api.meraki.com/api_docs#list-the-floor-plans-that-belong-to-your-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Floorplans'], + 'operation': 'getNetworkFloorPlans', + } + resource = f'/networks/{networkId}/floorPlans' + + return await self._session.get(metadata, resource) + + async def createNetworkFloorPlan(self, networkId: str, name: str, imageContents: str, **kwargs): + """ + **Upload a floor plan** + https://api.meraki.com/api_docs#upload-a-floor-plan + + - networkId (string) + - name (string): The name of your floor plan. + - imageContents (string): The file contents (a base 64 encoded string) of your image. Supported formats are PNG, GIF, and JPG. Note that all images are saved as PNG files, regardless of the format they are uploaded in. + - center (object): The longitude and latitude of the center of your floor plan. The 'center' or two adjacent corners (e.g. 'topLeftCorner' and 'bottomLeftCorner') must be specified. If 'center' is specified, the floor plan is placed over that point with no rotation. If two adjacent corners are specified, the floor plan is rotated to line up with the two specified points. The aspect ratio of the floor plan's image is preserved regardless of which corners/center are specified. (This means if that more than two corners are specified, only two corners may be used to preserve the floor plan's aspect ratio.). No two points can have the same latitude, longitude pair. + - bottomLeftCorner (object): The longitude and latitude of the bottom left corner of your floor plan. + - bottomRightCorner (object): The longitude and latitude of the bottom right corner of your floor plan. + - topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan. + - topRightCorner (object): The longitude and latitude of the top right corner of your floor plan. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Floorplans'], + 'operation': 'createNetworkFloorPlan', + } + resource = f'/networks/{networkId}/floorPlans' + + body_params = ['name', 'center', 'bottomLeftCorner', 'bottomRightCorner', 'topLeftCorner', 'topRightCorner', 'imageContents'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkFloorPlan(self, networkId: str, floorPlanId: str): + """ + **Find a floor plan by ID** + https://api.meraki.com/api_docs#find-a-floor-plan-by-id + + - networkId (string) + - floorPlanId (string) + """ + + metadata = { + 'tags': ['Floorplans'], + 'operation': 'getNetworkFloorPlan', + } + resource = f'/networks/{networkId}/floorPlans/{floorPlanId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs): + """ + **Update a floor plan's geolocation and other meta data** + https://api.meraki.com/api_docs#update-a-floor-plans-geolocation-and-other-meta-data + + - networkId (string) + - floorPlanId (string) + - name (string): The name of your floor plan. + - center (object): The longitude and latitude of the center of your floor plan. If you want to change the geolocation data of your floor plan, either the 'center' or two adjacent corners (e.g. 'topLeftCorner' and 'bottomLeftCorner') must be specified. If 'center' is specified, the floor plan is placed over that point with no rotation. If two adjacent corners are specified, the floor plan is rotated to line up with the two specified points. The aspect ratio of the floor plan's image is preserved regardless of which corners/center are specified. (This means if that more than two corners are specified, only two corners may be used to preserve the floor plan's aspect ratio.). No two points can have the same latitude, longitude pair. + - bottomLeftCorner (object): The longitude and latitude of the bottom left corner of your floor plan. + - bottomRightCorner (object): The longitude and latitude of the bottom right corner of your floor plan. + - topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan. + - topRightCorner (object): The longitude and latitude of the top right corner of your floor plan. + - imageContents (string): The file contents (a base 64 encoded string) of your new image. Supported formats are PNG, GIF, and JPG. Note that all images are saved as PNG files, regardless of the format they are uploaded in. If you upload a new image, and you do NOT specify any new geolocation fields ('center, 'topLeftCorner', etc), the floor plan will be recentered with no rotation in order to maintain the aspect ratio of your new image. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Floorplans'], + 'operation': 'updateNetworkFloorPlan', + } + resource = f'/networks/{networkId}/floorPlans/{floorPlanId}' + + body_params = ['name', 'center', 'bottomLeftCorner', 'bottomRightCorner', 'topLeftCorner', 'topRightCorner', 'imageContents'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkFloorPlan(self, networkId: str, floorPlanId: str): + """ + **Destroy a floor plan** + https://api.meraki.com/api_docs#destroy-a-floor-plan + + - networkId (string) + - floorPlanId (string) + """ + + metadata = { + 'tags': ['Floorplans'], + 'operation': 'deleteNetworkFloorPlan', + } + resource = f'/networks/{networkId}/floorPlans/{floorPlanId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/group_policies.py b/meraki/aio/api/group_policies.py new file mode 100644 index 00000000..57507ef0 --- /dev/null +++ b/meraki/aio/api/group_policies.py @@ -0,0 +1,128 @@ +class AsyncGroupPolicies: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkGroupPolicies(self, networkId: str): + """ + **List the group policies in a network** + https://api.meraki.com/api_docs#list-the-group-policies-in-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Group policies'], + 'operation': 'getNetworkGroupPolicies', + } + resource = f'/networks/{networkId}/groupPolicies' + + return await self._session.get(metadata, resource) + + async def createNetworkGroupPolicy(self, networkId: str, name: str, **kwargs): + """ + **Create a group policy** + https://api.meraki.com/api_docs#create-a-group-policy + + - networkId (string) + - name (string): The name for your group policy. Required. + - scheduling (object): The schedule for the group policy. Schedules are applied to days of the week. + + - bandwidth (object): The bandwidth settings for clients bound to your group policy. + + - firewallAndTrafficShaping (object): The firewall and traffic shaping rules and settings for your policy. + + - contentFiltering (object): The content filtering settings for your group policy + - splashAuthSettings (string): Whether clients bound to your policy will bypass splash authorization or behave according to the network's rules. Can be one of 'network default' or 'bypass'. Only available if your network has a wireless configuration. + - vlanTagging (object): The VLAN tagging settings for your group policy. Only available if your network has a wireless configuration. + - bonjourForwarding (object): The Bonjour settings for your group policy. Only valid if your network has a wireless configuration. + """ + + kwargs.update(locals()) + + if 'splashAuthSettings' in kwargs: + options = ['network default', 'bypass'] + assert kwargs['splashAuthSettings'] in options, f'''"splashAuthSettings" cannot be "{kwargs['splashAuthSettings']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Group policies'], + 'operation': 'createNetworkGroupPolicy', + } + resource = f'/networks/{networkId}/groupPolicies' + + body_params = ['name', 'scheduling', 'bandwidth', 'firewallAndTrafficShaping', 'contentFiltering', 'splashAuthSettings', 'vlanTagging', 'bonjourForwarding'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkGroupPolicy(self, networkId: str, groupPolicyId: str): + """ + **Display a group policy** + https://api.meraki.com/api_docs#display-a-group-policy + + - networkId (string) + - groupPolicyId (string) + """ + + metadata = { + 'tags': ['Group policies'], + 'operation': 'getNetworkGroupPolicy', + } + resource = f'/networks/{networkId}/groupPolicies/{groupPolicyId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkGroupPolicy(self, networkId: str, groupPolicyId: str, **kwargs): + """ + **Update a group policy** + https://api.meraki.com/api_docs#update-a-group-policy + + - networkId (string) + - groupPolicyId (string) + - name (string): The name for your group policy. + - scheduling (object): The schedule for the group policy. Schedules are applied to days of the week. + + - bandwidth (object): The bandwidth settings for clients bound to your group policy. + + - firewallAndTrafficShaping (object): The firewall and traffic shaping rules and settings for your policy. + + - contentFiltering (object): The content filtering settings for your group policy + - splashAuthSettings (string): Whether clients bound to your policy will bypass splash authorization or behave according to the network's rules. Can be one of 'network default' or 'bypass'. Only available if your network has a wireless configuration. + - vlanTagging (object): The VLAN tagging settings for your group policy. Only available if your network has a wireless configuration. + - bonjourForwarding (object): The Bonjour settings for your group policy. Only valid if your network has a wireless configuration. + """ + + kwargs.update(locals()) + + if 'splashAuthSettings' in kwargs: + options = ['network default', 'bypass'] + assert kwargs['splashAuthSettings'] in options, f'''"splashAuthSettings" cannot be "{kwargs['splashAuthSettings']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Group policies'], + 'operation': 'updateNetworkGroupPolicy', + } + resource = f'/networks/{networkId}/groupPolicies/{groupPolicyId}' + + body_params = ['name', 'scheduling', 'bandwidth', 'firewallAndTrafficShaping', 'contentFiltering', 'splashAuthSettings', 'vlanTagging', 'bonjourForwarding'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkGroupPolicy(self, networkId: str, groupPolicyId: str): + """ + **Delete a group policy** + https://api.meraki.com/api_docs#delete-a-group-policy + + - networkId (string) + - groupPolicyId (string) + """ + + metadata = { + 'tags': ['Group policies'], + 'operation': 'deleteNetworkGroupPolicy', + } + resource = f'/networks/{networkId}/groupPolicies/{groupPolicyId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/http_servers.py b/meraki/aio/api/http_servers.py new file mode 100644 index 00000000..39fafba4 --- /dev/null +++ b/meraki/aio/api/http_servers.py @@ -0,0 +1,143 @@ +class AsyncHTTPServers: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkHttpServers(self, networkId: str): + """ + **List the HTTP servers for a network** + https://api.meraki.com/api_docs#list-the-http-servers-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'getNetworkHttpServers', + } + resource = f'/networks/{networkId}/httpServers' + + return await self._session.get(metadata, resource) + + async def createNetworkHttpServer(self, networkId: str, name: str, url: str, **kwargs): + """ + **Add an HTTP server to a network** + https://api.meraki.com/api_docs#add-an-http-server-to-a-network + + - networkId (string) + - name (string): A name for easy reference to the HTTP server + - url (string): The URL of the HTTP server + - sharedSecret (string): A shared secret that will be included in POSTs sent to the HTTP server. This secret can be used to verify that the request was sent by Meraki. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'createNetworkHttpServer', + } + resource = f'/networks/{networkId}/httpServers' + + body_params = ['name', 'url', 'sharedSecret'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def createNetworkHttpServersWebhookTest(self, networkId: str, url: str): + """ + **Send a test webhook for a network** + https://api.meraki.com/api_docs#send-a-test-webhook-for-a-network + + - networkId (string) + - url (string): The URL where the test webhook will be sent + """ + + kwargs = locals() + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'createNetworkHttpServersWebhookTest', + } + resource = f'/networks/{networkId}/httpServers/webhookTests' + + body_params = ['url'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkHttpServersWebhookTest(self, networkId: str, id: str): + """ + **Return the status of a webhook test for a network** + https://api.meraki.com/api_docs#return-the-status-of-a-webhook-test-for-a-network + + - networkId (string) + - id (string) + """ + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'getNetworkHttpServersWebhookTest', + } + resource = f'/networks/{networkId}/httpServers/webhookTests/{id}' + + return await self._session.get(metadata, resource) + + async def getNetworkHttpServer(self, networkId: str, id: str): + """ + **Return an HTTP server for a network** + https://api.meraki.com/api_docs#return-an-http-server-for-a-network + + - networkId (string) + - id (string) + """ + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'getNetworkHttpServer', + } + resource = f'/networks/{networkId}/httpServers/{id}' + + return await self._session.get(metadata, resource) + + async def updateNetworkHttpServer(self, networkId: str, id: str, **kwargs): + """ + **Update an HTTP server** + https://api.meraki.com/api_docs#update-an-http-server + + - networkId (string) + - id (string) + - name (string): A name for easy reference to the HTTP server + - url (string): The URL of the HTTP server + - sharedSecret (string): A shared secret that will be included in POSTs sent to the HTTP server. This secret can be used to verify that the request was sent by Meraki. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'updateNetworkHttpServer', + } + resource = f'/networks/{networkId}/httpServers/{id}' + + body_params = ['name', 'url', 'sharedSecret'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkHttpServer(self, networkId: str, id: str): + """ + **Delete an HTTP server from a network** + https://api.meraki.com/api_docs#delete-an-http-server-from-a-network + + - networkId (string) + - id (string) + """ + + metadata = { + 'tags': ['HTTP servers'], + 'operation': 'deleteNetworkHttpServer', + } + resource = f'/networks/{networkId}/httpServers/{id}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/intrusion_settings.py b/meraki/aio/api/intrusion_settings.py new file mode 100644 index 00000000..8e934ada --- /dev/null +++ b/meraki/aio/api/intrusion_settings.py @@ -0,0 +1,90 @@ +class AsyncIntrusionSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSecurityIntrusionSettings(self, networkId: str): + """ + **Returns all supported intrusion settings for an MX network** + https://api.meraki.com/api_docs#returns-all-supported-intrusion-settings-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Intrusion settings'], + 'operation': 'getNetworkSecurityIntrusionSettings', + } + resource = f'/networks/{networkId}/security/intrusionSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkSecurityIntrusionSettings(self, networkId: str, **kwargs): + """ + **Set the supported intrusion settings for an MX network** + https://api.meraki.com/api_docs#set-the-supported-intrusion-settings-for-an-mx-network + + - networkId (string) + - mode (string): Set mode to 'disabled'/'detection'/'prevention' (optional - omitting will leave current config unchanged) + - idsRulesets (string): Set the detection ruleset 'connectivity'/'balanced'/'security' (optional - omitting will leave current config unchanged). Default value is 'balanced' if none currently saved + - protectedNetworks (object): Set the included/excluded networks from the intrusion engine (optional - omitting will leave current config unchanged). This is available only in 'passthrough' mode + """ + + kwargs.update(locals()) + + if 'mode' in kwargs: + options = ['prevention', 'detection', 'disabled'] + assert kwargs['mode'] in options, f'''"mode" cannot be "{kwargs['mode']}", & must be set to one of: {options}''' + if 'idsRulesets' in kwargs: + options = ['connectivity', 'balanced', 'security'] + assert kwargs['idsRulesets'] in options, f'''"idsRulesets" cannot be "{kwargs['idsRulesets']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Intrusion settings'], + 'operation': 'updateNetworkSecurityIntrusionSettings', + } + resource = f'/networks/{networkId}/security/intrusionSettings' + + body_params = ['mode', 'idsRulesets', 'protectedNetworks'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getOrganizationSecurityIntrusionSettings(self, organizationId: str): + """ + **Returns all supported intrusion settings for an organization** + https://api.meraki.com/api_docs#returns-all-supported-intrusion-settings-for-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Intrusion settings'], + 'operation': 'getOrganizationSecurityIntrusionSettings', + } + resource = f'/organizations/{organizationId}/security/intrusionSettings' + + return await self._session.get(metadata, resource) + + async def updateOrganizationSecurityIntrusionSettings(self, organizationId: str, whitelistedRules: list): + """ + **Sets supported intrusion settings for an organization** + https://api.meraki.com/api_docs#sets-supported-intrusion-settings-for-an-organization + + - organizationId (string) + - whitelistedRules (array): Sets a list of specific SNORT® signatures to whitelist + """ + + kwargs = locals() + + metadata = { + 'tags': ['Intrusion settings'], + 'operation': 'updateOrganizationSecurityIntrusionSettings', + } + resource = f'/organizations/{organizationId}/security/intrusionSettings' + + body_params = ['whitelistedRules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/licenses.py b/meraki/aio/api/licenses.py new file mode 100644 index 00000000..f0101ae0 --- /dev/null +++ b/meraki/aio/api/licenses.py @@ -0,0 +1,173 @@ +class AsyncLicenses: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationLicenses(self, organizationId: str, total_pages=1, direction='next', **kwargs): + """ + **List the licenses for an organization** + https://api.meraki.com/api_docs#list-the-licenses-for-an-organization + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - deviceSerial (string): Filter the licenses to those assigned to a particular device + - networkId (string): Filter the licenses to those assigned in a particular network + - state (string): Filter the licenses to those in a particular state. Can be one of 'active', 'expired', 'expiring', 'unused', 'unusedActive' or 'recentlyQueued' + """ + + kwargs.update(locals()) + + if 'state' in kwargs: + options = ['active', 'expired', 'expiring', 'unused', 'unusedActive', 'recentlyQueued'] + assert kwargs['state'] in options, f'''"state" cannot be "{kwargs['state']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Licenses'], + 'operation': 'getOrganizationLicenses', + } + resource = f'/organizations/{organizationId}/licenses' + + query_params = ['perPage', 'startingAfter', 'endingBefore', 'deviceSerial', 'networkId', 'state'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def assignOrganizationLicensesSeats(self, organizationId: str, licenseId: str, networkId: str, seatCount: int): + """ + **Assign SM seats to a network. This will increase the managed SM device limit of the network** + https://api.meraki.com/api_docs#assign-sm-seats-to-a-network + + - organizationId (string) + - licenseId (string): The ID of the SM license to assign seats from + - networkId (string): The ID of the SM network to assign the seats to + - seatCount (integer): The number of seats to assign to the SM network. Must be less than or equal to the total number of seats of the license + """ + + kwargs = locals() + + metadata = { + 'tags': ['Licenses'], + 'operation': 'assignOrganizationLicensesSeats', + } + resource = f'/organizations/{organizationId}/licenses/assignSeats' + + body_params = ['licenseId', 'networkId', 'seatCount'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def moveOrganizationLicenses(self, organizationId: str, destOrganizationId: str, licenseIds: list): + """ + **Move licenses to another organization. This will also move any devices that the licenses are assigned to** + https://api.meraki.com/api_docs#move-licenses-to-another-organization + + - organizationId (string) + - destOrganizationId (string): The ID of the organization to move the licenses to + - licenseIds (array): A list of IDs of licenses to move to the new organization + """ + + kwargs = locals() + + metadata = { + 'tags': ['Licenses'], + 'operation': 'moveOrganizationLicenses', + } + resource = f'/organizations/{organizationId}/licenses/move' + + body_params = ['destOrganizationId', 'licenseIds'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def moveOrganizationLicensesSeats(self, organizationId: str, destOrganizationId: str, licenseId: str, seatCount: int): + """ + **Move SM seats to another organization** + https://api.meraki.com/api_docs#move-sm-seats-to-another-organization + + - organizationId (string) + - destOrganizationId (string): The ID of the organization to move the SM seats to + - licenseId (string): The ID of the SM license to move the seats from + - seatCount (integer): The number of seats to move to the new organization. Must be less than or equal to the total number of seats of the license + """ + + kwargs = locals() + + metadata = { + 'tags': ['Licenses'], + 'operation': 'moveOrganizationLicensesSeats', + } + resource = f'/organizations/{organizationId}/licenses/moveSeats' + + body_params = ['destOrganizationId', 'licenseId', 'seatCount'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def renewOrganizationLicensesSeats(self, organizationId: str, licenseIdToRenew: str, unusedLicenseId: str): + """ + **Renew SM seats of a license. This will extend the license expiration date of managed SM devices covered by this license** + https://api.meraki.com/api_docs#renew-sm-seats-of-a-license + + - organizationId (string) + - licenseIdToRenew (string): The ID of the SM license to renew. This license must already be assigned to an SM network + - unusedLicenseId (string): The SM license to use to renew the seats on 'licenseIdToRenew'. This license must have at least as many seats available as there are seats on 'licenseIdToRenew' + """ + + kwargs = locals() + + metadata = { + 'tags': ['Licenses'], + 'operation': 'renewOrganizationLicensesSeats', + } + resource = f'/organizations/{organizationId}/licenses/renewSeats' + + body_params = ['licenseIdToRenew', 'unusedLicenseId'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganizationLicense(self, organizationId: str, licenseId: str): + """ + **Display a license** + https://api.meraki.com/api_docs#display-a-license + + - organizationId (string) + - licenseId (string) + """ + + metadata = { + 'tags': ['Licenses'], + 'operation': 'getOrganizationLicense', + } + resource = f'/organizations/{organizationId}/licenses/{licenseId}' + + return await self._session.get(metadata, resource) + + async def updateOrganizationLicense(self, organizationId: str, licenseId: str, **kwargs): + """ + **Update a license** + https://api.meraki.com/api_docs#update-a-license + + - organizationId (string) + - licenseId (string) + - deviceSerial (string): The serial number of the device to assign this license to. Set this to null to unassign the license. If a different license is already active on the device, this parameter will control queueing/dequeuing this license. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Licenses'], + 'operation': 'updateOrganizationLicense', + } + resource = f'/organizations/{organizationId}/licenses/{licenseId}' + + body_params = ['deviceSerial'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/link_aggregations.py b/meraki/aio/api/link_aggregations.py new file mode 100644 index 00000000..78e9ec83 --- /dev/null +++ b/meraki/aio/api/link_aggregations.py @@ -0,0 +1,85 @@ +class AsyncLinkAggregations: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSwitchLinkAggregations(self, networkId: str): + """ + **List link aggregation groups** + https://api.meraki.com/api_docs#list-link-aggregation-groups + + - networkId (string) + """ + + metadata = { + 'tags': ['Link aggregations'], + 'operation': 'getNetworkSwitchLinkAggregations', + } + resource = f'/networks/{networkId}/switch/linkAggregations' + + return await self._session.get(metadata, resource) + + async def createNetworkSwitchLinkAggregation(self, networkId: str, **kwargs): + """ + **Create a link aggregation group** + https://api.meraki.com/api_docs#create-a-link-aggregation-group + + - networkId (string) + - 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. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Link aggregations'], + 'operation': 'createNetworkSwitchLinkAggregation', + } + resource = f'/networks/{networkId}/switch/linkAggregations' + + body_params = ['switchPorts', 'switchProfilePorts'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def updateNetworkSwitchLinkAggregation(self, networkId: str, linkAggregationId: str, **kwargs): + """ + **Update a link aggregation group** + https://api.meraki.com/api_docs#update-a-link-aggregation-group + + - networkId (string) + - linkAggregationId (string) + - switchPorts (array): Array of switch or stack ports for updating aggregation group. Minimum 2 and maximum 8 ports are supported. + - switchProfilePorts (array): Array of switch profile ports for updating aggregation group. Minimum 2 and maximum 8 ports are supported. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Link aggregations'], + 'operation': 'updateNetworkSwitchLinkAggregation', + } + resource = f'/networks/{networkId}/switch/linkAggregations/{linkAggregationId}' + + body_params = ['switchPorts', 'switchProfilePorts'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkSwitchLinkAggregation(self, networkId: str, linkAggregationId: str): + """ + **Split a link aggregation group into separate ports** + https://api.meraki.com/api_docs#split-a-link-aggregation-group-into-separate-ports + + - networkId (string) + - linkAggregationId (string) + """ + + metadata = { + 'tags': ['Link aggregations'], + 'operation': 'deleteNetworkSwitchLinkAggregation', + } + resource = f'/networks/{networkId}/switch/linkAggregations/{linkAggregationId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/malware_settings.py b/meraki/aio/api/malware_settings.py new file mode 100644 index 00000000..4cb09b5a --- /dev/null +++ b/meraki/aio/api/malware_settings.py @@ -0,0 +1,49 @@ +class AsyncMalwareSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSecurityMalwareSettings(self, networkId: str): + """ + **Returns all supported malware settings for an MX network** + https://api.meraki.com/api_docs#returns-all-supported-malware-settings-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Malware settings'], + 'operation': 'getNetworkSecurityMalwareSettings', + } + resource = f'/networks/{networkId}/security/malwareSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkSecurityMalwareSettings(self, networkId: str, mode: str, **kwargs): + """ + **Set the supported malware settings for an MX network** + https://api.meraki.com/api_docs#set-the-supported-malware-settings-for-an-mx-network + + - networkId (string) + - mode (string): Set mode to 'enabled' to enable malware prevention, otherwise 'disabled' + - allowedUrls (array): The urls that should be permitted by the malware detection engine. If omitted, the current config will remain unchanged. This is available only if your network supports AMP whitelisting + - allowedFiles (array): The sha256 digests of files that should be permitted by the malware detection engine. If omitted, the current config will remain unchanged. This is available only if your network supports AMP whitelisting + """ + + kwargs.update(locals()) + + if 'mode' in kwargs: + options = ['enabled', 'disabled'] + assert kwargs['mode'] in options, f'''"mode" cannot be "{kwargs['mode']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Malware settings'], + 'operation': 'updateNetworkSecurityMalwareSettings', + } + resource = f'/networks/{networkId}/security/malwareSettings' + + body_params = ['mode', 'allowedUrls', 'allowedFiles'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/management_interface_settings.py b/meraki/aio/api/management_interface_settings.py new file mode 100644 index 00000000..c6deb4d2 --- /dev/null +++ b/meraki/aio/api/management_interface_settings.py @@ -0,0 +1,46 @@ +class AsyncManagementInterfaceSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkDeviceManagementInterfaceSettings(self, networkId: str, serial: str): + """ + **Return the management interface settings for a device** + https://api.meraki.com/api_docs#return-the-management-interface-settings-for-a-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Management interface settings'], + 'operation': 'getNetworkDeviceManagementInterfaceSettings', + } + resource = f'/networks/{networkId}/devices/{serial}/managementInterfaceSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkDeviceManagementInterfaceSettings(self, networkId: str, serial: str, **kwargs): + """ + **Update the management interface settings for a device** + https://api.meraki.com/api_docs#update-the-management-interface-settings-for-a-device + + - networkId (string) + - serial (string) + - wan1 (object): WAN 1 settings + - wan2 (object): WAN 2 settings (only for MX devices) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Management interface settings'], + 'operation': 'updateNetworkDeviceManagementInterfaceSettings', + } + resource = f'/networks/{networkId}/devices/{serial}/managementInterfaceSettings' + + body_params = ['wan1', 'wan2'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/meraki_auth_users.py b/meraki/aio/api/meraki_auth_users.py new file mode 100644 index 00000000..8f3d8421 --- /dev/null +++ b/meraki/aio/api/meraki_auth_users.py @@ -0,0 +1,38 @@ +class AsyncMerakiAuthUsers: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkMerakiAuthUsers(self, networkId: str): + """ + **List the splash or RADIUS users configured under Meraki Authentication for a network** + https://api.meraki.com/api_docs#list-the-splash-or-radius-users-configured-under-meraki-authentication-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Meraki auth users'], + 'operation': 'getNetworkMerakiAuthUsers', + } + resource = f'/networks/{networkId}/merakiAuthUsers' + + return await self._session.get(metadata, resource) + + async def getNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str): + """ + **Return the Meraki Auth splash or RADIUS user** + https://api.meraki.com/api_docs#return-the-meraki-auth-splash-or-radius-user + + - networkId (string) + - merakiAuthUserId (string) + """ + + metadata = { + 'tags': ['Meraki auth users'], + 'operation': 'getNetworkMerakiAuthUser', + } + resource = f'/networks/{networkId}/merakiAuthUsers/{merakiAuthUserId}' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/mg_connectivity_monitoring_destinations.py b/meraki/aio/api/mg_connectivity_monitoring_destinations.py new file mode 100644 index 00000000..1530b20f --- /dev/null +++ b/meraki/aio/api/mg_connectivity_monitoring_destinations.py @@ -0,0 +1,43 @@ +class AsyncMGConnectivityMonitoringDestinations: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkCellularGatewaySettingsConnectivityMonitoringDestinations(self, networkId: str): + """ + **Return the connectivity testing destinations for an MG network** + https://api.meraki.com/api_docs#return-the-connectivity-testing-destinations-for-an-mg-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MG connectivity monitoring destinations'], + 'operation': 'getNetworkCellularGatewaySettingsConnectivityMonitoringDestinations', + } + resource = f'/networks/{networkId}/cellularGateway/settings/connectivityMonitoringDestinations' + + return await self._session.get(metadata, resource) + + async def updateNetworkCellularGatewaySettingsConnectivityMonitoringDestinations(self, networkId: str, **kwargs): + """ + **Update the connectivity testing destinations for an MG network** + https://api.meraki.com/api_docs#update-the-connectivity-testing-destinations-for-an-mg-network + + - networkId (string) + - destinations (array): The list of connectivity monitoring destinations + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MG connectivity monitoring destinations'], + 'operation': 'updateNetworkCellularGatewaySettingsConnectivityMonitoringDestinations', + } + resource = f'/networks/{networkId}/cellularGateway/settings/connectivityMonitoringDestinations' + + body_params = ['destinations'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mg_dhcp_settings.py b/meraki/aio/api/mg_dhcp_settings.py new file mode 100644 index 00000000..23d41e2c --- /dev/null +++ b/meraki/aio/api/mg_dhcp_settings.py @@ -0,0 +1,45 @@ +class AsyncMGDHCPSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkCellularGatewaySettingsDhcp(self, networkId: str): + """ + **List common DHCP settings of MGs** + https://api.meraki.com/api_docs#list-common-dhcp-settings-of-mgs + + - networkId (string) + """ + + metadata = { + 'tags': ['MG DHCP settings'], + 'operation': 'getNetworkCellularGatewaySettingsDhcp', + } + resource = f'/networks/{networkId}/cellularGateway/settings/dhcp' + + return await self._session.get(metadata, resource) + + async def updateNetworkCellularGatewaySettingsDhcp(self, networkId: str, **kwargs): + """ + **Update common DHCP settings of MGs** + https://api.meraki.com/api_docs#update-common-dhcp-settings-of-mgs + + - networkId (string) + - dhcpLeaseTime (string): DHCP Lease time for all MG of the network. It can be '30 minutes', '1 hour', '4 hours', '12 hours', '1 day' or '1 week'. + - dnsNameservers (string): DNS name servers mode for all MG of the network. It can take 4 different values: 'upstream_dns', 'google_dns', 'opendns', 'custom'. + - dnsCustomNameservers (array): list of fixed IP representing the the DNS Name servers when the mode is 'custom' + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MG DHCP settings'], + 'operation': 'updateNetworkCellularGatewaySettingsDhcp', + } + resource = f'/networks/{networkId}/cellularGateway/settings/dhcp' + + body_params = ['dhcpLeaseTime', 'dnsNameservers', 'dnsCustomNameservers'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mg_lan_settings.py b/meraki/aio/api/mg_lan_settings.py new file mode 100644 index 00000000..e71f434d --- /dev/null +++ b/meraki/aio/api/mg_lan_settings.py @@ -0,0 +1,44 @@ +class AsyncMGLANSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceCellularGatewaySettings(self, serial: str): + """ + **Show the LAN Settings of a MG** + https://api.meraki.com/api_docs#show-the-lan-settings-of-a-mg + + - serial (string) + """ + + metadata = { + 'tags': ['MG LAN settings'], + 'operation': 'getDeviceCellularGatewaySettings', + } + resource = f'/devices/{serial}/cellularGateway/settings' + + return await self._session.get(metadata, resource) + + async def updateDeviceCellularGatewaySettings(self, serial: str, **kwargs): + """ + **Update the LAN Settings for a single MG.** + https://api.meraki.com/api_docs#update-the-lan-settings-for-a-single-mg + + - serial (string) + - reservedIpRanges (array): list of all reserved IP ranges for a single MG + - fixedIpAssignments (array): list of all fixed IP assignments for a single MG + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MG LAN settings'], + 'operation': 'updateDeviceCellularGatewaySettings', + } + resource = f'/devices/{serial}/cellularGateway/settings' + + body_params = ['reservedIpRanges', 'fixedIpAssignments'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mg_port_forwarding_rules.py b/meraki/aio/api/mg_port_forwarding_rules.py new file mode 100644 index 00000000..b0f7e9a7 --- /dev/null +++ b/meraki/aio/api/mg_port_forwarding_rules.py @@ -0,0 +1,43 @@ +class AsyncMGPortForwardingRules: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceCellularGatewaySettingsPortForwardingRules(self, serial: str): + """ + **Returns the port forwarding rules for a single MG.** + https://api.meraki.com/api_docs#returns-the-port-forwarding-rules-for-a-single-mg + + - serial (string) + """ + + metadata = { + 'tags': ['MG port forwarding rules'], + 'operation': 'getDeviceCellularGatewaySettingsPortForwardingRules', + } + resource = f'/devices/{serial}/cellularGateway/settings/portForwardingRules' + + return await self._session.get(metadata, resource) + + async def updateDeviceCellularGatewaySettingsPortForwardingRules(self, serial: str, **kwargs): + """ + **Updates the port forwarding rules for a single MG.** + https://api.meraki.com/api_docs#updates-the-port-forwarding-rules-for-a-single-mg + + - serial (string) + - rules (array): An array of port forwarding params + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MG port forwarding rules'], + 'operation': 'updateDeviceCellularGatewaySettingsPortForwardingRules', + } + resource = f'/devices/{serial}/cellularGateway/settings/portForwardingRules' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mg_subnet_pool_settings.py b/meraki/aio/api/mg_subnet_pool_settings.py new file mode 100644 index 00000000..9f442d4d --- /dev/null +++ b/meraki/aio/api/mg_subnet_pool_settings.py @@ -0,0 +1,44 @@ +class AsyncMGSubnetPoolSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkCellularGatewaySettingsSubnetPool(self, networkId: str): + """ + **Return the subnet pool and mask configured for MGs in the network.** + https://api.meraki.com/api_docs#return-the-subnet-pool-and-mask-configured-for-mgs-in-the-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MG subnet pool settings'], + 'operation': 'getNetworkCellularGatewaySettingsSubnetPool', + } + resource = f'/networks/{networkId}/cellularGateway/settings/subnetPool' + + return await self._session.get(metadata, resource) + + async def updateNetworkCellularGatewaySettingsSubnetPool(self, networkId: str, **kwargs): + """ + **Update the subnet pool and mask configuration for MGs in the network.** + https://api.meraki.com/api_docs#update-the-subnet-pool-and-mask-configuration-for-mgs-in-the-network + + - networkId (string) + - mask (integer): Mask used for the subnet of all MGs in this network. + - cidr (string): CIDR of the pool of subnets. Each MG in this network will automatically pick a subnet from this pool. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MG subnet pool settings'], + 'operation': 'updateNetworkCellularGatewaySettingsSubnetPool', + } + resource = f'/networks/{networkId}/cellularGateway/settings/subnetPool' + + body_params = ['mask', 'cidr'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mg_uplink_settings.py b/meraki/aio/api/mg_uplink_settings.py new file mode 100644 index 00000000..313b63a0 --- /dev/null +++ b/meraki/aio/api/mg_uplink_settings.py @@ -0,0 +1,43 @@ +class AsyncMGUplinkSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkCellularGatewaySettingsUplink(self, networkId: str): + """ + **Returns the uplink settings for your MG network.** + https://api.meraki.com/api_docs#returns-the-uplink-settings-for-your-mg-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MG uplink settings'], + 'operation': 'getNetworkCellularGatewaySettingsUplink', + } + resource = f'/networks/{networkId}/cellularGateway/settings/uplink' + + return await self._session.get(metadata, resource) + + async def updateNetworkCellularGatewaySettingsUplink(self, networkId: str, **kwargs): + """ + **Updates the uplink settings for your MG network.** + https://api.meraki.com/api_docs#updates-the-uplink-settings-for-your-mg-network + + - networkId (string) + - bandwidthLimits (object): The bandwidth settings for the 'cellular' uplink + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MG uplink settings'], + 'operation': 'updateNetworkCellularGatewaySettingsUplink', + } + resource = f'/networks/{networkId}/cellularGateway/settings/uplink' + + body_params = ['bandwidthLimits'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/monitored_media_servers.py b/meraki/aio/api/monitored_media_servers.py new file mode 100644 index 00000000..f0f8b334 --- /dev/null +++ b/meraki/aio/api/monitored_media_servers.py @@ -0,0 +1,102 @@ +class AsyncMonitoredMediaServers: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationInsightMonitoredMediaServers(self, organizationId: str): + """ + **List the monitored media servers for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#list-the-monitored-media-servers-for-this-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'getOrganizationInsightMonitoredMediaServers', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers' + + return await self._session.get(metadata, resource) + + async def createOrganizationInsightMonitoredMediaServer(self, organizationId: str, name: str, address: str): + """ + **Add a media server to be monitored for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#add-a-media-server-to-be-monitored-for-this-organization + + - organizationId (string) + - name (string): The name of the VoIP provider + - address (string): The IP address (IPv4 only) or hostname of the media server to monitor + """ + + kwargs = locals() + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'createOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers' + + body_params = ['name', 'address'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganizationInsightMonitoredMediaServer(self, organizationId: str, monitoredMediaServerId: str): + """ + **Return a monitored media server for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#return-a-monitored-media-server-for-this-organization + + - organizationId (string) + - monitoredMediaServerId (string) + """ + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'getOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}' + + return await self._session.get(metadata, resource) + + async def updateOrganizationInsightMonitoredMediaServer(self, organizationId: str, monitoredMediaServerId: str, **kwargs): + """ + **Update a monitored media server for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#update-a-monitored-media-server-for-this-organization + + - organizationId (string) + - monitoredMediaServerId (string) + - name (string): The name of the VoIP provider + - address (string): The IP address (IPv4 only) or hostname of the media server to monitor + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'updateOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}' + + body_params = ['name', 'address'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteOrganizationInsightMonitoredMediaServer(self, organizationId: str, monitoredMediaServerId: str): + """ + **Delete a monitored media server from this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#delete-a-monitored-media-server-from-this-organization + + - organizationId (string) + - monitoredMediaServerId (string) + """ + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'deleteOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/mr_l3_firewall.py b/meraki/aio/api/mr_l3_firewall.py new file mode 100644 index 00000000..496ba6f5 --- /dev/null +++ b/meraki/aio/api/mr_l3_firewall.py @@ -0,0 +1,46 @@ +class AsyncMRL3Firewall: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSsidL3FirewallRules(self, networkId: str, number: str): + """ + **Return the L3 firewall rules for an SSID on an MR network** + https://api.meraki.com/api_docs#return-the-l3-firewall-rules-for-an-ssid-on-an-mr-network + + - networkId (string) + - number (string) + """ + + metadata = { + 'tags': ['MR L3 firewall'], + 'operation': 'getNetworkSsidL3FirewallRules', + } + resource = f'/networks/{networkId}/ssids/{number}/l3FirewallRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkSsidL3FirewallRules(self, networkId: str, number: str, **kwargs): + """ + **Update the L3 firewall rules of an SSID on an MR network** + https://api.meraki.com/api_docs#update-the-l3-firewall-rules-of-an-ssid-on-an-mr-network + + - networkId (string) + - number (string) + - rules (array): An ordered array of the firewall rules for this SSID (not including the local LAN access rule or the default rule) + - allowLanAccess (boolean): Allow wireless client access to local LAN (boolean value - true allows access and false denies access) (optional) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MR L3 firewall'], + 'operation': 'updateNetworkSsidL3FirewallRules', + } + resource = f'/networks/{networkId}/ssids/{number}/l3FirewallRules' + + body_params = ['rules', 'allowLanAccess'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mv_sense.py b/meraki/aio/api/mv_sense.py new file mode 100644 index 00000000..11f510c3 --- /dev/null +++ b/meraki/aio/api/mv_sense.py @@ -0,0 +1,123 @@ +class AsyncMVSense: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceCameraAnalyticsLive(self, serial: str): + """ + **Returns live state from camera of analytics zones** + https://api.meraki.com/api_docs#returns-live-state-from-camera-of-analytics-zones + + - serial (string) + """ + + metadata = { + 'tags': ['MV Sense'], + 'operation': 'getDeviceCameraAnalyticsLive', + } + resource = f'/devices/{serial}/camera/analytics/live' + + return await self._session.get(metadata, resource) + + async def getDeviceCameraAnalyticsOverview(self, serial: str, **kwargs): + """ + **Returns an overview of aggregate analytics data for a timespan** + https://api.meraki.com/api_docs#returns-an-overview-of-aggregate-analytics-data-for-a-timespan + + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. The default is 1 hour. + - objectType (string): [optional] The object type for which analytics will be retrieved. The default object type is person. The available types are [person, vehicle]. + """ + + kwargs.update(locals()) + + if 'objectType' in kwargs: + options = ['person', 'vehicle'] + assert kwargs['objectType'] in options, f'''"objectType" cannot be "{kwargs['objectType']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['MV Sense'], + 'operation': 'getDeviceCameraAnalyticsOverview', + } + resource = f'/devices/{serial}/camera/analytics/overview' + + query_params = ['t0', 't1', 'timespan', 'objectType'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getDeviceCameraAnalyticsRecent(self, serial: str, **kwargs): + """ + **Returns most recent record for analytics zones** + https://api.meraki.com/api_docs#returns-most-recent-record-for-analytics-zones + + - serial (string) + - objectType (string): [optional] The object type for which analytics will be retrieved. The default object type is person. The available types are [person, vehicle]. + """ + + kwargs.update(locals()) + + if 'objectType' in kwargs: + options = ['person', 'vehicle'] + assert kwargs['objectType'] in options, f'''"objectType" cannot be "{kwargs['objectType']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['MV Sense'], + 'operation': 'getDeviceCameraAnalyticsRecent', + } + resource = f'/devices/{serial}/camera/analytics/recent' + + query_params = ['objectType'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getDeviceCameraAnalyticsZones(self, serial: str): + """ + **Returns all configured analytic zones for this camera** + https://api.meraki.com/api_docs#returns-all-configured-analytic-zones-for-this-camera + + - serial (string) + """ + + metadata = { + 'tags': ['MV Sense'], + 'operation': 'getDeviceCameraAnalyticsZones', + } + resource = f'/devices/{serial}/camera/analytics/zones' + + return await self._session.get(metadata, resource) + + async def getDeviceCameraAnalyticsZoneHistory(self, serial: str, zoneId: str, **kwargs): + """ + **Return historical records for analytic zones** + https://api.meraki.com/api_docs#return-historical-records-for-analytic-zones + + - serial (string) + - zoneId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 14 hours after t0. + - timespan (number): The timespan for 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 hours. The default is 1 hour. + - resolution (integer): The time resolution in seconds for returned data. The valid resolutions are: 60. The default is 60. + - objectType (string): [optional] The object type for which analytics will be retrieved. The default object type is person. The available types are [person, vehicle]. + """ + + kwargs.update(locals()) + + if 'objectType' in kwargs: + options = ['person', 'vehicle'] + assert kwargs['objectType'] in options, f'''"objectType" cannot be "{kwargs['objectType']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['MV Sense'], + 'operation': 'getDeviceCameraAnalyticsZoneHistory', + } + resource = f'/devices/{serial}/camera/analytics/zones/{zoneId}/history' + + query_params = ['t0', 't1', 'timespan', 'resolution', 'objectType'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/mx_1_1_nat_rules.py b/meraki/aio/api/mx_1_1_nat_rules.py new file mode 100644 index 00000000..4d072693 --- /dev/null +++ b/meraki/aio/api/mx_1_1_nat_rules.py @@ -0,0 +1,43 @@ +class AsyncMX11NATRules: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkOneToOneNatRules(self, networkId: str): + """ + **Return the 1:1 NAT mapping rules for an MX network** + https://api.meraki.com/api_docs#return-the-11-nat-mapping-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX 1:1 NAT rules'], + 'operation': 'getNetworkOneToOneNatRules', + } + resource = f'/networks/{networkId}/oneToOneNatRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkOneToOneNatRules(self, networkId: str, rules: list): + """ + **Set the 1:1 NAT mapping rules for an MX network** + https://api.meraki.com/api_docs#set-the-11-nat-mapping-rules-for-an-mx-network + + - networkId (string) + - rules (array): An array of 1:1 nat rules + """ + + kwargs = locals() + + metadata = { + 'tags': ['MX 1:1 NAT rules'], + 'operation': 'updateNetworkOneToOneNatRules', + } + resource = f'/networks/{networkId}/oneToOneNatRules' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_1_many_nat_rules.py b/meraki/aio/api/mx_1_many_nat_rules.py new file mode 100644 index 00000000..549bcf06 --- /dev/null +++ b/meraki/aio/api/mx_1_many_nat_rules.py @@ -0,0 +1,43 @@ +class AsyncMX1ManyNATRules: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkOneToManyNatRules(self, networkId: str): + """ + **Return the 1:Many NAT mapping rules for an MX network** + https://api.meraki.com/api_docs#return-the-1many-nat-mapping-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX 1:Many NAT rules'], + 'operation': 'getNetworkOneToManyNatRules', + } + resource = f'/networks/{networkId}/oneToManyNatRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkOneToManyNatRules(self, networkId: str, rules: list): + """ + **Set the 1:Many NAT mapping rules for an MX network** + https://api.meraki.com/api_docs#set-the-1many-nat-mapping-rules-for-an-mx-network + + - networkId (string) + - rules (array): An array of 1:Many nat rules + """ + + kwargs = locals() + + metadata = { + 'tags': ['MX 1:Many NAT rules'], + 'operation': 'updateNetworkOneToManyNatRules', + } + resource = f'/networks/{networkId}/oneToManyNatRules' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_cellular_firewall.py b/meraki/aio/api/mx_cellular_firewall.py new file mode 100644 index 00000000..8910b839 --- /dev/null +++ b/meraki/aio/api/mx_cellular_firewall.py @@ -0,0 +1,43 @@ +class AsyncMXCellularFirewall: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkCellularFirewallRules(self, networkId: str): + """ + **Return the cellular firewall rules for an MX network** + https://api.meraki.com/api_docs#return-the-cellular-firewall-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX cellular firewall'], + 'operation': 'getNetworkCellularFirewallRules', + } + resource = f'/networks/{networkId}/cellularFirewallRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkCellularFirewallRules(self, networkId: str, **kwargs): + """ + **Update the cellular firewall rules of an MX network** + https://api.meraki.com/api_docs#update-the-cellular-firewall-rules-of-an-mx-network + + - networkId (string) + - rules (array): An ordered array of the firewall rules (not including the default rule) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX cellular firewall'], + 'operation': 'updateNetworkCellularFirewallRules', + } + resource = f'/networks/{networkId}/cellularFirewallRules' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_inbound_firewall.py b/meraki/aio/api/mx_inbound_firewall.py new file mode 100644 index 00000000..68ee471b --- /dev/null +++ b/meraki/aio/api/mx_inbound_firewall.py @@ -0,0 +1,44 @@ +class AsyncMXInboundFirewall: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkApplianceFirewallInboundFirewallRules(self, networkId: str): + """ + **Return the inbound firewall rules for an MX network** + https://api.meraki.com/api_docs#return-the-inbound-firewall-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX inbound firewall'], + 'operation': 'getNetworkApplianceFirewallInboundFirewallRules', + } + resource = f'/networks/{networkId}/appliance/firewall/inboundFirewallRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkApplianceFirewallInboundFirewallRules(self, networkId: str, **kwargs): + """ + **Update the inbound firewall rules of an MX network** + https://api.meraki.com/api_docs#update-the-inbound-firewall-rules-of-an-mx-network + + - networkId (string) + - rules (array): An ordered array of the firewall rules (not including the default rule) + - syslogDefaultRule (boolean): Log the special default rule (boolean value - enable only if you've configured a syslog server) (optional) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX inbound firewall'], + 'operation': 'updateNetworkApplianceFirewallInboundFirewallRules', + } + resource = f'/networks/{networkId}/appliance/firewall/inboundFirewallRules' + + body_params = ['rules', 'syslogDefaultRule'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_l3_firewall.py b/meraki/aio/api/mx_l3_firewall.py new file mode 100644 index 00000000..7276622c --- /dev/null +++ b/meraki/aio/api/mx_l3_firewall.py @@ -0,0 +1,44 @@ +class AsyncMXL3Firewall: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkL3FirewallRules(self, networkId: str): + """ + **Return the L3 firewall rules for an MX network** + https://api.meraki.com/api_docs#return-the-l3-firewall-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX L3 firewall'], + 'operation': 'getNetworkL3FirewallRules', + } + resource = f'/networks/{networkId}/l3FirewallRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkL3FirewallRules(self, networkId: str, **kwargs): + """ + **Update the L3 firewall rules of an MX network** + https://api.meraki.com/api_docs#update-the-l3-firewall-rules-of-an-mx-network + + - networkId (string) + - rules (array): An ordered array of the firewall rules (not including the default rule) + - syslogDefaultRule (boolean): Log the special default rule (boolean value - enable only if you've configured a syslog server) (optional) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX L3 firewall'], + 'operation': 'updateNetworkL3FirewallRules', + } + resource = f'/networks/{networkId}/l3FirewallRules' + + body_params = ['rules', 'syslogDefaultRule'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_l7_application_categories.py b/meraki/aio/api/mx_l7_application_categories.py new file mode 100644 index 00000000..3ed25f9e --- /dev/null +++ b/meraki/aio/api/mx_l7_application_categories.py @@ -0,0 +1,21 @@ +class AsyncMXL7ApplicationCategories: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkL7FirewallRulesApplicationCategories(self, networkId: str): + """ + **Return the L7 firewall application categories and their associated applications for an MX network** + https://api.meraki.com/api_docs#return-the-l7-firewall-application-categories-and-their-associated-applications-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX L7 application categories'], + 'operation': 'getNetworkL7FirewallRulesApplicationCategories', + } + resource = f'/networks/{networkId}/l7FirewallRules/applicationCategories' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/mx_l7_firewall.py b/meraki/aio/api/mx_l7_firewall.py new file mode 100644 index 00000000..73ce56bc --- /dev/null +++ b/meraki/aio/api/mx_l7_firewall.py @@ -0,0 +1,43 @@ +class AsyncMXL7Firewall: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkL7FirewallRules(self, networkId: str): + """ + **List the MX L7 firewall rules for an MX network** + https://api.meraki.com/api_docs#list-the-mx-l7-firewall-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX L7 firewall'], + 'operation': 'getNetworkL7FirewallRules', + } + resource = f'/networks/{networkId}/l7FirewallRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkL7FirewallRules(self, networkId: str, **kwargs): + """ + **Update the MX L7 firewall rules for an MX network** + https://api.meraki.com/api_docs#update-the-mx-l7-firewall-rules-for-an-mx-network + + - networkId (string) + - rules (array): An ordered array of the MX L7 firewall rules + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX L7 firewall'], + 'operation': 'updateNetworkL7FirewallRules', + } + resource = f'/networks/{networkId}/l7FirewallRules' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_port_forwarding_rules.py b/meraki/aio/api/mx_port_forwarding_rules.py new file mode 100644 index 00000000..b55bbb0f --- /dev/null +++ b/meraki/aio/api/mx_port_forwarding_rules.py @@ -0,0 +1,43 @@ +class AsyncMXPortForwardingRules: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkPortForwardingRules(self, networkId: str): + """ + **Return the port forwarding rules for an MX network** + https://api.meraki.com/api_docs#return-the-port-forwarding-rules-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX port forwarding rules'], + 'operation': 'getNetworkPortForwardingRules', + } + resource = f'/networks/{networkId}/portForwardingRules' + + return await self._session.get(metadata, resource) + + async def updateNetworkPortForwardingRules(self, networkId: str, rules: list): + """ + **Update the port forwarding rules for an MX network** + https://api.meraki.com/api_docs#update-the-port-forwarding-rules-for-an-mx-network + + - networkId (string) + - rules (array): An array of port forwarding params + """ + + kwargs = locals() + + metadata = { + 'tags': ['MX port forwarding rules'], + 'operation': 'updateNetworkPortForwardingRules', + } + resource = f'/networks/{networkId}/portForwardingRules' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_static_routes.py b/meraki/aio/api/mx_static_routes.py new file mode 100644 index 00000000..6bafe540 --- /dev/null +++ b/meraki/aio/api/mx_static_routes.py @@ -0,0 +1,107 @@ +class AsyncMXStaticRoutes: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkStaticRoutes(self, networkId: str): + """ + **List the static routes for an MX or teleworker network** + https://api.meraki.com/api_docs#list-the-static-routes-for-an-mx-or-teleworker-network + + - networkId (string) + """ + + metadata = { + 'tags': ['MX static routes'], + 'operation': 'getNetworkStaticRoutes', + } + resource = f'/networks/{networkId}/staticRoutes' + + return await self._session.get(metadata, resource) + + async def createNetworkStaticRoute(self, networkId: str, name: str, subnet: str, gatewayIp: str): + """ + **Add a static route for an MX or teleworker network** + https://api.meraki.com/api_docs#add-a-static-route-for-an-mx-or-teleworker-network + + - networkId (string) + - name (string): The name of the new static route + - subnet (string): The subnet of the static route + - gatewayIp (string): The gateway IP (next hop) of the static route + """ + + kwargs = locals() + + metadata = { + 'tags': ['MX static routes'], + 'operation': 'createNetworkStaticRoute', + } + resource = f'/networks/{networkId}/staticRoutes' + + body_params = ['name', 'subnet', 'gatewayIp'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkStaticRoute(self, networkId: str, staticRouteId: str): + """ + **Return a static route for an MX or teleworker network** + https://api.meraki.com/api_docs#return-a-static-route-for-an-mx-or-teleworker-network + + - networkId (string) + - staticRouteId (string) + """ + + metadata = { + 'tags': ['MX static routes'], + 'operation': 'getNetworkStaticRoute', + } + resource = f'/networks/{networkId}/staticRoutes/{staticRouteId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkStaticRoute(self, networkId: str, staticRouteId: str, **kwargs): + """ + **Update a static route for an MX or teleworker network** + https://api.meraki.com/api_docs#update-a-static-route-for-an-mx-or-teleworker-network + + - networkId (string) + - staticRouteId (string) + - name (string): The name of the static route + - subnet (string): The subnet of the static route + - gatewayIp (string): The gateway IP (next hop) of the static route + - enabled (boolean): The enabled state of the static route + - fixedIpAssignments (object): The DHCP fixed IP assignments on the static route. This should be an object that contains mappings from MAC addresses to objects that themselves each contain "ip" and "name" string fields. See the sample request/response for more details. + - reservedIpRanges (array): The DHCP reserved IP ranges on the static route + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX static routes'], + 'operation': 'updateNetworkStaticRoute', + } + resource = f'/networks/{networkId}/staticRoutes/{staticRouteId}' + + body_params = ['name', 'subnet', 'gatewayIp', 'enabled', 'fixedIpAssignments', 'reservedIpRanges'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkStaticRoute(self, networkId: str, staticRouteId: str): + """ + **Delete a static route from an MX or teleworker network** + https://api.meraki.com/api_docs#delete-a-static-route-from-an-mx-or-teleworker-network + + - networkId (string) + - staticRouteId (string) + """ + + metadata = { + 'tags': ['MX static routes'], + 'operation': 'deleteNetworkStaticRoute', + } + resource = f'/networks/{networkId}/staticRoutes/{staticRouteId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/mx_vlan_ports.py b/meraki/aio/api/mx_vlan_ports.py new file mode 100644 index 00000000..68439d79 --- /dev/null +++ b/meraki/aio/api/mx_vlan_ports.py @@ -0,0 +1,66 @@ +class AsyncMXVLANPorts: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkAppliancePorts(self, networkId: str): + """ + **List per-port VLAN settings for all ports of a MX.** + https://api.meraki.com/api_docs#list-per-port-vlan-settings-for-all-ports-of-a-mx + + - networkId (string) + """ + + metadata = { + 'tags': ['MX VLAN ports'], + 'operation': 'getNetworkAppliancePorts', + } + resource = f'/networks/{networkId}/appliancePorts' + + return await self._session.get(metadata, resource) + + async def getNetworkAppliancePort(self, networkId: str, appliancePortId: str): + """ + **Return per-port VLAN settings for a single MX port.** + https://api.meraki.com/api_docs#return-per-port-vlan-settings-for-a-single-mx-port + + - networkId (string) + - appliancePortId (string) + """ + + metadata = { + 'tags': ['MX VLAN ports'], + 'operation': 'getNetworkAppliancePort', + } + resource = f'/networks/{networkId}/appliancePorts/{appliancePortId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkAppliancePort(self, networkId: str, appliancePortId: str, **kwargs): + """ + **Update the per-port VLAN settings for a single MX port.** + https://api.meraki.com/api_docs#update-the-per-port-vlan-settings-for-a-single-mx-port + + - networkId (string) + - appliancePortId (string) + - enabled (boolean): The status of the port + - dropUntaggedTraffic (boolean): Trunk port can Drop all Untagged traffic. When true, no VLAN is required. Access ports cannot have dropUntaggedTraffic set to true. + - type (string): The type of the port: 'access' or 'trunk'. + - vlan (integer): Native VLAN when the port is in Trunk mode. Access VLAN when the port is in Access mode. + - allowedVlans (string): Comma-delimited list of the VLAN ID's allowed on the port, or 'all' to permit all VLAN's on the port. + - accessPolicy (string): The name of the policy. Only applicable to Access ports. Valid values are: 'open', '8021x-radius', 'mac-radius', 'hybris-radius' for MX64 or Z3 or any MX supporting the per port authentication feature. Otherwise, 'open' is the only valid value and 'open' is the default value if the field is missing. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX VLAN ports'], + 'operation': 'updateNetworkAppliancePort', + } + resource = f'/networks/{networkId}/appliancePorts/{appliancePortId}' + + body_params = ['enabled', 'dropUntaggedTraffic', 'type', 'vlan', 'allowedVlans', 'accessPolicy'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_vpn_firewall.py b/meraki/aio/api/mx_vpn_firewall.py new file mode 100644 index 00000000..9e7c4312 --- /dev/null +++ b/meraki/aio/api/mx_vpn_firewall.py @@ -0,0 +1,44 @@ +class AsyncMXVPNFirewall: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationVpnFirewallRules(self, organizationId: str): + """ + **Return the firewall rules for an organization's site-to-site VPN** + https://api.meraki.com/api_docs#return-the-firewall-rules-for-an-organizations-site-to-site-vpn + + - organizationId (string) + """ + + metadata = { + 'tags': ['MX VPN firewall'], + 'operation': 'getOrganizationVpnFirewallRules', + } + resource = f'/organizations/{organizationId}/vpnFirewallRules' + + return await self._session.get(metadata, resource) + + async def updateOrganizationVpnFirewallRules(self, organizationId: str, **kwargs): + """ + **Update the firewall rules of an organization's site-to-site VPN** + https://api.meraki.com/api_docs#update-the-firewall-rules-of-an-organizations-site-to-site-vpn + + - organizationId (string) + - rules (array): An ordered array of the firewall rules (not including the default rule) + - syslogDefaultRule (boolean): Log the special default rule (boolean value - enable only if you've configured a syslog server) (optional) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX VPN firewall'], + 'operation': 'updateOrganizationVpnFirewallRules', + } + resource = f'/organizations/{organizationId}/vpnFirewallRules' + + body_params = ['rules', 'syslogDefaultRule'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/mx_warm_spare_settings.py b/meraki/aio/api/mx_warm_spare_settings.py new file mode 100644 index 00000000..59dfbae4 --- /dev/null +++ b/meraki/aio/api/mx_warm_spare_settings.py @@ -0,0 +1,63 @@ +class AsyncMXWarmSpareSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def swapNetworkWarmspare(self, networkId: str): + """ + **Swap MX primary and warm spare appliances** + https://api.meraki.com/api_docs#swap-mx-primary-and-warm-spare-appliances + + - networkId (string) + """ + + metadata = { + 'tags': ['MX warm spare settings'], + 'operation': 'swapNetworkWarmspare', + } + resource = f'/networks/{networkId}/swapWarmSpare' + + return await self._session.post(metadata, resource) + + async def getNetworkWarmSpareSettings(self, networkId: str): + """ + **Return MX warm spare settings** + https://api.meraki.com/api_docs#return-mx-warm-spare-settings + + - networkId (string) + """ + + metadata = { + 'tags': ['MX warm spare settings'], + 'operation': 'getNetworkWarmSpareSettings', + } + resource = f'/networks/{networkId}/warmSpareSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkWarmSpareSettings(self, networkId: str, enabled: bool, **kwargs): + """ + **Update MX warm spare settings** + https://api.meraki.com/api_docs#update-mx-warm-spare-settings + + - networkId (string) + - enabled (boolean): Enable warm spare + - spareSerial (string): Serial number of the warm spare appliance + - uplinkMode (string): Uplink mode, either virtual or public + - virtualIp1 (string): The WAN 1 shared IP + - virtualIp2 (string): The WAN 2 shared IP + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['MX warm spare settings'], + 'operation': 'updateNetworkWarmSpareSettings', + } + resource = f'/networks/{networkId}/warmSpareSettings' + + body_params = ['enabled', 'spareSerial', 'uplinkMode', 'virtualIp1', 'virtualIp2'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/named_tag_scope.py b/meraki/aio/api/named_tag_scope.py new file mode 100644 index 00000000..984a123d --- /dev/null +++ b/meraki/aio/api/named_tag_scope.py @@ -0,0 +1,114 @@ +class AsyncNamedTagScope: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSmTargetGroups(self, networkId: str, **kwargs): + """ + **List the target groups in this network** + https://api.meraki.com/api_docs#list-the-target-groups-in-this-network + + - networkId (string) + - withDetails (boolean): Boolean indicating if the the ids of the devices or users scoped by the target group should be included in the response + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Named tag scope'], + 'operation': 'getNetworkSmTargetGroups', + } + resource = f'/networks/{networkId}/sm/targetGroups' + + query_params = ['withDetails'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def createNetworkSmTargetGroup(self, networkId: str, **kwargs): + """ + **Add a target group** + https://api.meraki.com/api_docs#add-a-target-group + + - networkId (string) + - name (string): The name of this target group + - scope (string): The scope and tag options of the target group. Comma separated values beginning with one of withAny, withAll, withoutAny, withoutAll, all, none, followed by tags. Default to none if empty. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Named tag scope'], + 'operation': 'createNetworkSmTargetGroup', + } + resource = f'/networks/{networkId}/sm/targetGroups' + + body_params = ['name', 'scope'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkSmTargetGroup(self, networkId: str, targetGroupId: str, **kwargs): + """ + **Return a target group** + https://api.meraki.com/api_docs#return-a-target-group + + - networkId (string) + - targetGroupId (string) + - withDetails (boolean): Boolean indicating if the the ids of the devices or users scoped by the target group should be included in the response + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Named tag scope'], + 'operation': 'getNetworkSmTargetGroup', + } + resource = f'/networks/{networkId}/sm/targetGroups/{targetGroupId}' + + query_params = ['withDetails'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def updateNetworkSmTargetGroup(self, networkId: str, targetGroupId: str, **kwargs): + """ + **Update a target group** + https://api.meraki.com/api_docs#update-a-target-group + + - networkId (string) + - targetGroupId (string) + - name (string): The name of this target group + - scope (string): The scope and tag options of the target group. Comma separated values beginning with one of withAny, withAll, withoutAny, withoutAll, all, none, followed by tags. Default to none if empty. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Named tag scope'], + 'operation': 'updateNetworkSmTargetGroup', + } + resource = f'/networks/{networkId}/sm/targetGroups/{targetGroupId}' + + body_params = ['name', 'scope'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkSmTargetGroup(self, networkId: str, targetGroupId: str): + """ + **Delete a target group from a network** + https://api.meraki.com/api_docs#delete-a-target-group-from-a-network + + - networkId (string) + - targetGroupId (string) + """ + + metadata = { + 'tags': ['Named tag scope'], + 'operation': 'deleteNetworkSmTargetGroup', + } + resource = f'/networks/{networkId}/sm/targetGroups/{targetGroupId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/netflow_settings.py b/meraki/aio/api/netflow_settings.py new file mode 100644 index 00000000..20c07462 --- /dev/null +++ b/meraki/aio/api/netflow_settings.py @@ -0,0 +1,45 @@ +class AsyncNetFlowSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkNetflowSettings(self, networkId: str): + """ + **Return the NetFlow traffic reporting settings for a network** + https://api.meraki.com/api_docs#return-the-netflow-traffic-reporting-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['NetFlow settings'], + 'operation': 'getNetworkNetflowSettings', + } + resource = f'/networks/{networkId}/netflowSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkNetflowSettings(self, networkId: str, **kwargs): + """ + **Update the NetFlow traffic reporting settings for a network** + https://api.meraki.com/api_docs#update-the-netflow-traffic-reporting-settings-for-a-network + + - networkId (string) + - reportingEnabled (boolean): Boolean indicating whether NetFlow traffic reporting is enabled (true) or disabled (false). + - collectorIp (string): The IPv4 address of the NetFlow collector. + - collectorPort (integer): The port that the NetFlow collector will be listening on. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['NetFlow settings'], + 'operation': 'updateNetworkNetflowSettings', + } + resource = f'/networks/{networkId}/netflowSettings' + + body_params = ['reportingEnabled', 'collectorIp', 'collectorPort'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/networks.py b/meraki/aio/api/networks.py new file mode 100644 index 00000000..1929e43c --- /dev/null +++ b/meraki/aio/api/networks.py @@ -0,0 +1,304 @@ +class AsyncNetworks: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetwork(self, networkId: str): + """ + **Return a network** + https://api.meraki.com/api_docs#return-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Networks'], + 'operation': 'getNetwork', + } + resource = f'/networks/{networkId}' + + return await self._session.get(metadata, resource) + + async def updateNetwork(self, networkId: str, **kwargs): + """ + **Update a network** + https://api.meraki.com/api_docs#update-a-network + + - networkId (string) + - name (string): The name of the network + - timeZone (string): The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article. + - tags (string): A space-separated list of tags to be applied to the network + - disableMyMerakiCom (boolean): Disables the local device status pages (my.meraki.com, ap.meraki.com, switch.meraki.com, wired.meraki.com). Optional (defaults to false) + - disableRemoteStatusPage (boolean): Disables access to the device status page (http://[device's LAN IP]). Optional. Can only be set if disableMyMerakiCom is set to false + - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'updateNetwork', + } + resource = f'/networks/{networkId}' + + body_params = ['name', 'timeZone', 'tags', 'disableMyMerakiCom', 'disableRemoteStatusPage', 'enrollmentString'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetwork(self, networkId: str): + """ + **Delete a network** + https://api.meraki.com/api_docs#delete-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Networks'], + 'operation': 'deleteNetwork', + } + resource = f'/networks/{networkId}' + + return await self._session.delete(metadata, resource) + + async def getNetworkAccessPolicies(self, networkId: str): + """ + **List the access policies for this network. Only valid for MS networks.** + https://api.meraki.com/api_docs#list-the-access-policies-for-this-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Networks'], + 'operation': 'getNetworkAccessPolicies', + } + resource = f'/networks/{networkId}/accessPolicies' + + return await self._session.get(metadata, resource) + + async def getNetworkAirMarshal(self, networkId: str, **kwargs): + """ + **List Air Marshal scan results from a network** + https://api.meraki.com/api_docs#list-air-marshal-scan-results-from-a-network + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 7 days. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'getNetworkAirMarshal', + } + resource = f'/networks/{networkId}/airMarshal' + + query_params = ['t0', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def bindNetwork(self, networkId: str, configTemplateId: str, **kwargs): + """ + **Bind a network to a template.** + https://api.meraki.com/api_docs#bind-a-network-to-a-template + + - networkId (string) + - configTemplateId (string): The ID of the template to which the network should be bound. + - autoBind (boolean): Optional boolean indicating whether the network's switches should automatically bind to profiles of the same model. Defaults to false if left unspecified. This option only affects switch networks and switch templates. Auto-bind is not valid unless the switch template has at least one profile and has at most one profile per switch model. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'bindNetwork', + } + resource = f'/networks/{networkId}/bind' + + body_params = ['configTemplateId', 'autoBind'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkSiteToSiteVpn(self, networkId: str): + """ + **Return the site-to-site VPN settings of a network. Only valid for MX networks.** + https://api.meraki.com/api_docs#return-the-site-to-site-vpn-settings-of-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Networks'], + 'operation': 'getNetworkSiteToSiteVpn', + } + resource = f'/networks/{networkId}/siteToSiteVpn' + + return await self._session.get(metadata, resource) + + async def updateNetworkSiteToSiteVpn(self, networkId: str, mode: str, **kwargs): + """ + **Update the site-to-site VPN settings of a network. Only valid for MX networks in NAT mode.** + https://api.meraki.com/api_docs#update-the-site-to-site-vpn-settings-of-a-network + + - networkId (string) + - mode (string): The site-to-site VPN mode. Can be one of 'none', 'spoke' or 'hub' + - hubs (array): The list of VPN hubs, in order of preference. In spoke mode, at least 1 hub is required. + - subnets (array): The list of subnets and their VPN presence. + """ + + kwargs.update(locals()) + + if 'mode' in kwargs: + options = ['none', 'spoke', 'hub'] + assert kwargs['mode'] in options, f'''"mode" cannot be "{kwargs['mode']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Networks'], + 'operation': 'updateNetworkSiteToSiteVpn', + } + resource = f'/networks/{networkId}/siteToSiteVpn' + + body_params = ['mode', 'hubs', 'subnets'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def splitNetwork(self, networkId: str): + """ + **Split a combined network into individual networks for each type of device** + https://api.meraki.com/api_docs#split-a-combined-network-into-individual-networks-for-each-type-of-device + + - networkId (string) + """ + + metadata = { + 'tags': ['Networks'], + 'operation': 'splitNetwork', + } + resource = f'/networks/{networkId}/split' + + return await self._session.post(metadata, resource) + + async def getNetworkTraffic(self, networkId: str, **kwargs): + """ + ** The traffic analysis data for this network. + Traffic Analysis with Hostname Visibility must be enabled on the network. +** + https://api.meraki.com/api_docs#----the-traffic-analysis-data-for-this-network + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 30 days from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 30 days. + - deviceType (string): Filter the data by device type: combined (default), wireless, switch, appliance. + When using combined, for each rule the data will come from the device type with the most usage. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'getNetworkTraffic', + } + resource = f'/networks/{networkId}/traffic' + + query_params = ['t0', 'timespan', 'deviceType'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def unbindNetwork(self, networkId: str): + """ + **Unbind a network from a template.** + https://api.meraki.com/api_docs#unbind-a-network-from-a-template + + - networkId (string) + """ + + metadata = { + 'tags': ['Networks'], + 'operation': 'unbindNetwork', + } + resource = f'/networks/{networkId}/unbind' + + return await self._session.post(metadata, resource) + + async def getOrganizationNetworks(self, organizationId: str, **kwargs): + """ + **List the networks in an organization** + https://api.meraki.com/api_docs#list-the-networks-in-an-organization + + - organizationId (string) + - configTemplateId (string): An optional parameter that is the ID of a config template. Will return all networks bound to that template. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'getOrganizationNetworks', + } + resource = f'/organizations/{organizationId}/networks' + + query_params = ['configTemplateId'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def createOrganizationNetwork(self, organizationId: str, name: str, type: str, **kwargs): + """ + **Create a network** + https://api.meraki.com/api_docs#create-a-network + + - organizationId (string) + - name (string): The name of the new network + - type (string): The type of the new network. Valid types are wireless, appliance, switch, systemsManager, camera, cellularGateway, or a space-separated list of those for a combined network. + - tags (string): A space-separated list of tags to be applied to the network + - timeZone (string): The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article. + - copyFromNetworkId (string): The ID of the network to copy configuration from. Other provided parameters will override the copied configuration, except type which must match this network's type exactly. + - disableMyMerakiCom (boolean): Disables the local device status pages (my.meraki.com, ap.meraki.com, switch.meraki.com, wired.meraki.com). Optional (defaults to false) + - disableRemoteStatusPage (boolean): Disables access to the device status page (http://[device's LAN IP]). Optional. Can only be set if disableMyMerakiCom is set to false + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'createOrganizationNetwork', + } + resource = f'/organizations/{organizationId}/networks' + + body_params = ['name', 'type', 'tags', 'timeZone', 'copyFromNetworkId', 'disableMyMerakiCom', 'disableRemoteStatusPage'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def combineOrganizationNetworks(self, organizationId: str, name: str, networkIds: list, **kwargs): + """ + **Combine multiple networks into a single network** + https://api.meraki.com/api_docs#combine-multiple-networks-into-a-single-network + + - organizationId (string) + - name (string): The name of the combined network + - networkIds (array): A list of the network IDs that will be combined. If an ID of a combined network is included in this list, the other networks in the list will be grouped into that network + - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break. All networks that are part of this combined network will have their enrollment string appended by '-network_type'. If left empty, all exisitng enrollment strings will be deleted. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Networks'], + 'operation': 'combineOrganizationNetworks', + } + resource = f'/organizations/{organizationId}/networks/combine' + + body_params = ['name', 'networkIds', 'enrollmentString'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + diff --git a/meraki/aio/api/openapi_spec.py b/meraki/aio/api/openapi_spec.py new file mode 100644 index 00000000..f13e1e68 --- /dev/null +++ b/meraki/aio/api/openapi_spec.py @@ -0,0 +1,21 @@ +class AsyncOpenAPISpec: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationOpenapiSpec(self, organizationId: str): + """ + **Return the OpenAPI 2.0 Specification of the organization's API documentation in JSON** + https://api.meraki.com/api_docs#return-the-openapi-2 + + - organizationId (string) + """ + + metadata = { + 'tags': ['OpenAPI Spec'], + 'operation': 'getOrganizationOpenapiSpec', + } + resource = f'/organizations/{organizationId}/openapiSpec' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/organizations.py b/meraki/aio/api/organizations.py new file mode 100644 index 00000000..e7132d1a --- /dev/null +++ b/meraki/aio/api/organizations.py @@ -0,0 +1,263 @@ +class AsyncOrganizations: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizations(self): + """ + **List the organizations that the user has privileges on** + https://api.meraki.com/api_docs#list-the-organizations-that-the-user-has-privileges-on + + """ + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganizations', + } + resource = f'/organizations' + + return await self._session.get(metadata, resource) + + async def createOrganization(self, name: str): + """ + **Create a new organization** + https://api.meraki.com/api_docs#create-a-new-organization + + - name (string): The name of the organization + """ + + kwargs = locals() + + metadata = { + 'tags': ['Organizations'], + 'operation': 'createOrganization', + } + resource = f'/organizations' + + body_params = ['name'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganization(self, organizationId: str): + """ + **Return an organization** + https://api.meraki.com/api_docs#return-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganization', + } + resource = f'/organizations/{organizationId}' + + return await self._session.get(metadata, resource) + + async def updateOrganization(self, organizationId: str, **kwargs): + """ + **Update an organization** + https://api.meraki.com/api_docs#update-an-organization + + - organizationId (string) + - name (string): The name of the organization + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Organizations'], + 'operation': 'updateOrganization', + } + resource = f'/organizations/{organizationId}' + + body_params = ['name'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteOrganization(self, organizationId: str): + """ + **Delete an organization** + https://api.meraki.com/api_docs#delete-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Organizations'], + 'operation': 'deleteOrganization', + } + resource = f'/organizations/{organizationId}' + + return await self._session.delete(metadata, resource) + + async def claimOrganization(self, organizationId: str, **kwargs): + """ + **Claim a list of devices, licenses, and/or orders into an organization. When claiming by order, all devices and licenses in the order will be claimed; licenses will be added to the organization and devices will be placed in the organization's inventory.** + https://api.meraki.com/api_docs#claim-a-list-of-devices-licenses-and/or-orders-into-an-organization + + - organizationId (string) + - orders (array): The numbers of the orders that should be claimed + - serials (array): The serials of the devices that should be claimed + - licenses (array): The licenses that should be claimed + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Organizations'], + 'operation': 'claimOrganization', + } + resource = f'/organizations/{organizationId}/claim' + + body_params = ['orders', 'serials', 'licenses'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def cloneOrganization(self, organizationId: str, name: str): + """ + **Create a new organization by cloning the addressed organization** + https://api.meraki.com/api_docs#create-a-new-organization-by-cloning-the-addressed-organization + + - organizationId (string) + - name (string): The name of the new organization + """ + + kwargs = locals() + + metadata = { + 'tags': ['Organizations'], + 'operation': 'cloneOrganization', + } + resource = f'/organizations/{organizationId}/clone' + + body_params = ['name'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganizationDeviceStatuses(self, organizationId: str): + """ + **List the status of every Meraki device in the organization** + https://api.meraki.com/api_docs#list-the-status-of-every-meraki-device-in-the-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganizationDeviceStatuses', + } + resource = f'/organizations/{organizationId}/deviceStatuses' + + return await self._session.get(metadata, resource) + + async def getOrganizationInventory(self, organizationId: str, **kwargs): + """ + **Return the inventory for an organization** + https://api.meraki.com/api_docs#return-the-inventory-for-an-organization + + - organizationId (string) + - includeLicenseInfo (boolean): When this parameter is true, each entity in the response will include the license expiration date of the device (if any). Only applies to organizations that support per-device licensing. Defaults to false. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganizationInventory', + } + resource = f'/organizations/{organizationId}/inventory' + + query_params = ['includeLicenseInfo'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getOrganizationLicenseState(self, organizationId: str): + """ + **Return an overview of the license state for an organization** + https://api.meraki.com/api_docs#return-an-overview-of-the-license-state-for-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganizationLicenseState', + } + resource = f'/organizations/{organizationId}/licenseState' + + return await self._session.get(metadata, resource) + + async def getOrganizationThirdPartyVPNPeers(self, organizationId: str): + """ + **Return the third party VPN peers for an organization** + https://api.meraki.com/api_docs#return-the-third-party-vpn-peers-for-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganizationThirdPartyVPNPeers', + } + resource = f'/organizations/{organizationId}/thirdPartyVPNPeers' + + return await self._session.get(metadata, resource) + + async def updateOrganizationThirdPartyVPNPeers(self, organizationId: str, peers: list): + """ + **Update the third party VPN peers for an organization** + https://api.meraki.com/api_docs#update-the-third-party-vpn-peers-for-an-organization + + - organizationId (string) + - peers (array): The list of VPN peers + """ + + kwargs = locals() + + metadata = { + 'tags': ['Organizations'], + 'operation': 'updateOrganizationThirdPartyVPNPeers', + } + resource = f'/organizations/{organizationId}/thirdPartyVPNPeers' + + body_params = ['peers'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getOrganizationUplinksLossAndLatency(self, organizationId: str, **kwargs): + """ + **Return the uplink loss and latency for every MX in the organization from at latest 2 minutes ago** + https://api.meraki.com/api_docs#return-the-uplink-loss-and-latency-for-every-mx-in-the-organization-from-at-latest-2-minutes-ago + + - organizationId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 5 minutes after t0. The latest possible time that t1 can be is 2 minutes into the past. + - timespan (number): The timespan for 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 5 minutes. The default is 5 minutes. + - uplink (string): Optional filter for a specific WAN uplink. Valid uplinks are wan1, wan2, cellular. Default will return all uplinks. + - ip (string): Optional filter for a specific destination IP. Default will return all destination IPs. + """ + + kwargs.update(locals()) + + if 'uplink' in kwargs: + options = ['wan1', 'wan2', 'cellular'] + assert kwargs['uplink'] in options, f'''"uplink" cannot be "{kwargs['uplink']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Organizations'], + 'operation': 'getOrganizationUplinksLossAndLatency', + } + resource = f'/organizations/{organizationId}/uplinksLossAndLatency' + + query_params = ['t0', 't1', 'timespan', 'uplink', 'ip'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/pii.py b/meraki/aio/api/pii.py new file mode 100644 index 00000000..a6f5e22b --- /dev/null +++ b/meraki/aio/api/pii.py @@ -0,0 +1,168 @@ +class AsyncPII: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkPiiPiiKeys(self, networkId: str, **kwargs): + """ + **List the keys required to access Personally Identifiable Information (PII) for a given identifier. Exactly one identifier will be accepted. If the organization contains org-wide Systems Manager users matching the key provided then there will be an entry with the key "0" containing the applicable keys.** + https://api.meraki.com/api_docs#list-the-keys-required-to-access-personally-identifiable-information-pii-for-a-given-identifier + + - networkId (string) + - username (string): The username of a Systems Manager user + - email (string): The email of a network user account or a Systems Manager device + - mac (string): The MAC of a network client device or a Systems Manager device + - serial (string): The serial of a Systems Manager device + - imei (string): The IMEI of a Systems Manager device + - bluetoothMac (string): The MAC of a Bluetooth client + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['PII'], + 'operation': 'getNetworkPiiPiiKeys', + } + resource = f'/networks/{networkId}/pii/piiKeys' + + query_params = ['username', 'email', 'mac', 'serial', 'imei', 'bluetoothMac'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkPiiRequests(self, networkId: str): + """ + **List the PII requests for this network or organization** + https://api.meraki.com/api_docs#list-the-pii-requests-for-this-network-or-organization + + - networkId (string) + """ + + metadata = { + 'tags': ['PII'], + 'operation': 'getNetworkPiiRequests', + } + resource = f'/networks/{networkId}/pii/requests' + + return await self._session.get(metadata, resource) + + async def createNetworkPiiRequest(self, networkId: str, **kwargs): + """ + **Submit a new delete or restrict processing PII request** + https://api.meraki.com/api_docs#submit-a-new-delete-or-restrict-processing-pii-request + + - networkId (string) + - type (string): One of "delete" or "restrict processing" + - datasets (array): The datasets related to the provided key that should be deleted. Only applies to "delete" requests. The value "all" will be expanded to all datasets applicable to this type. The datasets by applicable to each type are: mac (usage, events, traffic), email (users, loginAttempts), username (users, loginAttempts), bluetoothMac (client, connectivity), smDeviceId (device), smUserId (user) + - username (string): The username of a network log in. Only applies to "delete" requests. + - email (string): The email of a network user account. Only applies to "delete" requests. + - mac (string): The MAC of a network client device. Applies to both "restrict processing" and "delete" requests. + - smDeviceId (string): The sm_device_id of a Systems Manager device. The only way to "restrict processing" or "delete" a Systems Manager device. Must include "device" in the dataset for a "delete" request to destroy the device. + - smUserId (string): The sm_user_id of a Systems Manager user. The only way to "restrict processing" or "delete" a Systems Manager user. Must include "user" in the dataset for a "delete" request to destroy the user. + """ + + kwargs.update(locals()) + + if 'type' in kwargs: + options = ['delete', 'restrict processing'] + assert kwargs['type'] in options, f'''"type" cannot be "{kwargs['type']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['PII'], + 'operation': 'createNetworkPiiRequest', + } + resource = f'/networks/{networkId}/pii/requests' + + body_params = ['type', 'datasets', 'username', 'email', 'mac', 'smDeviceId', 'smUserId'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkPiiRequest(self, networkId: str, requestId: str): + """ + **Return a PII request** + https://api.meraki.com/api_docs#return-a-pii-request + + - networkId (string) + - requestId (string) + """ + + metadata = { + 'tags': ['PII'], + 'operation': 'getNetworkPiiRequest', + } + resource = f'/networks/{networkId}/pii/requests/{requestId}' + + return await self._session.get(metadata, resource) + + async def deleteNetworkPiiRequest(self, networkId: str, requestId: str): + """ + **Delete a restrict processing PII request** + https://api.meraki.com/api_docs#delete-a-restrict-processing-pii-request + + - networkId (string) + - requestId (string) + """ + + metadata = { + 'tags': ['PII'], + 'operation': 'deleteNetworkPiiRequest', + } + resource = f'/networks/{networkId}/pii/requests/{requestId}' + + return await self._session.delete(metadata, resource) + + async def getNetworkPiiSmDevicesForKey(self, networkId: str, **kwargs): + """ + **Given a piece of Personally Identifiable Information (PII), return the Systems Manager device ID(s) associated with that identifier. These device IDs can be used with the Systems Manager API endpoints to retrieve device details. Exactly one identifier will be accepted.** + https://api.meraki.com/api_docs#given-a-piece-of-personally-identifiable-information-pii-return-the-systems-manager-device-ids-associated-with-that-identifier + + - networkId (string) + - username (string): The username of a Systems Manager user + - email (string): The email of a network user account or a Systems Manager device + - mac (string): The MAC of a network client device or a Systems Manager device + - serial (string): The serial of a Systems Manager device + - imei (string): The IMEI of a Systems Manager device + - bluetoothMac (string): The MAC of a Bluetooth client + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['PII'], + 'operation': 'getNetworkPiiSmDevicesForKey', + } + resource = f'/networks/{networkId}/pii/smDevicesForKey' + + query_params = ['username', 'email', 'mac', 'serial', 'imei', 'bluetoothMac'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkPiiSmOwnersForKey(self, networkId: str, **kwargs): + """ + **Given a piece of Personally Identifiable Information (PII), return the Systems Manager owner ID(s) associated with that identifier. These owner IDs can be used with the Systems Manager API endpoints to retrieve owner details. Exactly one identifier will be accepted.** + https://api.meraki.com/api_docs#given-a-piece-of-personally-identifiable-information-pii-return-the-systems-manager-owner-ids-associated-with-that-identifier + + - networkId (string) + - username (string): The username of a Systems Manager user + - email (string): The email of a network user account or a Systems Manager device + - mac (string): The MAC of a network client device or a Systems Manager device + - serial (string): The serial of a Systems Manager device + - imei (string): The IMEI of a Systems Manager device + - bluetoothMac (string): The MAC of a Bluetooth client + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['PII'], + 'operation': 'getNetworkPiiSmOwnersForKey', + } + resource = f'/networks/{networkId}/pii/smOwnersForKey' + + query_params = ['username', 'email', 'mac', 'serial', 'imei', 'bluetoothMac'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/radio_settings.py b/meraki/aio/api/radio_settings.py new file mode 100644 index 00000000..0f5c9391 --- /dev/null +++ b/meraki/aio/api/radio_settings.py @@ -0,0 +1,177 @@ +class AsyncRadioSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkDeviceWirelessRadioSettings(self, networkId: str, serial: str): + """ + **Return the radio settings of a device** + https://api.meraki.com/api_docs#return-the-radio-settings-of-a-device + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'getNetworkDeviceWirelessRadioSettings', + } + resource = f'/networks/{networkId}/devices/{serial}/wireless/radioSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkDeviceWirelessRadioSettings(self, networkId: str, serial: str, **kwargs): + """ + **Update the radio settings of a device** + https://api.meraki.com/api_docs#update-the-radio-settings-of-a-device + + - networkId (string) + - serial (string) + - rfProfileId (integer): The ID of an RF profile to assign to the device. If the value of this parameter is null, the appropriate basic RF profile + (indoor or outdoor) will be assigned to the device. Assigning an RF profile will clear ALL manually configured overrides + on the device (channel width, channel, power). + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'updateNetworkDeviceWirelessRadioSettings', + } + resource = f'/networks/{networkId}/devices/{serial}/wireless/radioSettings' + + body_params = ['rfProfileId'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkWirelessRfProfiles(self, networkId: str, **kwargs): + """ + **List the non-basic RF profiles for this network** + https://api.meraki.com/api_docs#list-the-non-basic-rf-profiles-for-this-network + + - networkId (string) + - includeTemplateProfiles (boolean): If the network is bound to a template, this parameter controls whether or not the non-basic RF profiles defined on the template + should be included in the response alongside the non-basic profiles defined on the bound network. Defaults to false. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'getNetworkWirelessRfProfiles', + } + resource = f'/networks/{networkId}/wireless/rfProfiles' + + query_params = ['includeTemplateProfiles'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def createNetworkWirelessRfProfile(self, networkId: str, name: str, bandSelectionType: str, **kwargs): + """ + **Creates new RF profile for this network** + https://api.meraki.com/api_docs#creates-new-rf-profile-for-this-network + + - networkId (string) + - name (string): The name of the new profile. Must be unique. This param is required on creation. + - bandSelectionType (string): Band selection can be set to either 'ssid' or 'ap'. This param is required on creation. + - clientBalancingEnabled (boolean): Steers client to best available access point. Can be either true or false. Defaults to true. + - minBitrateType (string): Minimum bitrate can be set to either 'band' or 'ssid'. Defaults to band. + - apBandSettings (object): Settings that will be enabled if selectionType is set to 'ap'. + - twoFourGhzSettings (object): Settings related to 2.4Ghz band + - fiveGhzSettings (object): Settings related to 5Ghz band + """ + + kwargs.update(locals()) + + if 'minBitrateType' in kwargs: + options = ['band', 'ssid'] + assert kwargs['minBitrateType'] in options, f'''"minBitrateType" cannot be "{kwargs['minBitrateType']}", & must be set to one of: {options}''' + if 'bandSelectionType' in kwargs: + options = ['ssid', 'ap'] + assert kwargs['bandSelectionType'] in options, f'''"bandSelectionType" cannot be "{kwargs['bandSelectionType']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'createNetworkWirelessRfProfile', + } + resource = f'/networks/{networkId}/wireless/rfProfiles' + + body_params = ['name', 'clientBalancingEnabled', 'minBitrateType', 'bandSelectionType', 'apBandSettings', 'twoFourGhzSettings', 'fiveGhzSettings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def updateNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str, **kwargs): + """ + **Updates specified RF profile for this network** + https://api.meraki.com/api_docs#updates-specified-rf-profile-for-this-network + + - networkId (string) + - rfProfileId (string) + - name (string): The name of the new profile. Must be unique. + - clientBalancingEnabled (boolean): Steers client to best available access point. Can be either true or false. + - minBitrateType (string): Minimum bitrate can be set to either 'band' or 'ssid'. + - bandSelectionType (string): Band selection can be set to either 'ssid' or 'ap'. + - apBandSettings (object): Settings that will be enabled if selectionType is set to 'ap'. + - twoFourGhzSettings (object): Settings related to 2.4Ghz band + - fiveGhzSettings (object): Settings related to 5Ghz band + """ + + kwargs.update(locals()) + + if 'minBitrateType' in kwargs: + options = ['band', 'ssid'] + assert kwargs['minBitrateType'] in options, f'''"minBitrateType" cannot be "{kwargs['minBitrateType']}", & must be set to one of: {options}''' + if 'bandSelectionType' in kwargs: + options = ['ssid', 'ap'] + assert kwargs['bandSelectionType'] in options, f'''"bandSelectionType" cannot be "{kwargs['bandSelectionType']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'updateNetworkWirelessRfProfile', + } + resource = f'/networks/{networkId}/wireless/rfProfiles/{rfProfileId}' + + body_params = ['name', 'clientBalancingEnabled', 'minBitrateType', 'bandSelectionType', 'apBandSettings', 'twoFourGhzSettings', 'fiveGhzSettings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str): + """ + **Delete a RF Profile** + https://api.meraki.com/api_docs#delete-a-rf-profile + + - networkId (string) + - rfProfileId (string) + """ + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'deleteNetworkWirelessRfProfile', + } + resource = f'/networks/{networkId}/wireless/rfProfiles/{rfProfileId}' + + return await self._session.delete(metadata, resource) + + async def getNetworkWirelessRfProfile(self, networkId: str, rfProfileId: str): + """ + **Return a RF profile** + https://api.meraki.com/api_docs#return-a-rf-profile + + - networkId (string) + - rfProfileId (string) + """ + + metadata = { + 'tags': ['Radio settings'], + 'operation': 'getNetworkWirelessRfProfile', + } + resource = f'/networks/{networkId}/wireless/rfProfiles/{rfProfileId}' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/saml_roles.py b/meraki/aio/api/saml_roles.py new file mode 100644 index 00000000..213e6280 --- /dev/null +++ b/meraki/aio/api/saml_roles.py @@ -0,0 +1,106 @@ +class AsyncSAMLRoles: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationSamlRoles(self, organizationId: str): + """ + **List the SAML roles for this organization** + https://api.meraki.com/api_docs#list-the-saml-roles-for-this-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['SAML roles'], + 'operation': 'getOrganizationSamlRoles', + } + resource = f'/organizations/{organizationId}/samlRoles' + + return await self._session.get(metadata, resource) + + async def createOrganizationSamlRole(self, organizationId: str, **kwargs): + """ + **Create a SAML role** + https://api.meraki.com/api_docs#create-a-saml-role + + - organizationId (string) + - role (string): The role of the SAML administrator + - orgAccess (string): The privilege of the SAML administrator on the organization + - tags (array): The list of tags that the SAML administrator has privleges on + - networks (array): The list of networks that the SAML administrator has privileges on + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SAML roles'], + 'operation': 'createOrganizationSamlRole', + } + resource = f'/organizations/{organizationId}/samlRoles' + + body_params = ['role', 'orgAccess', 'tags', 'networks'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getOrganizationSamlRole(self, organizationId: str, samlRoleId: str): + """ + **Return a SAML role** + https://api.meraki.com/api_docs#return-a-saml-role + + - organizationId (string) + - samlRoleId (string) + """ + + metadata = { + 'tags': ['SAML roles'], + 'operation': 'getOrganizationSamlRole', + } + resource = f'/organizations/{organizationId}/samlRoles/{samlRoleId}' + + return await self._session.get(metadata, resource) + + async def updateOrganizationSamlRole(self, organizationId: str, samlRoleId: str, **kwargs): + """ + **Update a SAML role** + https://api.meraki.com/api_docs#update-a-saml-role + + - organizationId (string) + - samlRoleId (string) + - role (string): The role of the SAML administrator + - orgAccess (string): The privilege of the SAML administrator on the organization + - tags (array): The list of tags that the SAML administrator has privleges on + - networks (array): The list of networks that the SAML administrator has privileges on + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SAML roles'], + 'operation': 'updateOrganizationSamlRole', + } + resource = f'/organizations/{organizationId}/samlRoles/{samlRoleId}' + + body_params = ['role', 'orgAccess', 'tags', 'networks'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteOrganizationSamlRole(self, organizationId: str, samlRoleId: str): + """ + **Remove a SAML role** + https://api.meraki.com/api_docs#remove-a-saml-role + + - organizationId (string) + - samlRoleId (string) + """ + + metadata = { + 'tags': ['SAML roles'], + 'operation': 'deleteOrganizationSamlRole', + } + resource = f'/organizations/{organizationId}/samlRoles/{samlRoleId}' + + return await self._session.delete(metadata, resource) + diff --git a/meraki/aio/api/security_events.py b/meraki/aio/api/security_events.py new file mode 100644 index 00000000..04df12d3 --- /dev/null +++ b/meraki/aio/api/security_events.py @@ -0,0 +1,96 @@ +class AsyncSecurityEvents: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkClientSecurityEvents(self, networkId: str, clientId: str, total_pages=1, direction='next', **kwargs): + """ + **List the security events for a client. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** + https://api.meraki.com/api_docs#list-the-security-events-for-a-client + + - networkId (string) + - clientId (string) + - total_pages (integer or string): total number of pages to retrieve, -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 791 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 791 days after t0. + - timespan (number): The timespan for 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 791 days. The default is 31 days. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Security events'], + 'operation': 'getNetworkClientSecurityEvents', + } + resource = f'/networks/{networkId}/clients/{clientId}/securityEvents' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkSecurityEvents(self, networkId: str, total_pages=1, direction='next', **kwargs): + """ + **List the security events for a network** + https://api.meraki.com/api_docs#list-the-security-events-for-a-network + + - networkId (string) + - total_pages (integer or string): total number of pages to retrieve, -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 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 365 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 365 days. The default is 31 days. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Security events'], + 'operation': 'getNetworkSecurityEvents', + } + resource = f'/networks/{networkId}/securityEvents' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getOrganizationSecurityEvents(self, organizationId: str, total_pages=1, direction='next', **kwargs): + """ + **List the security events for an organization** + https://api.meraki.com/api_docs#list-the-security-events-for-an-organization + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -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 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 365 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 365 days. The default is 31 days. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 100. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Security events'], + 'operation': 'getOrganizationSecurityEvents', + } + resource = f'/organizations/{organizationId}/securityEvents' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + diff --git a/meraki/aio/api/sm.py b/meraki/aio/api/sm.py new file mode 100644 index 00000000..63d2c428 --- /dev/null +++ b/meraki/aio/api/sm.py @@ -0,0 +1,686 @@ +class AsyncSM: + def __init__(self, session): + super().__init__() + self._session = session + + async def createNetworkSmAppPolaris(self, networkId: str, scope: str, **kwargs): + """ + **Create a new Polaris app** + https://api.meraki.com/api_docs#create-a-new-polaris-app + + - networkId (string) + - scope (string): The scope (one of all, none, automatic, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be assigned + - manifestUrl (string): The manifest URL of the Polaris app (one of manifestUrl and bundleId must be provided) + - bundleId (string): The bundleId of the Polaris app (one of manifestUrl and bundleId must be provided) + - preventAutoInstall (boolean): (optional) Whether or not SM should auto-install this app (one of true or false). False by default. + - usesVPP (boolean): (optional) Whether or not the app should use VPP by device assignment (one of true or false). False by default. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'createNetworkSmAppPolaris', + } + resource = f'/networks/{networkId}/sm/app/polaris' + + body_params = ['scope', 'manifestUrl', 'bundleId', 'preventAutoInstall', 'usesVPP'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkSmAppPolaris(self, networkId: str, **kwargs): + """ + **Get details for a Cisco Polaris app if it exists** + https://api.meraki.com/api_docs#get-details-for-a-cisco-polaris-app-if-it-exists + + - networkId (string) + - bundleId (string): The bundle ID of the app to be found, defaults to com.cisco.ciscosecurity.app + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmAppPolaris', + } + resource = f'/networks/{networkId}/sm/app/polaris' + + query_params = ['bundleId'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def updateNetworkSmAppPolaris(self, networkId: str, appId: str, **kwargs): + """ + **Update an existing Polaris app** + https://api.meraki.com/api_docs#update-an-existing-polaris-app + + - networkId (string) + - appId (string) + - scope (string): optional: The scope (one of all, none, automatic, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be assigned + - preventAutoInstall (boolean): optional: Whether or not SM should auto-install this app (one of true or false) + - usesVPP (boolean): optional: Whether or not the app should use VPP by device assignment (one of true or false) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'updateNetworkSmAppPolaris', + } + resource = f'/networks/{networkId}/sm/app/polaris/{appId}' + + body_params = ['scope', 'preventAutoInstall', 'usesVPP'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkSmAppPolaris(self, networkId: str, appId: str): + """ + **Delete a Cisco Polaris app** + https://api.meraki.com/api_docs#delete-a-cisco-polaris-app + + - networkId (string) + - appId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'deleteNetworkSmAppPolaris', + } + resource = f'/networks/{networkId}/sm/app/polaris/{appId}' + + return await self._session.delete(metadata, resource) + + async def createNetworkSmBypassActivationLockAttempt(self, networkId: str, ids: list): + """ + **Bypass activation lock attempt** + https://api.meraki.com/api_docs#bypass-activation-lock-attempt + + - networkId (string) + - ids (array): The ids of the devices to attempt activation lock bypass. + """ + + kwargs = locals() + + metadata = { + 'tags': ['SM'], + 'operation': 'createNetworkSmBypassActivationLockAttempt', + } + resource = f'/networks/{networkId}/sm/bypassActivationLockAttempts' + + body_params = ['ids'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkSmBypassActivationLockAttempt(self, networkId: str, attemptId: str): + """ + **Bypass activation lock attempt status** + https://api.meraki.com/api_docs#bypass-activation-lock-attempt-status + + - networkId (string) + - attemptId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmBypassActivationLockAttempt', + } + resource = f'/networks/{networkId}/sm/bypassActivationLockAttempts/{attemptId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkSmDeviceFields(self, networkId: str, deviceFields: dict, **kwargs): + """ + **Modify the fields of a device** + https://api.meraki.com/api_docs#modify-the-fields-of-a-device + + - networkId (string) + - deviceFields (object): The new fields of the device. Each field of this object is optional. + - wifiMac (string): The wifiMac of the device to be modified. + - id (string): The id of the device to be modified. + - serial (string): The serial of the device to be modified. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'updateNetworkSmDeviceFields', + } + resource = f'/networks/{networkId}/sm/device/fields' + + body_params = ['wifiMac', 'id', 'serial', 'deviceFields'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def wipeNetworkSmDevice(self, networkId: str, **kwargs): + """ + **Wipe a device** + https://api.meraki.com/api_docs#wipe-a-device + + - networkId (string) + - wifiMac (string): The wifiMac of the device to be wiped. + - id (string): The id of the device to be wiped. + - serial (string): The serial of the device to be wiped. + - pin (integer): The pin number (a six digit value) for wiping a macOS device. Required only for macOS devices. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'wipeNetworkSmDevice', + } + resource = f'/networks/{networkId}/sm/device/wipe' + + body_params = ['wifiMac', 'id', 'serial', 'pin'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def refreshNetworkSmDeviceDetails(self, networkId: str, deviceId: str): + """ + **Refresh the details of a device** + https://api.meraki.com/api_docs#refresh-the-details-of-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'refreshNetworkSmDeviceDetails', + } + resource = f'/networks/{networkId}/sm/device/{deviceId}/refreshDetails' + + return await self._session.post(metadata, resource) + + async def getNetworkSmDevices(self, networkId: str, **kwargs): + """ + **List the devices enrolled in an SM network with various specified fields and filters** + https://api.meraki.com/api_docs#list-the-devices-enrolled-in-an-sm-network-with-various-specified-fields-and-filters + + - networkId (string) + - fields (string): Additional fields that will be displayed for each device. Multiple fields can be passed in as comma separated values. + The default fields are: id, name, tags, ssid, wifiMac, osName, systemModel, uuid, and serialNumber. The additional fields are: ip, + systemType, availableDeviceCapacity, kioskAppName, biosVersion, lastConnected, missingAppsCount, userSuppliedAddress, location, lastUser, + ownerEmail, ownerUsername, publicIp, phoneNumber, diskInfoJson, deviceCapacity, isManaged, hadMdm, isSupervised, meid, imei, iccid, + simCarrierNetwork, cellularDataUsed, isHotspotEnabled, createdAt, batteryEstCharge, quarantined, avName, avRunning, asName, fwName, + isRooted, loginRequired, screenLockEnabled, screenLockDelay, autoLoginDisabled, autoTags, hasMdm, hasDesktopAgent, diskEncryptionEnabled, + hardwareEncryptionCaps, passCodeLock, usesHardwareKeystore, and androidSecurityPatchVersion. + - wifiMacs (string): Filter devices by wifi mac(s). Multiple wifi macs can be passed in as comma separated values. + - serials (string): Filter devices by serial(s). Multiple serials can be passed in as comma separated values. + - ids (string): Filter devices by id(s). Multiple ids can be passed in as comma separated values. + - scope (string): Specify a scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags as comma separated values. + - batchSize (integer): Number of devices to return, 1000 is the default as well as the max. + - batchToken (string): If the network has more devices than the batch size, a batch token will be returned + as a part of the device list. To see the remainder of the devices, pass in the batchToken as a parameter in the next request. + Requests made with the batchToken do not require additional parameters as the batchToken includes the parameters passed in + with the original request. Additional parameters passed in with the batchToken will be ignored. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmDevices', + } + resource = f'/networks/{networkId}/sm/devices' + + query_params = ['fields', 'wifiMacs', 'serials', 'ids', 'scope', 'batchSize', 'batchToken'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def checkinNetworkSmDevices(self, networkId: str, **kwargs): + """ + **Force check-in a set of devices** + https://api.meraki.com/api_docs#force-check-in-a-set-of-devices + + - networkId (string) + - wifiMacs (string): The wifiMacs of the devices to be checked-in. + - ids (string): The ids of the devices to be checked-in. + - serials (string): The serials of the devices to be checked-in. + - scope (string): The scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be checked-in. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'checkinNetworkSmDevices', + } + resource = f'/networks/{networkId}/sm/devices/checkin' + + body_params = ['wifiMacs', 'ids', 'serials', 'scope'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def moveNetworkSmDevices(self, networkId: str, newNetwork: str, **kwargs): + """ + **Move a set of devices to a new network** + https://api.meraki.com/api_docs#move-a-set-of-devices-to-a-new-network + + - networkId (string) + - newNetwork (string): The new network to which the devices will be moved. + - wifiMacs (string): The wifiMacs of the devices to be moved. + - ids (string): The ids of the devices to be moved. + - serials (string): The serials of the devices to be moved. + - scope (string): The scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be moved. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'moveNetworkSmDevices', + } + resource = f'/networks/{networkId}/sm/devices/move' + + body_params = ['wifiMacs', 'ids', 'serials', 'scope', 'newNetwork'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def updateNetworkSmDevicesTags(self, networkId: str, tags: str, updateAction: str, **kwargs): + """ + **Add, delete, or update the tags of a set of devices** + https://api.meraki.com/api_docs#add-delete-or-update-the-tags-of-a-set-of-devices + + - networkId (string) + - tags (string): The tags to be added, deleted, or updated. + - updateAction (string): One of add, delete, or update. Only devices that have been modified will be returned. + - wifiMacs (string): The wifiMacs of the devices to be modified. + - ids (string): The ids of the devices to be modified. + - serials (string): The serials of the devices to be modified. + - scope (string): The scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be modified. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'updateNetworkSmDevicesTags', + } + resource = f'/networks/{networkId}/sm/devices/tags' + + body_params = ['wifiMacs', 'ids', 'serials', 'scope', 'tags', 'updateAction'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def unenrollNetworkSmDevice(self, networkId: str, deviceId: str): + """ + **Unenroll a device** + https://api.meraki.com/api_docs#unenroll-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'unenrollNetworkSmDevice', + } + resource = f'/networks/{networkId}/sm/devices/{deviceId}/unenroll' + + return await self._session.post(metadata, resource) + + async def getNetworkSmProfiles(self, networkId: str): + """ + **List all the profiles in the network** + https://api.meraki.com/api_docs#list-all-the-profiles-in-the-network + + - networkId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmProfiles', + } + resource = f'/networks/{networkId}/sm/profiles' + + return await self._session.get(metadata, resource) + + async def getNetworkSmUserDeviceProfiles(self, networkId: str, userId: str): + """ + **Get the profiles associated with a user** + https://api.meraki.com/api_docs#get-the-profiles-associated-with-a-user + + - networkId (string) + - userId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmUserDeviceProfiles', + } + resource = f'/networks/{networkId}/sm/user/{userId}/deviceProfiles' + + return await self._session.get(metadata, resource) + + async def getNetworkSmUserSoftwares(self, networkId: str, userId: str): + """ + **Get a list of softwares associated with a user** + https://api.meraki.com/api_docs#get-a-list-of-softwares-associated-with-a-user + + - networkId (string) + - userId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmUserSoftwares', + } + resource = f'/networks/{networkId}/sm/user/{userId}/softwares' + + return await self._session.get(metadata, resource) + + async def getNetworkSmUsers(self, networkId: str, **kwargs): + """ + **List the owners in an SM network with various specified fields and filters** + https://api.meraki.com/api_docs#list-the-owners-in-an-sm-network-with-various-specified-fields-and-filters + + - networkId (string) + - ids (string): Filter users by id(s). Multiple ids can be passed in as comma separated values. + - usernames (string): Filter users by username(s). Multiple usernames can be passed in as comma separated values. + - emails (string): Filter users by email(s). Multiple emails can be passed in as comma separated values. + - scope (string): Specifiy a scope (one of all, none, withAny, withAll, withoutAny, withoutAll) and a set of tags as comma separated values. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmUsers', + } + resource = f'/networks/{networkId}/sm/users' + + query_params = ['ids', 'usernames', 'emails', 'scope'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkSmCellularUsageHistory(self, networkId: str, deviceId: str): + """ + **Return the client's daily cellular data usage history. Usage data is in kilobytes.** + https://api.meraki.com/api_docs#return-the-clients-daily-cellular-data-usage-history + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmCellularUsageHistory', + } + resource = f'/networks/{networkId}/sm/{deviceId}/cellularUsageHistory' + + return await self._session.get(metadata, resource) + + async def getNetworkSmCerts(self, networkId: str, deviceId: str): + """ + **List the certs on a device** + https://api.meraki.com/api_docs#list-the-certs-on-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmCerts', + } + resource = f'/networks/{networkId}/sm/{deviceId}/certs' + + return await self._session.get(metadata, resource) + + async def getNetworkSmDeviceProfiles(self, networkId: str, deviceId: str): + """ + **Get the profiles associated with a device** + https://api.meraki.com/api_docs#get-the-profiles-associated-with-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmDeviceProfiles', + } + resource = f'/networks/{networkId}/sm/{deviceId}/deviceProfiles' + + return await self._session.get(metadata, resource) + + async def getNetworkSmNetworkAdapters(self, networkId: str, deviceId: str): + """ + **List the network adapters of a device** + https://api.meraki.com/api_docs#list-the-network-adapters-of-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmNetworkAdapters', + } + resource = f'/networks/{networkId}/sm/{deviceId}/networkAdapters' + + return await self._session.get(metadata, resource) + + async def getNetworkSmRestrictions(self, networkId: str, deviceId: str): + """ + **List the restrictions on a device** + https://api.meraki.com/api_docs#list-the-restrictions-on-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmRestrictions', + } + resource = f'/networks/{networkId}/sm/{deviceId}/restrictions' + + return await self._session.get(metadata, resource) + + async def getNetworkSmSecurityCenters(self, networkId: str, deviceId: str): + """ + **List the security centers on a device** + https://api.meraki.com/api_docs#list-the-security-centers-on-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmSecurityCenters', + } + resource = f'/networks/{networkId}/sm/{deviceId}/securityCenters' + + return await self._session.get(metadata, resource) + + async def getNetworkSmSoftwares(self, networkId: str, deviceId: str): + """ + **Get a list of softwares associated with a device** + https://api.meraki.com/api_docs#get-a-list-of-softwares-associated-with-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmSoftwares', + } + resource = f'/networks/{networkId}/sm/{deviceId}/softwares' + + return await self._session.get(metadata, resource) + + async def getNetworkSmWlanLists(self, networkId: str, deviceId: str): + """ + **List the saved SSID names on a device** + https://api.meraki.com/api_docs#list-the-saved-ssid-names-on-a-device + + - networkId (string) + - deviceId (string) + """ + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmWlanLists', + } + resource = f'/networks/{networkId}/sm/{deviceId}/wlanLists' + + return await self._session.get(metadata, resource) + + async def lockNetworkSmDevices(self, network_id: str, **kwargs): + """ + **Lock a set of devices** + https://api.meraki.com/api_docs#lock-a-set-of-devices + + - network_id (string) + - wifiMacs (string): The wifiMacs of the devices to be locked. + - ids (string): The ids of the devices to be locked. + - serials (string): The serials of the devices to be locked. + - scope (string): The scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be wiped. + - pin (integer): The pin number for locking macOS devices (a six digit number). Required only for macOS devices. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'lockNetworkSmDevices', + } + resource = f'/networks/{network_id}/sm/devices/lock' + + body_params = ['wifiMacs', 'ids', 'serials', 'scope', 'pin'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSmConnectivity(self, network_id: str, id: str, total_pages=1, direction='next', **kwargs): + """ + **Returns historical connectivity data (whether a device is regularly checking in to Dashboard).** + https://api.meraki.com/api_docs#returns-historical-connectivity-data-whether-a-device-is-regularly-checking-in-to-dashboard + + - network_id (string) + - id (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmConnectivity', + } + resource = f'/networks/{network_id}/sm/{id}/connectivity' + + query_params = ['perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkSmDesktopLogs(self, network_id: str, id: str, total_pages=1, direction='next', **kwargs): + """ + **Return historical records of various Systems Manager network connection details for desktop devices.** + https://api.meraki.com/api_docs#return-historical-records-of-various-systems-manager-network-connection-details-for-desktop-devices + + - network_id (string) + - id (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmDesktopLogs', + } + resource = f'/networks/{network_id}/sm/{id}/desktopLogs' + + query_params = ['perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkSmDeviceCommandLogs(self, network_id: str, id: str, total_pages=1, direction='next', **kwargs): + """ + ** Return historical records of commands sent to Systems Manager devices. +

Note that this will include the name of the Dashboard user who initiated the command if it was generated + by a Dashboard admin rather than the automatic behavior of the system; you may wish to filter this out + of any reports.

+** + https://api.meraki.com/api_docs#----return-historical-records-of-commands-sent-to-systems-manager-devices + + - network_id (string) + - id (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmDeviceCommandLogs', + } + resource = f'/networks/{network_id}/sm/{id}/deviceCommandLogs' + + query_params = ['perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + + async def getNetworkSmPerformanceHistory(self, network_id: str, id: str, total_pages=1, direction='next', **kwargs): + """ + **Return historical records of various Systems Manager client metrics for desktop devices.** + https://api.meraki.com/api_docs#return-historical-records-of-various-systems-manager-client-metrics-for-desktop-devices + + - network_id (string) + - id (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "next" (default) or "prev" page + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['SM'], + 'operation': 'getNetworkSmPerformanceHistory', + } + resource = f'/networks/{network_id}/sm/{id}/performanceHistory' + + query_params = ['perPage', 'startingAfter', 'endingBefore'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + diff --git a/meraki/aio/api/snmp_settings.py b/meraki/aio/api/snmp_settings.py new file mode 100644 index 00000000..121356d1 --- /dev/null +++ b/meraki/aio/api/snmp_settings.py @@ -0,0 +1,100 @@ +class AsyncSNMPSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSnmpSettings(self, networkId: str): + """ + **Return the SNMP settings for a network** + https://api.meraki.com/api_docs#return-the-snmp-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['SNMP settings'], + 'operation': 'getNetworkSnmpSettings', + } + resource = f'/networks/{networkId}/snmpSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkSnmpSettings(self, networkId: str, **kwargs): + """ + **Update the SNMP settings for a network** + https://api.meraki.com/api_docs#update-the-snmp-settings-for-a-network + + - networkId (string) + - access (string): The type of SNMP access. Can be one of 'none' (disabled), 'community' (V1/V2c), or 'users' (V3). + - communityString (string): The SNMP community string. Only relevant if 'access' is set to 'community'. + - users (array): The list of SNMP users. Only relevant if 'access' is set to 'users'. + """ + + kwargs.update(locals()) + + if 'access' in kwargs: + options = ['none', 'community', 'users'] + assert kwargs['access'] in options, f'''"access" cannot be "{kwargs['access']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['SNMP settings'], + 'operation': 'updateNetworkSnmpSettings', + } + resource = f'/networks/{networkId}/snmpSettings' + + body_params = ['access', 'communityString', 'users'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getOrganizationSnmp(self, organizationId: str): + """ + **Return the SNMP settings for an organization** + https://api.meraki.com/api_docs#return-the-snmp-settings-for-an-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['SNMP settings'], + 'operation': 'getOrganizationSnmp', + } + resource = f'/organizations/{organizationId}/snmp' + + return await self._session.get(metadata, resource) + + async def updateOrganizationSnmp(self, organizationId: str, **kwargs): + """ + **Update the SNMP settings for an organization** + https://api.meraki.com/api_docs#update-the-snmp-settings-for-an-organization + + - organizationId (string) + - v2cEnabled (boolean): Boolean indicating whether SNMP version 2c is enabled for the organization. + - v3Enabled (boolean): Boolean indicating whether SNMP version 3 is enabled for the organization. + - v3AuthMode (string): The SNMP version 3 authentication mode. Can be either 'MD5' or 'SHA'. + - v3AuthPass (string): The SNMP version 3 authentication password. Must be at least 8 characters if specified. + - v3PrivMode (string): The SNMP version 3 privacy mode. Can be either 'DES' or 'AES128'. + - v3PrivPass (string): The SNMP version 3 privacy password. Must be at least 8 characters if specified. + - peerIps (string): The IPs that are allowed to access the SNMP server. This list should be IPv4 addresses separated by semi-colons (ie. "1.2.3.4;2.3.4.5"). + """ + + kwargs.update(locals()) + + if 'v3AuthMode' in kwargs: + options = ['MD5', 'SHA'] + assert kwargs['v3AuthMode'] in options, f'''"v3AuthMode" cannot be "{kwargs['v3AuthMode']}", & must be set to one of: {options}''' + if 'v3PrivMode' in kwargs: + options = ['DES', 'AES128'] + assert kwargs['v3PrivMode'] in options, f'''"v3PrivMode" cannot be "{kwargs['v3PrivMode']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['SNMP settings'], + 'operation': 'updateOrganizationSnmp', + } + resource = f'/organizations/{organizationId}/snmp' + + body_params = ['v2cEnabled', 'v3Enabled', 'v3AuthMode', 'v3AuthPass', 'v3PrivMode', 'v3PrivPass', 'peerIps'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/splash_login_attempts.py b/meraki/aio/api/splash_login_attempts.py new file mode 100644 index 00000000..62c48678 --- /dev/null +++ b/meraki/aio/api/splash_login_attempts.py @@ -0,0 +1,33 @@ +class AsyncSplashLoginAttempts: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSplashLoginAttempts(self, networkId: str, **kwargs): + """ + **List the splash login attempts for a network** + https://api.meraki.com/api_docs#list-the-splash-login-attempts-for-a-network + + - networkId (string) + - ssidNumber (integer): Only return the login attempts for the specified SSID + - loginIdentifier (string): The username, email, or phone number used during login + - timespan (integer): The timespan, in seconds, for the login attempts. The period will be from [timespan] seconds ago until now. The maximum timespan is 3 months + """ + + kwargs.update(locals()) + + if 'ssidNumber' in kwargs: + options = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + assert kwargs['ssidNumber'] in options, f'''"ssidNumber" cannot be "{kwargs['ssidNumber']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Splash login attempts'], + 'operation': 'getNetworkSplashLoginAttempts', + } + resource = f'/networks/{networkId}/splashLoginAttempts' + + query_params = ['ssidNumber', 'loginIdentifier', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/splash_settings.py b/meraki/aio/api/splash_settings.py new file mode 100644 index 00000000..e0d6cfce --- /dev/null +++ b/meraki/aio/api/splash_settings.py @@ -0,0 +1,46 @@ +class AsyncSplashSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSsidSplashSettings(self, networkId: str, number: str): + """ + **Display the splash page settings for the given SSID** + https://api.meraki.com/api_docs#display-the-splash-page-settings-for-the-given-ssid + + - networkId (string) + - number (string) + """ + + metadata = { + 'tags': ['Splash settings'], + 'operation': 'getNetworkSsidSplashSettings', + } + resource = f'/networks/{networkId}/ssids/{number}/splashSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkSsidSplashSettings(self, networkId: str, number: str, **kwargs): + """ + **Modify the splash page settings for the given SSID** + https://api.meraki.com/api_docs#modify-the-splash-page-settings-for-the-given-ssid + + - networkId (string) + - number (string) + - splashUrl (string): [optional] The custom splash URL of the click-through splash page. Note that the URL can be configured without necessarily being used. In order to enable the custom URL, see 'useSplashUrl' + - useSplashUrl (boolean): [optional] Boolean indicating whether the user will be redirected to the custom splash url. A custom splash URL must be set if this is true. Note that depending on your SSID's access control settings, it may not be possible to use the custom splash URL. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Splash settings'], + 'operation': 'updateNetworkSsidSplashSettings', + } + resource = f'/networks/{networkId}/ssids/{number}/splashSettings' + + body_params = ['splashUrl', 'useSplashUrl'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/ssids.py b/meraki/aio/api/ssids.py new file mode 100644 index 00000000..34c43806 --- /dev/null +++ b/meraki/aio/api/ssids.py @@ -0,0 +1,128 @@ +class AsyncSSIDs: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkDeviceWirelessStatus(self, networkId: str, serial: str): + """ + **Return the SSID statuses of an access point** + https://api.meraki.com/api_docs#return-the-ssid-statuses-of-an-access-point + + - networkId (string) + - serial (string) + """ + + metadata = { + 'tags': ['SSIDs'], + 'operation': 'getNetworkDeviceWirelessStatus', + } + resource = f'/networks/{networkId}/devices/{serial}/wireless/status' + + return await self._session.get(metadata, resource) + + async def getNetworkSsids(self, networkId: str): + """ + **List the SSIDs in a network. Supports networks with access points or wireless-enabled security appliances and teleworker gateways.** + https://api.meraki.com/api_docs#list-the-ssids-in-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['SSIDs'], + 'operation': 'getNetworkSsids', + } + resource = f'/networks/{networkId}/ssids' + + return await self._session.get(metadata, resource) + + async def getNetworkSsid(self, networkId: str, number: str): + """ + **Return a single SSID** + https://api.meraki.com/api_docs#return-a-single-ssid + + - networkId (string) + - number (string) + """ + + metadata = { + 'tags': ['SSIDs'], + 'operation': 'getNetworkSsid', + } + resource = f'/networks/{networkId}/ssids/{number}' + + return await self._session.get(metadata, resource) + + async def updateNetworkSsid(self, networkId: str, number: str, **kwargs): + """ + **Update the attributes of an SSID** + https://api.meraki.com/api_docs#update-the-attributes-of-an-ssid + + - networkId (string) + - number (string) + - name (string): The name of the SSID + - enabled (boolean): Whether or not the SSID is enabled + - authMode (string): The association control method for the SSID ('open', 'psk', 'open-with-radius', '8021x-meraki' or '8021x-radius') + - enterpriseAdminAccess (string): Whether or not an SSID is accessible by 'enterprise' administrators ('access disabled' or 'access enabled') + - encryptionMode (string): The psk encryption mode for the SSID ('wep' or 'wpa'). This param is only valid if the authMode is 'psk' + - psk (string): The passkey for the SSID. This param is only valid if the authMode is 'psk' + - wpaEncryptionMode (string): The types of WPA encryption. ('WPA1 only', 'WPA1 and WPA2', 'WPA2 only', 'WPA3 Transition Mode' or 'WPA3 only') + - splashPage (string): The type of splash page for the SSID ('None', 'Click-through splash page', 'Billing', 'Password-protected with Meraki RADIUS', 'Password-protected with custom RADIUS', 'Password-protected with Active Directory', 'Password-protected with LDAP', 'SMS authentication', 'Systems Manager Sentry', 'Facebook Wi-Fi', 'Google OAuth' or 'Sponsored guest'). This attribute is not supported for template children. + - radiusServers (array): The RADIUS 802.1x servers to be used for authentication. This param is only valid if the authMode is 'open-with-radius' or '8021x-radius' + - radiusCoaEnabled (boolean): If true, Meraki devices will act as a RADIUS Dynamic Authorization Server and will respond to RADIUS Change-of-Authorization and Disconnect messages sent by the RADIUS server. + - radiusFailoverPolicy (string): This policy determines how authentication requests should be handled in the event that all of the configured RADIUS servers are unreachable ('Deny access' or 'Allow access') + - radiusLoadBalancingPolicy (string): This policy determines which RADIUS server will be contacted first in an authentication attempt and the ordering of any necessary retry attempts ('Strict priority order' or 'Round robin') + - radiusAccountingEnabled (boolean): Whether or not RADIUS accounting is enabled. This param is only valid if the authMode is 'open-with-radius' or '8021x-radius' + - radiusAccountingServers (array): The RADIUS accounting 802.1x servers to be used for authentication. This param is only valid if the authMode is 'open-with-radius' or '8021x-radius' and radiusAccountingEnabled is 'true' + - radiusAttributeForGroupPolicies (string): Specify the RADIUS attribute used to look up group policies ('Filter-Id', 'Reply-Message', 'Airespace-ACL-Name' or 'Aruba-User-Role'). Access points must receive this attribute in the RADIUS Access-Accept message + - ipAssignmentMode (string): The client IP assignment mode ('NAT mode', 'Bridge mode', 'Layer 3 roaming', 'Layer 3 roaming with a concentrator' or 'VPN') + - useVlanTagging (boolean): Whether or not traffic should be directed to use specific VLANs. This param is only valid if the ipAssignmentMode is 'Bridge mode' or 'Layer 3 roaming' + - concentratorNetworkId (string): The concentrator to use when the ipAssignmentMode is 'Layer 3 roaming with a concentrator' or 'VPN'. + - vlanId (integer): The VLAN ID used for VLAN tagging. This param is only valid when the ipAssignmentMode is 'Layer 3 roaming with a concentrator' or 'VPN' + - defaultVlanId (integer): The default VLAN ID used for 'all other APs'. This param is only valid when the ipAssignmentMode is 'Bridge mode' or 'Layer 3 roaming' + - apTagsAndVlanIds (array): The list of tags and VLAN IDs used for VLAN tagging. This param is only valid when the ipAssignmentMode is 'Bridge mode' or 'Layer 3 roaming' + - walledGardenEnabled (boolean): Allow access to a configurable list of IP ranges, which users may access prior to sign-on. + - walledGardenRanges (string): Specify your walled garden by entering space-separated addresses, ranges using CIDR notation, domain names, and domain wildcards (e.g. 192.168.1.1/24 192.168.37.10/32 www.yahoo.com *.google.com). Meraki's splash page is automatically included in your walled garden. + - radiusOverride (boolean): If true, the RADIUS response can override VLAN tag. This is not valid when ipAssignmentMode is 'NAT mode'. + - minBitrate (number): The minimum bitrate in Mbps. ('1', '2', '5.5', '6', '9', '11', '12', '18', '24', '36', '48' or '54') + - bandSelection (string): The client-serving radio frequencies. ('Dual band operation', '5 GHz band only' or 'Dual band operation with Band Steering') + - perClientBandwidthLimitUp (integer): The upload bandwidth limit in Kbps. (0 represents no limit.) + - perClientBandwidthLimitDown (integer): The download bandwidth limit in Kbps. (0 represents no limit.) + - lanIsolationEnabled (boolean): Boolean indicating whether Layer 2 LAN isolation should be enabled or disabled. Only configurable when ipAssignmentMode is 'Bridge mode'. + """ + + kwargs.update(locals()) + + if 'authMode' in kwargs: + options = ['open', 'psk', 'open-with-radius', '8021x-meraki', '8021x-radius'] + assert kwargs['authMode'] in options, f'''"authMode" cannot be "{kwargs['authMode']}", & must be set to one of: {options}''' + if 'enterpriseAdminAccess' in kwargs: + options = ['access disabled', 'access enabled'] + assert kwargs['enterpriseAdminAccess'] in options, f'''"enterpriseAdminAccess" cannot be "{kwargs['enterpriseAdminAccess']}", & must be set to one of: {options}''' + if 'encryptionMode' in kwargs: + options = ['wep', 'wpa'] + assert kwargs['encryptionMode'] in options, f'''"encryptionMode" cannot be "{kwargs['encryptionMode']}", & must be set to one of: {options}''' + if 'wpaEncryptionMode' in kwargs: + options = ['WPA1 only', 'WPA1 and WPA2', 'WPA2 only', 'WPA3 Transition Mode', 'WPA3 only'] + assert kwargs['wpaEncryptionMode'] in options, f'''"wpaEncryptionMode" cannot be "{kwargs['wpaEncryptionMode']}", & must be set to one of: {options}''' + if 'splashPage' in kwargs: + options = ['None', 'Click-through splash page', 'Billing', 'Password-protected with Meraki RADIUS', 'Password-protected with custom RADIUS', 'Password-protected with Active Directory', 'Password-protected with LDAP', 'SMS authentication', 'Systems Manager Sentry', 'Facebook Wi-Fi', 'Google OAuth', 'Sponsored guest'] + assert kwargs['splashPage'] in options, f'''"splashPage" cannot be "{kwargs['splashPage']}", & must be set to one of: {options}''' + if 'radiusFailoverPolicy' in kwargs: + options = ['Deny access', 'Allow access'] + assert kwargs['radiusFailoverPolicy'] in options, f'''"radiusFailoverPolicy" cannot be "{kwargs['radiusFailoverPolicy']}", & must be set to one of: {options}''' + if 'radiusLoadBalancingPolicy' in kwargs: + options = ['Strict priority order', 'Round robin'] + assert kwargs['radiusLoadBalancingPolicy'] in options, f'''"radiusLoadBalancingPolicy" cannot be "{kwargs['radiusLoadBalancingPolicy']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['SSIDs'], + 'operation': 'updateNetworkSsid', + } + resource = f'/networks/{networkId}/ssids/{number}' + + body_params = ['name', 'enabled', 'authMode', 'enterpriseAdminAccess', 'encryptionMode', 'psk', 'wpaEncryptionMode', 'splashPage', 'radiusServers', 'radiusCoaEnabled', 'radiusFailoverPolicy', 'radiusLoadBalancingPolicy', 'radiusAccountingEnabled', 'radiusAccountingServers', 'radiusAttributeForGroupPolicies', 'ipAssignmentMode', 'useVlanTagging', 'concentratorNetworkId', 'vlanId', 'defaultVlanId', 'apTagsAndVlanIds', 'walledGardenEnabled', 'walledGardenRanges', 'radiusOverride', 'minBitrate', 'bandSelection', 'perClientBandwidthLimitUp', 'perClientBandwidthLimitDown', 'lanIsolationEnabled'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/switch_acls.py b/meraki/aio/api/switch_acls.py new file mode 100644 index 00000000..027629e5 --- /dev/null +++ b/meraki/aio/api/switch_acls.py @@ -0,0 +1,43 @@ +class AsyncSwitchACLs: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSwitchAccessControlLists(self, networkId: str): + """ + **Return the access control lists for a MS network** + https://api.meraki.com/api_docs#return-the-access-control-lists-for-a-ms-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch ACLs'], + 'operation': 'getNetworkSwitchAccessControlLists', + } + resource = f'/networks/{networkId}/switch/accessControlLists' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchAccessControlLists(self, networkId: str, rules: list): + """ + **Update the access control lists for a MS network** + https://api.meraki.com/api_docs#update-the-access-control-lists-for-a-ms-network + + - networkId (string) + - rules (array): An ordered array of the access control list rules (not including the default rule). An empty array will clear the rules. + """ + + kwargs = locals() + + metadata = { + 'tags': ['Switch ACLs'], + 'operation': 'updateNetworkSwitchAccessControlLists', + } + resource = f'/networks/{networkId}/switch/accessControlLists' + + body_params = ['rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/switch_port_schedules.py b/meraki/aio/api/switch_port_schedules.py new file mode 100644 index 00000000..d376d5aa --- /dev/null +++ b/meraki/aio/api/switch_port_schedules.py @@ -0,0 +1,91 @@ +class AsyncSwitchPortSchedules: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSwitchPortSchedules(self, networkId: str): + """ + **List switch port schedules** + https://api.meraki.com/api_docs#list-switch-port-schedules + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch port schedules'], + 'operation': 'getNetworkSwitchPortSchedules', + } + resource = f'/networks/{networkId}/switch/portSchedules' + + return await self._session.get(metadata, resource) + + async def createNetworkSwitchPortSchedule(self, networkId: str, name: str, **kwargs): + """ + **Add a switch port schedule** + https://api.meraki.com/api_docs#add-a-switch-port-schedule + + - networkId (string) + - name (string): The name for your port schedule. Required + - portSchedule (object): The schedule for switch port scheduling. Schedules are applied to days of the week. + When it's empty, default schedule with all days of a week are configured. + Any unspecified day in the schedule is added as a default schedule configuration of the day. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch port schedules'], + 'operation': 'createNetworkSwitchPortSchedule', + } + resource = f'/networks/{networkId}/switch/portSchedules' + + body_params = ['name', 'portSchedule'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def deleteNetworkSwitchPortSchedule(self, networkId: str, portScheduleId: str): + """ + **Delete a switch port schedule** + https://api.meraki.com/api_docs#delete-a-switch-port-schedule + + - networkId (string) + - portScheduleId (string) + """ + + metadata = { + 'tags': ['Switch port schedules'], + 'operation': 'deleteNetworkSwitchPortSchedule', + } + resource = f'/networks/{networkId}/switch/portSchedules/{portScheduleId}' + + return await self._session.delete(metadata, resource) + + async def updateNetworkSwitchPortSchedule(self, networkId: str, portScheduleId: str, **kwargs): + """ + **Update a switch port schedule** + https://api.meraki.com/api_docs#update-a-switch-port-schedule + + - networkId (string) + - portScheduleId (string) + - name (string): The name for your port schedule. + - portSchedule (object): The schedule for switch port scheduling. Schedules are applied to days of the week. + When it's empty, default schedule with all days of a week are configured. + Any unspecified day in the schedule is added as a default schedule configuration of the day. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch port schedules'], + 'operation': 'updateNetworkSwitchPortSchedule', + } + resource = f'/networks/{networkId}/switch/portSchedules/{portScheduleId}' + + body_params = ['name', 'portSchedule'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/switch_ports.py b/meraki/aio/api/switch_ports.py new file mode 100644 index 00000000..77d889ae --- /dev/null +++ b/meraki/aio/api/switch_ports.py @@ -0,0 +1,135 @@ +class AsyncSwitchPorts: + def __init__(self, session): + super().__init__() + self._session = session + + async def getDeviceSwitchPortStatuses(self, serial: str, **kwargs): + """ + **Return the status for all the ports of a switch** + https://api.meraki.com/api_docs#return-the-status-for-all-the-ports-of-a-switch + + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch ports'], + 'operation': 'getDeviceSwitchPortStatuses', + } + resource = f'/devices/{serial}/switchPortStatuses' + + query_params = ['t0', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getDeviceSwitchPortStatusesPackets(self, serial: str, **kwargs): + """ + **Return the packet counters for all the ports of a switch** + https://api.meraki.com/api_docs#return-the-packet-counters-for-all-the-ports-of-a-switch + + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 1 day. The default is 1 day. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch ports'], + 'operation': 'getDeviceSwitchPortStatusesPackets', + } + resource = f'/devices/{serial}/switchPortStatuses/packets' + + query_params = ['t0', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getDeviceSwitchPorts(self, serial: str): + """ + **List the switch ports for a switch** + https://api.meraki.com/api_docs#list-the-switch-ports-for-a-switch + + - serial (string) + """ + + metadata = { + 'tags': ['Switch ports'], + 'operation': 'getDeviceSwitchPorts', + } + resource = f'/devices/{serial}/switchPorts' + + return await self._session.get(metadata, resource) + + async def getDeviceSwitchPort(self, serial: str, number: str): + """ + **Return a switch port** + https://api.meraki.com/api_docs#return-a-switch-port + + - serial (string) + - number (string) + """ + + metadata = { + 'tags': ['Switch ports'], + 'operation': 'getDeviceSwitchPort', + } + resource = f'/devices/{serial}/switchPorts/{number}' + + return await self._session.get(metadata, resource) + + async def updateDeviceSwitchPort(self, serial: str, number: str, **kwargs): + """ + **Update a switch port** + https://api.meraki.com/api_docs#update-a-switch-port + + - serial (string) + - number (string) + - name (string): The name of the switch port + - tags (string): The tags of the switch port + - enabled (boolean): The status of the switch port + - type (string): The type of the switch port ('trunk' or 'access') + - vlan (integer): The VLAN of the switch port. A null value will clear the value set for trunk ports. + - voiceVlan (integer): The voice VLAN of the switch port. Only applicable to access ports. + - allowedVlans (string): The VLANs allowed on the switch port. Only applicable to trunk ports. + - poeEnabled (boolean): The PoE status of the switch port + - isolationEnabled (boolean): The isolation status of the switch port + - rstpEnabled (boolean): The rapid spanning tree protocol status + - stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard') + - accessPolicyNumber (integer): The number of the access policy of the switch port. Only applicable to access ports. + - linkNegotiation (string): The link speed for the switch port + - portScheduleId (string): The ID of the port schedule. A value of null will clear the port schedule. + - udld (string): The action to take when Unidirectional Link is detected (Alert only, Enforce). Default configuration is Alert only. + - macWhitelist (array): Only devices with MAC addresses specified in this list will have access to this port. Up to 20 MAC addresses can be defined. To disable MAC whitelist, set accessPolicyNumber to null. + - stickyMacWhitelist (array): The initial list of MAC addresses for sticky Mac whitelist. To reset Sticky MAC whitelist, set accessPolicyNumber to null. + - stickyMacWhitelistLimit (integer): The maximum number of MAC addresses for sticky MAC whitelist. + - stormControlEnabled (boolean): The storm control status of the switch port + """ + + kwargs.update(locals()) + + if 'type' in kwargs: + options = ['trunk', 'access'] + assert kwargs['type'] in options, f'''"type" cannot be "{kwargs['type']}", & must be set to one of: {options}''' + if 'stpGuard' in kwargs: + options = ['disabled', 'root guard', 'bpdu guard', 'loop guard'] + assert kwargs['stpGuard'] in options, f'''"stpGuard" cannot be "{kwargs['stpGuard']}", & must be set to one of: {options}''' + if 'udld' in kwargs: + options = ['Alert only', 'Enforce'] + assert kwargs['udld'] in options, f'''"udld" cannot be "{kwargs['udld']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Switch ports'], + 'operation': 'updateDeviceSwitchPort', + } + resource = f'/devices/{serial}/switchPorts/{number}' + + body_params = ['name', 'tags', 'enabled', 'type', 'vlan', 'voiceVlan', 'allowedVlans', 'poeEnabled', 'isolationEnabled', 'rstpEnabled', 'stpGuard', 'accessPolicyNumber', 'linkNegotiation', 'portScheduleId', 'udld', 'macWhitelist', 'stickyMacWhitelist', 'stickyMacWhitelistLimit', 'stormControlEnabled'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/switch_profiles.py b/meraki/aio/api/switch_profiles.py new file mode 100644 index 00000000..77d6d4c0 --- /dev/null +++ b/meraki/aio/api/switch_profiles.py @@ -0,0 +1,22 @@ +class AsyncSwitchProfiles: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationConfigTemplateSwitchProfiles(self, organizationId: str, configTemplateId: str): + """ + **List the switch profiles for your switch template configuration** + https://api.meraki.com/api_docs#list-the-switch-profiles-for-your-switch-template-configuration + + - organizationId (string) + - configTemplateId (string) + """ + + metadata = { + 'tags': ['Switch profiles'], + 'operation': 'getOrganizationConfigTemplateSwitchProfiles', + } + resource = f'/organizations/{organizationId}/configTemplates/{configTemplateId}/switchProfiles' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/switch_settings.py b/meraki/aio/api/switch_settings.py new file mode 100644 index 00000000..c773a551 --- /dev/null +++ b/meraki/aio/api/switch_settings.py @@ -0,0 +1,437 @@ +class AsyncSwitchSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSwitchSettings(self, networkId: str): + """ + **Returns the switch network settings** + https://api.meraki.com/api_docs#returns-the-switch-network-settings + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettings', + } + resource = f'/networks/{networkId}/switch/settings' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettings(self, networkId: str, **kwargs): + """ + **Update switch network settings** + https://api.meraki.com/api_docs#update-switch-network-settings + + - networkId (string) + - vlan (integer): Management VLAN + - useCombinedPower (boolean): The use Combined Power as the default behavior of secondary power supplies on supported devices. + - powerExceptions (array): Exceptions on a per switch basis to "useCombinedPower" + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettings', + } + resource = f'/networks/{networkId}/switch/settings' + + body_params = ['vlan', 'useCombinedPower', 'powerExceptions'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsDhcpServerPolicy(self, networkId: str): + """ + **Return the DHCP server policy** + https://api.meraki.com/api_docs#return-the-dhcp-server-policy + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsDhcpServerPolicy', + } + resource = f'/networks/{networkId}/switch/settings/dhcpServerPolicy' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsDhcpServerPolicy(self, networkId: str, **kwargs): + """ + **Update the DHCP server policy** + https://api.meraki.com/api_docs#update-the-dhcp-server-policy + + - networkId (string) + - defaultPolicy (string): 'allow' or 'block' new DHCP servers. Default value is 'allow'. + - allowedServers (array): List the MAC addresses of DHCP servers to permit on the network. Applicable only if defaultPolicy is set to block. An empty array will clear the entries. + - blockedServers (array): List the MAC addresses of DHCP servers to block on the network. Applicable only if defaultPolicy is set to allow. An empty array will clear the entries. + """ + + kwargs.update(locals()) + + if 'defaultPolicy' in kwargs: + options = ['allow', 'block'] + assert kwargs['defaultPolicy'] in options, f'''"defaultPolicy" cannot be "{kwargs['defaultPolicy']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsDhcpServerPolicy', + } + resource = f'/networks/{networkId}/switch/settings/dhcpServerPolicy' + + body_params = ['defaultPolicy', 'allowedServers', 'blockedServers'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsDscpToCosMappings(self, networkId: str): + """ + **Return the DSCP to CoS mappings** + https://api.meraki.com/api_docs#return-the-dscp-to-cos-mappings + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsDscpToCosMappings', + } + resource = f'/networks/{networkId}/switch/settings/dscpToCosMappings' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsDscpToCosMappings(self, networkId: str, mappings: list): + """ + **Update the DSCP to CoS mappings** + https://api.meraki.com/api_docs#update-the-dscp-to-cos-mappings + + - networkId (string) + - mappings (array): An array of DSCP to CoS mappings. An empty array will reset the mappings to default. + """ + + kwargs = locals() + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsDscpToCosMappings', + } + resource = f'/networks/{networkId}/switch/settings/dscpToCosMappings' + + body_params = ['mappings'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsMtu(self, networkId: str): + """ + **Return the MTU configuration** + https://api.meraki.com/api_docs#return-the-mtu-configuration + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsMtu', + } + resource = f'/networks/{networkId}/switch/settings/mtu' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsMtu(self, networkId: str, **kwargs): + """ + **Update the MTU configuration** + https://api.meraki.com/api_docs#update-the-mtu-configuration + + - networkId (string) + - defaultMtuSize (integer): MTU size for the entire network. Default value is 9578. + - overrides (array): Override MTU size for individual switches or switch profiles. An empty array will clear overrides. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsMtu', + } + resource = f'/networks/{networkId}/switch/settings/mtu' + + body_params = ['defaultMtuSize', 'overrides'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsMulticast(self, networkId: str): + """ + **Return multicast settings for a network** + https://api.meraki.com/api_docs#return-multicast-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsMulticast', + } + resource = f'/networks/{networkId}/switch/settings/multicast' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsMulticast(self, networkId: str, **kwargs): + """ + **Update multicast settings for a network** + https://api.meraki.com/api_docs#update-multicast-settings-for-a-network + + - networkId (string) + - defaultSettings (object): Default multicast setting for entire network. IGMP snooping and Flood unknown multicast traffic settings are enabled by default. + - overrides (array): Array of paired switches/stacks/profiles and corresponding multicast settings. An empty array will clear the multicast settings. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsMulticast', + } + resource = f'/networks/{networkId}/switch/settings/multicast' + + body_params = ['defaultSettings', 'overrides'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsQosRules(self, networkId: str): + """ + **List quality of service rules** + https://api.meraki.com/api_docs#list-quality-of-service-rules + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsQosRules', + } + resource = f'/networks/{networkId}/switch/settings/qosRules' + + return await self._session.get(metadata, resource) + + async def createNetworkSwitchSettingsQosRule(self, networkId: str, vlan: int, **kwargs): + """ + **Add a quality of service rule** + https://api.meraki.com/api_docs#add-a-quality-of-service-rule + + - networkId (string) + - vlan (integer): The VLAN of the incoming packet. A null value will match any VLAN. + - protocol (string): The protocol of the incoming packet. Can be one of "ANY", "TCP" or "UDP". Default value is "ANY" + - srcPort (integer): The source port of the incoming packet. Applicable only if protocol is TCP or UDP. + - srcPortRange (string): The source port range of the incoming packet. Applicable only if protocol is set to TCP or UDP. Example: 70-80 + - dstPort (integer): The destination port of the incoming packet. Applicable only if protocol is TCP or UDP. + - dstPortRange (string): The destination port range of the incoming packet. Applicable only if protocol is set to TCP or UDP. Example: 70-80 + - dscp (integer): DSCP tag. Set this to -1 to trust incoming DSCP. Default value is 0 + """ + + kwargs.update(locals()) + + if 'protocol' in kwargs: + options = ['ANY', 'TCP', 'UDP'] + assert kwargs['protocol'] in options, f'''"protocol" cannot be "{kwargs['protocol']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'createNetworkSwitchSettingsQosRule', + } + resource = f'/networks/{networkId}/switch/settings/qosRules' + + body_params = ['vlan', 'protocol', 'srcPort', 'srcPortRange', 'dstPort', 'dstPortRange', 'dscp'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkSwitchSettingsQosRulesOrder(self, networkId: str): + """ + **Return the quality of service rule IDs by order in which they will be processed by the switch** + https://api.meraki.com/api_docs#return-the-quality-of-service-rule-ids-by-order-in-which-they-will-be-processed-by-the-switch + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsQosRulesOrder', + } + resource = f'/networks/{networkId}/switch/settings/qosRules/order' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsQosRulesOrder(self, networkId: str, ruleIds: list): + """ + **Update the order in which the rules should be processed by the switch** + https://api.meraki.com/api_docs#update-the-order-in-which-the-rules-should-be-processed-by-the-switch + + - networkId (string) + - ruleIds (array): A list of quality of service rule IDs arranged in order in which they should be processed by the switch. + """ + + kwargs = locals() + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsQosRulesOrder', + } + resource = f'/networks/{networkId}/switch/settings/qosRules/order' + + body_params = ['ruleIds'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsQosRule(self, networkId: str, qosRuleId: str): + """ + **Return a quality of service rule** + https://api.meraki.com/api_docs#return-a-quality-of-service-rule + + - networkId (string) + - qosRuleId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsQosRule', + } + resource = f'/networks/{networkId}/switch/settings/qosRules/{qosRuleId}' + + return await self._session.get(metadata, resource) + + async def deleteNetworkSwitchSettingsQosRule(self, networkId: str, qosRuleId: str): + """ + **Delete a quality of service rule** + https://api.meraki.com/api_docs#delete-a-quality-of-service-rule + + - networkId (string) + - qosRuleId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'deleteNetworkSwitchSettingsQosRule', + } + resource = f'/networks/{networkId}/switch/settings/qosRules/{qosRuleId}' + + return await self._session.delete(metadata, resource) + + async def updateNetworkSwitchSettingsQosRule(self, networkId: str, qosRuleId: str, **kwargs): + """ + **Update a quality of service rule** + https://api.meraki.com/api_docs#update-a-quality-of-service-rule + + - networkId (string) + - qosRuleId (string) + - vlan (integer): The VLAN of the incoming packet. A null value will match any VLAN. + - protocol (string): The protocol of the incoming packet. Can be one of "ANY", "TCP" or "UDP". Default value is "ANY". + - srcPort (integer): The source port of the incoming packet. Applicable only if protocol is TCP or UDP. + - srcPortRange (string): The source port range of the incoming packet. Applicable only if protocol is set to TCP or UDP. Example: 70-80 + - dstPort (integer): The destination port of the incoming packet. Applicable only if protocol is TCP or UDP. + - dstPortRange (string): The destination port range of the incoming packet. Applicable only if protocol is set to TCP or UDP. Example: 70-80 + - dscp (integer): DSCP tag that should be assigned to incoming packet. Set this to -1 to trust incoming DSCP. Default value is 0. + """ + + kwargs.update(locals()) + + if 'protocol' in kwargs: + options = ['ANY', 'TCP', 'UDP'] + assert kwargs['protocol'] in options, f'''"protocol" cannot be "{kwargs['protocol']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsQosRule', + } + resource = f'/networks/{networkId}/switch/settings/qosRules/{qosRuleId}' + + body_params = ['vlan', 'protocol', 'srcPort', 'srcPortRange', 'dstPort', 'dstPortRange', 'dscp'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsStormControl(self, networkId: str): + """ + **Return the storm control configuration for a switch network** + https://api.meraki.com/api_docs#return-the-storm-control-configuration-for-a-switch-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsStormControl', + } + resource = f'/networks/{networkId}/switch/settings/stormControl' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsStormControl(self, networkId: str, **kwargs): + """ + **Update the storm control configuration for a switch network** + https://api.meraki.com/api_docs#update-the-storm-control-configuration-for-a-switch-network + + - networkId (string) + - broadcastThreshold (integer): Percentage (1 to 99) of total available port bandwidth for broadcast traffic type. Default value 100 percent rate is to clear the configuration. + - multicastThreshold (integer): Percentage (1 to 99) of total available port bandwidth for multicast traffic type. Default value 100 percent rate is to clear the configuration. + - unknownUnicastThreshold (integer): Percentage (1 to 99) of total available port bandwidth for unknown unicast (dlf-destination lookup failure) traffic type. Default value 100 percent rate is to clear the configuration. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsStormControl', + } + resource = f'/networks/{networkId}/switch/settings/stormControl' + + body_params = ['broadcastThreshold', 'multicastThreshold', 'unknownUnicastThreshold'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSwitchSettingsStp(self, networkId: str): + """ + **Returns STP settings** + https://api.meraki.com/api_docs#returns-stp-settings + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsStp', + } + resource = f'/networks/{networkId}/switch/settings/stp' + + return await self._session.get(metadata, resource) + + async def updateNetworkSwitchSettingsStp(self, networkId: str, **kwargs): + """ + **Updates STP settings** + https://api.meraki.com/api_docs#updates-stp-settings + + - networkId (string) + - rstpEnabled (boolean): The spanning tree protocol status in network + - stpBridgePriority (array): STP bridge priority for switches/stacks or switch profiles. An empty array will clear the STP bridge priority settings. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsStp', + } + resource = f'/networks/{networkId}/switch/settings/stp' + + body_params = ['rstpEnabled', 'stpBridgePriority'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/switch_stacks.py b/meraki/aio/api/switch_stacks.py new file mode 100644 index 00000000..2e0a9950 --- /dev/null +++ b/meraki/aio/api/switch_stacks.py @@ -0,0 +1,124 @@ +class AsyncSwitchStacks: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSwitchStacks(self, networkId: str): + """ + **List the switch stacks in a network** + https://api.meraki.com/api_docs#list-the-switch-stacks-in-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch stacks'], + 'operation': 'getNetworkSwitchStacks', + } + resource = f'/networks/{networkId}/switchStacks' + + return await self._session.get(metadata, resource) + + async def createNetworkSwitchStack(self, networkId: str, name: str, serials: list): + """ + **Create a stack** + https://api.meraki.com/api_docs#create-a-stack + + - networkId (string) + - name (string): The name of the new stack + - serials (array): An array of switch serials to be added into the new stack + """ + + kwargs = locals() + + metadata = { + 'tags': ['Switch stacks'], + 'operation': 'createNetworkSwitchStack', + } + resource = f'/networks/{networkId}/switchStacks' + + body_params = ['name', 'serials'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkSwitchStack(self, networkId: str, switchStackId: str): + """ + **Show a switch stack** + https://api.meraki.com/api_docs#show-a-switch-stack + + - networkId (string) + - switchStackId (string) + """ + + metadata = { + 'tags': ['Switch stacks'], + 'operation': 'getNetworkSwitchStack', + } + resource = f'/networks/{networkId}/switchStacks/{switchStackId}' + + return await self._session.get(metadata, resource) + + async def deleteNetworkSwitchStack(self, networkId: str, switchStackId: str): + """ + **Delete a stack** + https://api.meraki.com/api_docs#delete-a-stack + + - networkId (string) + - switchStackId (string) + """ + + metadata = { + 'tags': ['Switch stacks'], + 'operation': 'deleteNetworkSwitchStack', + } + resource = f'/networks/{networkId}/switchStacks/{switchStackId}' + + return await self._session.delete(metadata, resource) + + async def addNetworkSwitchStack(self, networkId: str, switchStackId: str, serial: str): + """ + **Add a switch to a stack** + https://api.meraki.com/api_docs#add-a-switch-to-a-stack + + - networkId (string) + - switchStackId (string) + - serial (string): The serial of the switch to be added + """ + + kwargs = locals() + + metadata = { + 'tags': ['Switch stacks'], + 'operation': 'addNetworkSwitchStack', + } + resource = f'/networks/{networkId}/switchStacks/{switchStackId}/add' + + body_params = ['serial'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def removeNetworkSwitchStack(self, networkId: str, switchStackId: str, serial: str): + """ + **Remove a switch from a stack** + https://api.meraki.com/api_docs#remove-a-switch-from-a-stack + + - networkId (string) + - switchStackId (string) + - serial (string): The serial of the switch to be removed + """ + + kwargs = locals() + + metadata = { + 'tags': ['Switch stacks'], + 'operation': 'removeNetworkSwitchStack', + } + resource = f'/networks/{networkId}/switchStacks/{switchStackId}/remove' + + body_params = ['serial'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + diff --git a/meraki/aio/api/syslog_servers.py b/meraki/aio/api/syslog_servers.py new file mode 100644 index 00000000..14d55409 --- /dev/null +++ b/meraki/aio/api/syslog_servers.py @@ -0,0 +1,43 @@ +class AsyncSyslogServers: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkSyslogServers(self, networkId: str): + """ + **List the syslog servers for a network** + https://api.meraki.com/api_docs#list-the-syslog-servers-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Syslog servers'], + 'operation': 'getNetworkSyslogServers', + } + resource = f'/networks/{networkId}/syslogServers' + + return await self._session.get(metadata, resource) + + async def updateNetworkSyslogServers(self, networkId: str, servers: list): + """ + **Update the syslog servers for a network** + https://api.meraki.com/api_docs#update-the-syslog-servers-for-a-network + + - networkId (string) + - servers (array): A list of the syslog servers for this network + """ + + kwargs = locals() + + metadata = { + 'tags': ['Syslog servers'], + 'operation': 'updateNetworkSyslogServers', + } + resource = f'/networks/{networkId}/syslogServers' + + body_params = ['servers'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/traffic_analysis_settings.py b/meraki/aio/api/traffic_analysis_settings.py new file mode 100644 index 00000000..a4982d3a --- /dev/null +++ b/meraki/aio/api/traffic_analysis_settings.py @@ -0,0 +1,50 @@ +class AsyncTrafficAnalysisSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkTrafficAnalysisSettings(self, networkId: str): + """ + **Return the traffic analysis settings for a network** + https://api.meraki.com/api_docs#return-the-traffic-analysis-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Traffic analysis settings'], + 'operation': 'getNetworkTrafficAnalysisSettings', + } + resource = f'/networks/{networkId}/trafficAnalysisSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkTrafficAnalysisSettings(self, networkId: str, **kwargs): + """ + **Update the traffic analysis settings for a network** + https://api.meraki.com/api_docs#update-the-traffic-analysis-settings-for-a-network + + - networkId (string) + - mode (string): The traffic analysis mode for the network. Can be one of 'disabled' (do not collect traffic types), + 'basic' (collect generic traffic categories), or 'detailed' (collect destination hostnames). + + - customPieChartItems (array): The list of items that make up the custom pie chart for traffic reporting. + """ + + kwargs.update(locals()) + + if 'mode' in kwargs: + options = ['disabled', 'basic', 'detailed'] + assert kwargs['mode'] in options, f'''"mode" cannot be "{kwargs['mode']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Traffic analysis settings'], + 'operation': 'updateNetworkTrafficAnalysisSettings', + } + resource = f'/networks/{networkId}/trafficAnalysisSettings' + + body_params = ['mode', 'customPieChartItems'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/traffic_shaping.py b/meraki/aio/api/traffic_shaping.py new file mode 100644 index 00000000..1e981cb6 --- /dev/null +++ b/meraki/aio/api/traffic_shaping.py @@ -0,0 +1,132 @@ +class AsyncTrafficShaping: + def __init__(self, session): + super().__init__() + self._session = session + + async def updateNetworkSsidTrafficShaping(self, networkId: str, number: str, **kwargs): + """ + **Update the traffic shaping settings for an SSID on an MR network** + https://api.meraki.com/api_docs#update-the-traffic-shaping-settings-for-an-ssid-on-an-mr-network + + - networkId (string) + - number (string) + - trafficShapingEnabled (boolean): Whether traffic shaping rules are applied to clients on your SSID. + - defaultRulesEnabled (boolean): Whether default traffic shaping rules are enabled (true) or disabled (false). + There are 4 default rules, which can + be seen on your network's traffic shaping page. Note that default rules + count against the rule limit of 8. + + - rules (array): An array of traffic shaping rules. Rules are applied in the order that + they are specified in. An empty list (or null) means no rules. Note that + you are allowed a maximum of 8 rules. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Traffic shaping'], + 'operation': 'updateNetworkSsidTrafficShaping', + } + resource = f'/networks/{networkId}/ssids/{number}/trafficShaping' + + body_params = ['trafficShapingEnabled', 'defaultRulesEnabled', 'rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkSsidTrafficShaping(self, networkId: str, number: str): + """ + **Display the traffic shaping settings for a SSID on an MR network** + https://api.meraki.com/api_docs#display-the-traffic-shaping-settings-for-a-ssid-on-an-mr-network + + - networkId (string) + - number (string) + """ + + metadata = { + 'tags': ['Traffic shaping'], + 'operation': 'getNetworkSsidTrafficShaping', + } + resource = f'/networks/{networkId}/ssids/{number}/trafficShaping' + + return await self._session.get(metadata, resource) + + async def updateNetworkTrafficShaping(self, networkId: str, **kwargs): + """ + **Update the traffic shaping settings for an MX network** + https://api.meraki.com/api_docs#update-the-traffic-shaping-settings-for-an-mx-network + + - networkId (string) + - defaultRulesEnabled (boolean): Whether default traffic shaping rules are enabled (true) or disabled (false). + There are 4 default rules, which can + be seen on your network's traffic shaping page. Note that default rules + count against the rule limit of 8. + + - rules (array): An array of traffic shaping rules. Rules are applied in the order that + they are specified in. An empty list (or null) means no rules. Note that + you are allowed a maximum of 8 rules. + + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Traffic shaping'], + 'operation': 'updateNetworkTrafficShaping', + } + resource = f'/networks/{networkId}/trafficShaping' + + body_params = ['defaultRulesEnabled', 'rules'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def getNetworkTrafficShaping(self, networkId: str): + """ + **Display the traffic shaping settings for an MX network** + https://api.meraki.com/api_docs#display-the-traffic-shaping-settings-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Traffic shaping'], + 'operation': 'getNetworkTrafficShaping', + } + resource = f'/networks/{networkId}/trafficShaping' + + return await self._session.get(metadata, resource) + + async def getNetworkTrafficShapingApplicationCategories(self, networkId: str): + """ + **Returns the application categories for traffic shaping rules.** + https://api.meraki.com/api_docs#returns-the-application-categories-for-traffic-shaping-rules + + - networkId (string) + """ + + metadata = { + 'tags': ['Traffic shaping'], + 'operation': 'getNetworkTrafficShapingApplicationCategories', + } + resource = f'/networks/{networkId}/trafficShaping/applicationCategories' + + return await self._session.get(metadata, resource) + + async def getNetworkTrafficShapingDscpTaggingOptions(self, networkId: str): + """ + **Returns the available DSCP tagging options for your traffic shaping rules.** + https://api.meraki.com/api_docs#returns-the-available-dscp-tagging-options-for-your-traffic-shaping-rules + + - networkId (string) + """ + + metadata = { + 'tags': ['Traffic shaping'], + 'operation': 'getNetworkTrafficShapingDscpTaggingOptions', + } + resource = f'/networks/{networkId}/trafficShaping/dscpTaggingOptions' + + return await self._session.get(metadata, resource) + diff --git a/meraki/aio/api/uplink_settings.py b/meraki/aio/api/uplink_settings.py new file mode 100644 index 00000000..2b23a1d9 --- /dev/null +++ b/meraki/aio/api/uplink_settings.py @@ -0,0 +1,43 @@ +class AsyncUplinkSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkUplinkSettings(self, networkId: str): + """ + **Returns the uplink settings for your MX network.** + https://api.meraki.com/api_docs#returns-the-uplink-settings-for-your-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Uplink settings'], + 'operation': 'getNetworkUplinkSettings', + } + resource = f'/networks/{networkId}/uplinkSettings' + + return await self._session.get(metadata, resource) + + async def updateNetworkUplinkSettings(self, networkId: str, **kwargs): + """ + **Updates the uplink settings for your MX network.** + https://api.meraki.com/api_docs#updates-the-uplink-settings-for-your-mx-network + + - networkId (string) + - bandwidthLimits (object): A mapping of uplinks to their bandwidth settings (be sure to check which uplinks are supported for your network) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Uplink settings'], + 'operation': 'updateNetworkUplinkSettings', + } + resource = f'/networks/{networkId}/uplinkSettings' + + body_params = ['bandwidthLimits'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/vlans.py b/meraki/aio/api/vlans.py new file mode 100644 index 00000000..fddcec2e --- /dev/null +++ b/meraki/aio/api/vlans.py @@ -0,0 +1,161 @@ +class AsyncVLANs: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkVlans(self, networkId: str): + """ + **List the VLANs for an MX network** + https://api.meraki.com/api_docs#list-the-vlans-for-an-mx-network + + - networkId (string) + """ + + metadata = { + 'tags': ['VLANs'], + 'operation': 'getNetworkVlans', + } + resource = f'/networks/{networkId}/vlans' + + return await self._session.get(metadata, resource) + + async def createNetworkVlan(self, networkId: str, id: str, name: str, subnet: str, applianceIp: str): + """ + **Add a VLAN** + https://api.meraki.com/api_docs#add-a-vlan + + - networkId (string) + - id (string): The VLAN ID of the new VLAN (must be between 1 and 4094) + - name (string): The name of the new VLAN + - subnet (string): The subnet of the VLAN + - applianceIp (string): The local IP of the appliance on the VLAN + """ + + kwargs = locals() + + metadata = { + 'tags': ['VLANs'], + 'operation': 'createNetworkVlan', + } + resource = f'/networks/{networkId}/vlans' + + body_params = ['id', 'name', 'subnet', 'applianceIp'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.post(metadata, resource, payload) + + async def getNetworkVlan(self, networkId: str, vlanId: str): + """ + **Return a VLAN** + https://api.meraki.com/api_docs#return-a-vlan + + - networkId (string) + - vlanId (string) + """ + + metadata = { + 'tags': ['VLANs'], + 'operation': 'getNetworkVlan', + } + resource = f'/networks/{networkId}/vlans/{vlanId}' + + return await self._session.get(metadata, resource) + + async def updateNetworkVlan(self, networkId: str, vlanId: str, **kwargs): + """ + **Update a VLAN** + https://api.meraki.com/api_docs#update-a-vlan + + - networkId (string) + - vlanId (string) + - name (string): The name of the VLAN + - subnet (string): The subnet of the VLAN + - applianceIp (string): The local IP of the appliance on the VLAN + - vpnNatSubnet (string): The translated VPN subnet if VPN and VPN subnet translation are enabled on the VLAN + - dhcpHandling (string): The appliance's handling of DHCP requests on this VLAN. One of: 'Run a DHCP server', 'Relay DHCP to another server' or 'Do not respond to DHCP requests' + - dhcpRelayServerIps (array): The IPs of the DHCP servers that DHCP requests should be relayed to + - dhcpLeaseTime (string): The term of DHCP leases if the appliance is running a DHCP server on this VLAN. One of: '30 minutes', '1 hour', '4 hours', '12 hours', '1 day' or '1 week' + - dhcpBootOptionsEnabled (boolean): Use DHCP boot options specified in other properties + - dhcpBootNextServer (string): DHCP boot option to direct boot clients to the server to load the boot file from + - dhcpBootFilename (string): DHCP boot option for boot filename + - fixedIpAssignments (object): The DHCP fixed IP assignments on the VLAN. This should be an object that contains mappings from MAC addresses to objects that themselves each contain "ip" and "name" string fields. See the sample request/response for more details. + - reservedIpRanges (array): The DHCP reserved IP ranges on the VLAN + - dnsNameservers (string): The DNS nameservers used for DHCP responses, either "upstream_dns", "google_dns", "opendns", or a newline seperated string of IP addresses or domain names + - 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. + """ + + kwargs.update(locals()) + + if 'dhcpHandling' in kwargs: + options = ['Run a DHCP server', 'Relay DHCP to another server', 'Do not respond to DHCP requests'] + assert kwargs['dhcpHandling'] in options, f'''"dhcpHandling" cannot be "{kwargs['dhcpHandling']}", & must be set to one of: {options}''' + if 'dhcpLeaseTime' in kwargs: + options = ['30 minutes', '1 hour', '4 hours', '12 hours', '1 day', '1 week'] + assert kwargs['dhcpLeaseTime'] in options, f'''"dhcpLeaseTime" cannot be "{kwargs['dhcpLeaseTime']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['VLANs'], + 'operation': 'updateNetworkVlan', + } + resource = f'/networks/{networkId}/vlans/{vlanId}' + + body_params = ['name', 'subnet', 'applianceIp', 'vpnNatSubnet', 'dhcpHandling', 'dhcpRelayServerIps', 'dhcpLeaseTime', 'dhcpBootOptionsEnabled', 'dhcpBootNextServer', 'dhcpBootFilename', 'fixedIpAssignments', 'reservedIpRanges', 'dnsNameservers', 'dhcpOptions'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + + async def deleteNetworkVlan(self, networkId: str, vlanId: str): + """ + **Delete a VLAN from a network** + https://api.meraki.com/api_docs#delete-a-vlan-from-a-network + + - networkId (string) + - vlanId (string) + """ + + metadata = { + 'tags': ['VLANs'], + 'operation': 'deleteNetworkVlan', + } + resource = f'/networks/{networkId}/vlans/{vlanId}' + + return await self._session.delete(metadata, resource) + + async def getNetworkVlansEnabledState(self, networkId: str): + """ + **Returns the enabled status of VLANs for the network** + https://api.meraki.com/api_docs#returns-the-enabled-status-of-vlans-for-the-network + + - networkId (string) + """ + + metadata = { + 'tags': ['VLANs'], + 'operation': 'getNetworkVlansEnabledState', + } + resource = f'/networks/{networkId}/vlansEnabledState' + + return await self._session.get(metadata, resource) + + async def updateNetworkVlansEnabledState(self, networkId: str, enabled: bool): + """ + **Enable/Disable VLANs for the given network** + https://api.meraki.com/api_docs#enable/disable-vlans-for-the-given-network + + - networkId (string) + - enabled (boolean): Boolean indicating whether to enable (true) or disable (false) VLANs for the network + """ + + kwargs = locals() + + metadata = { + 'tags': ['VLANs'], + 'operation': 'updateNetworkVlansEnabledState', + } + resource = f'/networks/{networkId}/vlansEnabledState' + + body_params = ['enabled'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/api/webhook_logs.py b/meraki/aio/api/webhook_logs.py new file mode 100644 index 00000000..d466ccc0 --- /dev/null +++ b/meraki/aio/api/webhook_logs.py @@ -0,0 +1,36 @@ +class AsyncWebhookLogs: + def __init__(self, session): + super().__init__() + self._session = session + + async def getOrganizationWebhookLogs(self, organizationId: str, total_pages=1, direction='next', **kwargs): + """ + **Return the log of webhook POSTs sent** + https://api.meraki.com/api_docs#return-the-log-of-webhook-posts-sent + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -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 90 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 50. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - url (string): The URL the webhook was sent to + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Webhook logs'], + 'operation': 'getOrganizationWebhookLogs', + } + resource = f'/organizations/{organizationId}/webhookLogs' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore', 'url'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get_pages(metadata, resource, params, total_pages, direction) + + diff --git a/meraki/aio/api/wireless_health.py b/meraki/aio/api/wireless_health.py new file mode 100644 index 00000000..ee524d9f --- /dev/null +++ b/meraki/aio/api/wireless_health.py @@ -0,0 +1,313 @@ +class AsyncWirelessHealth: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkClientsConnectionStats(self, networkId: str, **kwargs): + """ + **Aggregated connectivity info for this network, grouped by clients** + https://api.meraki.com/api_docs#aggregated-connectivity-info-for-this-network-grouped-by-clients + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkClientsConnectionStats', + } + resource = f'/networks/{networkId}/clients/connectionStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkClientsLatencyStats(self, networkId: str, **kwargs): + """ + **Aggregated latency info for this network, grouped by clients** + https://api.meraki.com/api_docs#aggregated-latency-info-for-this-network-grouped-by-clients + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + - fields (string): Partial selection: If present, this call will return only the selected fields of ["rawDistribution", "avg"]. All fields will be returned by default. Selected fields must be entered as a comma separated string. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkClientsLatencyStats', + } + resource = f'/networks/{networkId}/clients/latencyStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag', 'fields'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkClientConnectionStats(self, networkId: str, clientId: str, **kwargs): + """ + **Aggregated connectivity info for a given client on this network. Clients are identified by their MAC.** + https://api.meraki.com/api_docs#aggregated-connectivity-info-for-a-given-client-on-this-network + + - networkId (string) + - clientId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkClientConnectionStats', + } + resource = f'/networks/{networkId}/clients/{clientId}/connectionStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkClientLatencyStats(self, networkId: str, clientId: str, **kwargs): + """ + **Aggregated latency info for a given client on this network. Clients are identified by their MAC.** + https://api.meraki.com/api_docs#aggregated-latency-info-for-a-given-client-on-this-network + + - networkId (string) + - clientId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + - fields (string): Partial selection: If present, this call will return only the selected fields of ["rawDistribution", "avg"]. All fields will be returned by default. Selected fields must be entered as a comma separated string. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkClientLatencyStats', + } + resource = f'/networks/{networkId}/clients/{clientId}/latencyStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag', 'fields'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkConnectionStats(self, networkId: str, **kwargs): + """ + **Aggregated connectivity info for this network** + https://api.meraki.com/api_docs#aggregated-connectivity-info-for-this-network + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkConnectionStats', + } + resource = f'/networks/{networkId}/connectionStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkDevicesConnectionStats(self, networkId: str, **kwargs): + """ + **Aggregated connectivity info for this network, grouped by node** + https://api.meraki.com/api_docs#aggregated-connectivity-info-for-this-network-grouped-by-node + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkDevicesConnectionStats', + } + resource = f'/networks/{networkId}/devices/connectionStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkDevicesLatencyStats(self, networkId: str, **kwargs): + """ + **Aggregated latency info for this network, grouped by node** + https://api.meraki.com/api_docs#aggregated-latency-info-for-this-network-grouped-by-node + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + - fields (string): Partial selection: If present, this call will return only the selected fields of ["rawDistribution", "avg"]. All fields will be returned by default. Selected fields must be entered as a comma separated string. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkDevicesLatencyStats', + } + resource = f'/networks/{networkId}/devices/latencyStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag', 'fields'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkDeviceConnectionStats(self, networkId: str, serial: str, **kwargs): + """ + **Aggregated connectivity info for a given AP on this network** + https://api.meraki.com/api_docs#aggregated-connectivity-info-for-a-given-ap-on-this-network + + - networkId (string) + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkDeviceConnectionStats', + } + resource = f'/networks/{networkId}/devices/{serial}/connectionStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkDeviceLatencyStats(self, networkId: str, serial: str, **kwargs): + """ + **Aggregated latency info for a given AP on this network** + https://api.meraki.com/api_docs#aggregated-latency-info-for-a-given-ap-on-this-network + + - networkId (string) + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + - fields (string): Partial selection: If present, this call will return only the selected fields of ["rawDistribution", "avg"]. All fields will be returned by default. Selected fields must be entered as a comma separated string. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkDeviceLatencyStats', + } + resource = f'/networks/{networkId}/devices/{serial}/latencyStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag', 'fields'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkFailedConnections(self, networkId: str, **kwargs): + """ + **List of all failed client connection events on this network in a given time range** + https://api.meraki.com/api_docs#list-of-all-failed-client-connection-events-on-this-network-in-a-given-time-range + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + - serial (string): Filter by AP + - clientId (string): Filter by client MAC + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkFailedConnections', + } + resource = f'/networks/{networkId}/failedConnections' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag', 'serial', 'clientId'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + + async def getNetworkLatencyStats(self, networkId: str, **kwargs): + """ + **Aggregated latency info for this network** + https://api.meraki.com/api_docs#aggregated-latency-info-for-this-network + + - networkId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 180 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 7 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 7 days. + - ssid (integer): Filter results by SSID + - vlan (integer): Filter results by VLAN + - apTag (string): Filter results by AP Tag + - fields (string): Partial selection: If present, this call will return only the selected fields of ["rawDistribution", "avg"]. All fields will be returned by default. Selected fields must be entered as a comma separated string. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless health'], + 'operation': 'getNetworkLatencyStats', + } + resource = f'/networks/{networkId}/latencyStats' + + query_params = ['t0', 't1', 'timespan', 'ssid', 'vlan', 'apTag', 'fields'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return await self._session.get(metadata, resource, params) + diff --git a/meraki/aio/api/wireless_settings.py b/meraki/aio/api/wireless_settings.py new file mode 100644 index 00000000..73b1330d --- /dev/null +++ b/meraki/aio/api/wireless_settings.py @@ -0,0 +1,46 @@ +class AsyncWirelessSettings: + def __init__(self, session): + super().__init__() + self._session = session + + async def getNetworkWirelessSettings(self, networkId: str): + """ + **Return the wireless settings for a network** + https://api.meraki.com/api_docs#return-the-wireless-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Wireless settings'], + 'operation': 'getNetworkWirelessSettings', + } + resource = f'/networks/{networkId}/wireless/settings' + + return await self._session.get(metadata, resource) + + async def updateNetworkWirelessSettings(self, networkId: str, **kwargs): + """ + **Update the wireless settings for a network** + https://api.meraki.com/api_docs#update-the-wireless-settings-for-a-network + + - networkId (string) + - meshingEnabled (boolean): Toggle for enabling or disabling meshing in a network + - ipv6BridgeEnabled (boolean): Toggle for enabling or disabling IPv6 bridging in a network (Note: if enabled, SSIDs must also be configured to use bridge mode) + - locationAnalyticsEnabled (boolean): Toggle for enabling or disabling location analytics for your network + - ledLightsOn (boolean): Toggle for enabling or disabling LED lights on all APs in the network (making them run dark) + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Wireless settings'], + 'operation': 'updateNetworkWirelessSettings', + } + resource = f'/networks/{networkId}/wireless/settings' + + body_params = ['meshingEnabled', 'ipv6BridgeEnabled', 'locationAnalyticsEnabled', 'ledLightsOn'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return await self._session.put(metadata, resource, payload) + diff --git a/meraki/aio/rest_session.py b/meraki/aio/rest_session.py new file mode 100644 index 00000000..fc31a9e0 --- /dev/null +++ b/meraki/aio/rest_session.py @@ -0,0 +1,241 @@ +import json +import time + +import ssl +import aiohttp +import asyncio + +from meraki.config import * +from meraki.exceptions import * + + +# Main module interface +class AsyncRestSession: + def __init__( + self, + logger, + api_key, + base_url=DEFAULT_BASE_URL, + single_request_timeout=SINGLE_REQUEST_TIMEOUT, + certificate_path=CERTIFICATE_PATH, + wait_on_rate_limit=WAIT_ON_RATE_LIMIT, + maximum_retries=MAXIMUM_RETRIES, + simulate=SIMULATE_API_CALLS, + ): + super().__init__() + + # Initialize attributes and properties + self._api_key = str(api_key) + self._base_url = str(base_url) + self._single_request_timeout = single_request_timeout + self._certificate_path = certificate_path + self._wait_on_rate_limit = wait_on_rate_limit + self._maximum_retries = maximum_retries + self._simulate = simulate + + # Update the headers of the `requests` session + headers = None + if "v0" in self._base_url: + headers = { + "X-Cisco-Meraki-API-Key": self._api_key, + "Content-Type": "application/json", + } + elif "v1" in self._base_url: + headers = { + "Authorization": "Bearer " + self._api_key, + "Content-Type": "application/json", + } + if self._certificate_path: + self._sslcontext = ssl.create_default_context() + self._sslcontext.load_verify_locations(certificate_path) + + # Initialize a new `aiohttp` session + self._req_session = aiohttp.ClientSession( + headers=headers, + timeout=aiohttp.ClientTimeout(total=single_request_timeout), + ) + + # Log API calls + self._logger = logger + self._parameters = locals() + self._parameters["api_key"] = "*" * 36 + self._api_key[-4:] + self._logger.info( + f"Meraki dashboard API session initialized with these parameters: {self._parameters}" + ) + + async def request(self, metadata, method, url, **kwargs): + # Metadata on endpoint + tag = metadata["tags"][0] + operation = metadata["operation"] + + # Update request kwargs with session defaults + if self._certificate_path: + kwargs.setdefault("ssl", self._sslcontext) + kwargs.setdefault("timeout", self._single_request_timeout) + + # Ensure proper base URL + if "meraki.com" in url: + abs_url = url + else: + abs_url = self._base_url + url + + # Set maximum number of retries + retries = self._maximum_retries + + # Option to simulate non-safe API calls without actually sending them + self._logger.debug(metadata) + if self._simulate and method != "GET": + self._logger.info(f"{tag}, {operation} - SIMULATED") + return None + else: + response = None + for _ in range(retries): + # Make the HTTP request to the API endpoint + try: + response = await self._req_session.request( + method, abs_url, **kwargs + ) + reason = response.reason if response.reason else None + status = response.status + except Exception as e: + self._logger.warning( + f"{tag}, {operation} - {e}, retrying in 1 second" + ) + await asyncio.sleep(1) + continue + + if status == 200: + if "page" in metadata: + counter = metadata["page"] + self._logger.info( + f"{tag}, {operation}; page {counter} - {status} {reason}" + ) + else: + self._logger.info(f"{tag}, {operation} - {status} {reason}") + # For non-empty response to GET, ensure valid JSON + try: + if method == "GET": + await response.json() + return response + except ( + json.decoder.JSONDecodeError, + aiohttp.client_exceptions.ContentTypeError, + ) as e: + self._logger.warning( + f"{tag}, {operation} - {e}, retrying in 1 second" + ) + await asyncio.sleep(1) + # Handle 3XX redirects automatically + elif 300 <= status < 400: + abs_url = response.headers["Location"] + substring = "meraki.com/api/v" + self._base_url = abs_url[ + : abs_url.find(substring) + len(substring) + 1 + ] + # Rate limit 429 errors + elif status == 429: + wait = int(response.headers["Retry-After"]) + self._logger.warning( + f"{tag}, {operation} - {status} {reason}, retrying in {wait} seconds" + ) + await asyncio.sleep(wait) + # 5XX errors + elif status >= 500: + self._logger.warning( + f"{tag}, {operation} - {status} {reason}, retrying in 1 second" + ) + await asyncio.sleep(1) + # 4XX errors + else: + try: + message = await response.json() + except aiohttp.client_exceptions.ContentTypeError: + message = (await response.text())[:100] + self._logger.error( + f"{tag}, {operation} - {status} {reason}, {message}" + ) + raise AsyncAPIError(metadata, response, await response.text()) + + async def get(self, metadata, url, params=None): + metadata["method"] = "GET" + metadata["url"] = url + metadata["params"] = params + response = await self.request(metadata, "GET", url, params=params) + return await response.json() + + async def get_pages( + self, metadata, url, params=None, total_pages=-1, direction="next" + ): + if type(total_pages) == str and total_pages.lower() == "all": + total_pages = -1 + metadata["page"] = 1 + + response = await self.request(metadata, "GET", url, params=params) + results = await response.json() + + # Get additional pages if more than one requested + while total_pages != 1: + # Parse Link from headers + links = response.headers["Link"].split(",") + first = prev = next = last = None + for l in links: + if "rel=first" in l: + first = l[l.find("<") + 1 : l.find(">")] + elif "rel=prev" in l: + prev = l[l.find("<") + 1 : l.find(">")] + elif "rel=next" in l: + next = l[l.find("<") + 1 : l.find(">")] + elif "rel=last" in l: + last = l[l.find("<") + 1 : l.find(">")] + + # GET the subsequent page + if direction == "next" and next: + metadata["page"] += 1 + response = await self.request(metadata, "GET", next) + elif direction == "prev" and prev: + metadata["page"] += 1 + response = await self.request(metadata, "GET", prev) + else: + break + + # Append that page's results, depending on the endpoint + if type(results) == list: + results.extend(await response.json()) + # For event log endpoint + elif type(results) == dict: + json_response = await response.json() + start = json_response["pageStartAt"] + end = json_response["pageEndAt"] + events = json_response["events"] + if start < results["pageStartAt"]: + results["pageStartAt"] = start + if end > results["pageEndAt"]: + results["pageEndAt"] = end + results["events"].extend(events) + + total_pages -= 1 + + return results + + async def post(self, metadata, url, json=None): + metadata["method"] = "POST" + metadata["url"] = url + metadata["json"] = json + response = await self.request(metadata, "POST", url, json=json) + return await response.json() + + async def put(self, metadata, url, json=None): + metadata["method"] = "PUT" + metadata["url"] = url + metadata["json"] = json + response = await self.request(metadata, "PUT", url, json=json) + return await response.json() + + async def delete(self, metadata, url): + metadata["method"] = "DELETE" + metadata["url"] = url + await self.request(metadata, "DELETE", url) + return None + + async def close(self): + await self._req_session.close() diff --git a/meraki/api/api_usage.py b/meraki/api/api_usage.py index be5d33ed..a52335ad 100644 --- a/meraki/api/api_usage.py +++ b/meraki/api/api_usage.py @@ -38,3 +38,27 @@ def getOrganizationApiRequests(self, organizationId: str, total_pages=1, directi return self._session.get_pages(metadata, resource, params, total_pages, direction) + def getOrganizationApiRequestsOverview(self, organizationId: str, **kwargs): + """ + **Return an aggregated overview of API requests data** + https://api.meraki.com/api_docs#return-an-aggregated-overview-of-api-requests-data + + - organizationId (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 31 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 31 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 31 days. The default is 31 days. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['API usage'], + 'operation': 'getOrganizationApiRequestsOverview', + } + resource = f'/organizations/{organizationId}/apiRequests/overview' + + query_params = ['t0', 't1', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return self._session.get(metadata, resource, params) + diff --git a/meraki/api/bluetooth_settings.py b/meraki/api/bluetooth_settings.py new file mode 100644 index 00000000..e8de19b4 --- /dev/null +++ b/meraki/api/bluetooth_settings.py @@ -0,0 +1,92 @@ +class BluetoothSettings(object): + def __init__(self, session): + super(BluetoothSettings, self).__init__() + self._session = session + + def getDeviceWirelessBluetoothSettings(self, serial: str): + """ + **Return the bluetooth settings for a wireless device** + https://api.meraki.com/api_docs#return-the-bluetooth-settings-for-a-wireless-device + + - serial (string) + """ + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'getDeviceWirelessBluetoothSettings', + } + resource = f'/devices/{serial}/wireless/bluetooth/settings' + + return self._session.get(metadata, resource) + + def updateDeviceWirelessBluetoothSettings(self, serial: str, **kwargs): + """ + **Update the bluetooth settings for a wireless device** + https://api.meraki.com/api_docs#update-the-bluetooth-settings-for-a-wireless-device + + - serial (string) + - uuid (string): Desired UUID of the beacon. If the value is set to null it will reset to Dashboard's automatically generated value. + - major (integer): Desired major value of the beacon. If the value is set to null it will reset to Dashboard's automatically generated value. + - minor (integer): Desired minor value of the beacon. If the value is set to null it will reset to Dashboard's automatically generated value. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'updateDeviceWirelessBluetoothSettings', + } + resource = f'/devices/{serial}/wireless/bluetooth/settings' + + body_params = ['uuid', 'major', 'minor'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return self._session.put(metadata, resource, payload) + + def getNetworkBluetoothSettings(self, networkId: str): + """ + **Return the Bluetooth settings for a network. Bluetooth settings must be enabled on the network.** + https://api.meraki.com/api_docs#return-the-bluetooth-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'getNetworkBluetoothSettings', + } + resource = f'/networks/{networkId}/bluetoothSettings' + + return self._session.get(metadata, resource) + + def updateNetworkBluetoothSettings(self, networkId: str, **kwargs): + """ + **Update the Bluetooth settings for a network. See the docs page for Bluetooth settings.** + https://api.meraki.com/api_docs#update-the-bluetooth-settings-for-a-network + + - networkId (string) + - scanningEnabled (boolean): Whether APs will scan for Bluetooth enabled clients. (true, false) + - advertisingEnabled (boolean): Whether APs will advertise beacons. (true, false) + - uuid (string): The UUID to be used in the beacon identifier. + - majorMinorAssignmentMode (string): The way major and minor number should be assigned to nodes in the network. ('Unique', 'Non-unique') + - major (integer): The major number to be used in the beacon identifier. Only valid in 'Non-unique' mode. + - minor (integer): The minor number to be used in the beacon identifier. Only valid in 'Non-unique' mode. + """ + + kwargs.update(locals()) + + if 'majorMinorAssignmentMode' in kwargs: + options = ['Unique', 'Non-unique'] + assert kwargs['majorMinorAssignmentMode'] in options, f'''"majorMinorAssignmentMode" cannot be "{kwargs['majorMinorAssignmentMode']}", & must be set to one of: {options}''' + + metadata = { + 'tags': ['Bluetooth settings'], + 'operation': 'updateNetworkBluetoothSettings', + } + resource = f'/networks/{networkId}/bluetoothSettings' + + body_params = ['scanningEnabled', 'advertisingEnabled', 'uuid', 'majorMinorAssignmentMode', 'major', 'minor'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return self._session.put(metadata, resource, payload) + diff --git a/meraki/api/camera_quality_retention_profiles.py b/meraki/api/camera_quality_retention_profiles.py index 109f6303..108deff7 100644 --- a/meraki/api/camera_quality_retention_profiles.py +++ b/meraki/api/camera_quality_retention_profiles.py @@ -30,6 +30,7 @@ def createNetworkCameraQualityRetentionProfile(self, networkId: str, name: str, - restrictedBandwidthModeEnabled (boolean): Disable features that require additional bandwidth such as Motion Recap. Can be either true or false. Defaults to false. - audioRecordingEnabled (boolean): Whether or not to record audio. Can be either true or false. Defaults to false. - cloudArchiveEnabled (boolean): Create redundant video backup using Cloud Archive. Can be either true or false. Defaults to false. + - motionDetectorVersion (integer): The version of the motion detector that will be used by the camera. Only applies to Gen 2 cameras. Defaults to v2. - scheduleId (string): Schedule for which this camera will record video, or 'null' to always record. - maxRetentionDays (integer): The maximum number of days for which the data will be stored, or 'null' to keep data until storage space runs out. If the former, it can be one of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 30, 60, 90] days - videoSettings (object): Video quality and resolution settings for all the camera models. @@ -43,7 +44,7 @@ def createNetworkCameraQualityRetentionProfile(self, networkId: str, name: str, } resource = f'/networks/{networkId}/camera/qualityRetentionProfiles' - body_params = ['name', 'motionBasedRetentionEnabled', 'restrictedBandwidthModeEnabled', 'audioRecordingEnabled', 'cloudArchiveEnabled', 'scheduleId', 'maxRetentionDays', 'videoSettings'] + body_params = ['name', 'motionBasedRetentionEnabled', 'restrictedBandwidthModeEnabled', 'audioRecordingEnabled', 'cloudArchiveEnabled', 'motionDetectorVersion', 'scheduleId', 'maxRetentionDays', 'videoSettings'] payload = {k: v for (k, v) in kwargs.items() if k in body_params} return self._session.post(metadata, resource, payload) @@ -77,6 +78,7 @@ def updateNetworkCameraQualityRetentionProfile(self, networkId: str, qualityRete - restrictedBandwidthModeEnabled (boolean): Disable features that require additional bandwidth such as Motion Recap. Can be either true or false. Defaults to false. - audioRecordingEnabled (boolean): Whether or not to record audio. Can be either true or false. Defaults to false. - cloudArchiveEnabled (boolean): Create redundant video backup using Cloud Archive. Can be either true or false. Defaults to false. + - motionDetectorVersion (integer): The version of the motion detector that will be used by the camera. Only applies to Gen 2 cameras. Defaults to v2. - scheduleId (string): Schedule for which this camera will record video, or 'null' to always record. - maxRetentionDays (integer): The maximum number of days for which the data will be stored, or 'null' to keep data until storage space runs out. If the former, it can be one of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 30, 60, 90] days - videoSettings (object): Video quality and resolution settings for all the camera models. @@ -90,7 +92,7 @@ def updateNetworkCameraQualityRetentionProfile(self, networkId: str, qualityRete } resource = f'/networks/{networkId}/camera/qualityRetentionProfiles/{qualityRetentionProfileId}' - body_params = ['name', 'motionBasedRetentionEnabled', 'restrictedBandwidthModeEnabled', 'audioRecordingEnabled', 'cloudArchiveEnabled', 'scheduleId', 'maxRetentionDays', 'videoSettings'] + body_params = ['name', 'motionBasedRetentionEnabled', 'restrictedBandwidthModeEnabled', 'audioRecordingEnabled', 'cloudArchiveEnabled', 'motionDetectorVersion', 'scheduleId', 'maxRetentionDays', 'videoSettings'] payload = {k: v for (k, v) in kwargs.items() if k in body_params} return self._session.put(metadata, resource, payload) diff --git a/meraki/api/cameras.py b/meraki/api/cameras.py index c46a6d30..e8863b0f 100644 --- a/meraki/api/cameras.py +++ b/meraki/api/cameras.py @@ -77,6 +77,7 @@ def generateNetworkCameraSnapshot(self, networkId: str, serial: str, **kwargs): - networkId (string) - serial (string) - timestamp (string): [optional] The snapshot will be taken from this time on the camera. The timestamp is expected to be in ISO 8601 format. If no timestamp is specified, we will assume current time. + - fullframe (boolean): [optional] If set to "true" the snapshot will be taken at full sensor resolution. This will error if used with timestamp. """ kwargs.update(locals()) @@ -87,7 +88,7 @@ def generateNetworkCameraSnapshot(self, networkId: str, serial: str, **kwargs): } resource = f'/networks/{networkId}/cameras/{serial}/snapshot' - body_params = ['timestamp'] + body_params = ['timestamp', 'fullframe'] payload = {k: v for (k, v) in kwargs.items() if k in body_params} return self._session.post(metadata, resource, payload) diff --git a/meraki/api/change_log.py b/meraki/api/change_log.py new file mode 100644 index 00000000..8c68ab62 --- /dev/null +++ b/meraki/api/change_log.py @@ -0,0 +1,37 @@ +class ChangeLog(object): + def __init__(self, session): + super(ChangeLog, self).__init__() + self._session = session + + def getOrganizationConfigurationChanges(self, organizationId: str, total_pages=1, direction='prev', **kwargs): + """ + **View the Change Log for your organization** + https://api.meraki.com/api_docs#view-the-change-log-for-your-organization + + - organizationId (string) + - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages + - direction (string): direction to paginate, either "prev" (default) or "next" page + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 365 days from today. + - t1 (string): The end of the timespan for the data. t1 can be a maximum of 365 days after t0. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameters t0 and t1. The value must be in seconds and be less than or equal to 365 days. The default is 365 days. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 5000. Default is 5000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - networkId (string): Filters on the given network + - adminId (string): Filters on the given Admin + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Change log'], + 'operation': 'getOrganizationConfigurationChanges', + } + resource = f'/organizations/{organizationId}/configurationChanges' + + query_params = ['t0', 't1', 'timespan', 'perPage', 'startingAfter', 'endingBefore', 'networkId', 'adminId'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return self._session.get_pages(metadata, resource, params, total_pages, direction) + + diff --git a/meraki/api/clients.py b/meraki/api/clients.py index 481d54b9..45794aef 100644 --- a/meraki/api/clients.py +++ b/meraki/api/clients.py @@ -55,27 +55,33 @@ def getNetworkClients(self, networkId: str, total_pages=1, direction='next', **k return self._session.get_pages(metadata, resource, params, total_pages, direction) - def provisionNetworkClients(self, networkId: str, **kwargs): + def provisionNetworkClients(self, networkId: str, mac: str, devicePolicy: str, **kwargs): """ **Provisions a client with a name and policy. Clients can be provisioned before they associate to the network.** https://api.meraki.com/api_docs#provisions-a-client-with-a-name-and-policy - networkId (string) - mac (string): The MAC address of the client. Required. + - devicePolicy (string): The policy to apply to the specified client. Can be 'Group policy', 'Whitelisted', 'Blocked', 'Per connection' or 'Normal'. Required. - name (string): The display name for the client. Optional. Limited to 255 bytes. - - devicePolicy (string): The policy to apply to the specified client. Can be 'Whitelisted', 'Blocked', 'Normal' or 'Group policy'. Required. - groupPolicyId (string): The ID of the desired group policy to apply to the client. Required if 'devicePolicy' is set to "Group policy". Otherwise this is ignored. + - policiesBySecurityAppliance (object): An object, describing what the policy-connection association is for the security appliance. (Only relevant if the security appliance is actually within the network) + - policiesBySsid (object): An object, describing the policy-connection associations for each active SSID within the network. Keys should be the number of enabled SSIDs, mapping to an object describing the client's policy """ kwargs.update(locals()) + if 'devicePolicy' in kwargs: + options = ['Group policy', 'Whitelisted', 'Blocked', 'Per connection', 'Normal'] + assert kwargs['devicePolicy'] in options, f'''"devicePolicy" cannot be "{kwargs['devicePolicy']}", & must be set to one of: {options}''' + metadata = { 'tags': ['Clients'], 'operation': 'provisionNetworkClients', } resource = f'/networks/{networkId}/clients/provision' - body_params = ['mac', 'name', 'devicePolicy', 'groupPolicyId'] + body_params = ['mac', 'name', 'devicePolicy', 'groupPolicyId', 'policiesBySecurityAppliance', 'policiesBySsid'] payload = {k: v for (k, v) in kwargs.items() if k in body_params} return self._session.post(metadata, resource, payload) @@ -168,15 +174,15 @@ def getNetworkClientPolicy(self, networkId: str, clientId: str): return self._session.get(metadata, resource) - def updateNetworkClientPolicy(self, networkId: str, clientId: str, **kwargs): + def updateNetworkClientPolicy(self, networkId: str, clientId: str, devicePolicy: str, **kwargs): """ **Update the policy assigned to a client on the network. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** https://api.meraki.com/api_docs#update-the-policy-assigned-to-a-client-on-the-network - networkId (string) - clientId (string) - - devicePolicy (string): The group policy (Whitelisted, Blocked, Normal, Group policy) - - groupPolicyId (string): [optional] If devicePolicy param is set to 'Group policy' this param is used to specify the group ID. + - devicePolicy (string): The policy to assign. Can be 'Whitelisted', 'Blocked', 'Normal' or 'Group policy'. Required. + - groupPolicyId (string): [optional] If 'devicePolicy' is set to 'Group policy' this param is used to specify the group policy ID. """ kwargs.update(locals()) @@ -209,17 +215,17 @@ def getNetworkClientSplashAuthorizationStatus(self, networkId: str, clientId: st return self._session.get(metadata, resource) - def updateNetworkClientSplashAuthorizationStatus(self, networkId: str, clientId: str, **kwargs): + def updateNetworkClientSplashAuthorizationStatus(self, networkId: str, clientId: str, ssids: dict): """ **Update a client's splash authorization. Clients can be identified by a client key or either the MAC or IP depending on whether the network uses Track-by-IP.** https://api.meraki.com/api_docs#update-a-clients-splash-authorization - networkId (string) - clientId (string) - - ssids (object): The target SSIDs. Each SSID must be enabled and must have Click-through splash enabled. For each SSID where isAuthorized is true, the expiration time will automatically be set according to the SSID's splash frequency. + - ssids (object): The target SSIDs. Each SSID must be enabled and must have Click-through splash enabled. For each SSID where isAuthorized is true, the expiration time will automatically be set according to the SSID's splash frequency. Not all networks support configuring all SSIDs """ - kwargs.update(locals()) + kwargs = locals() metadata = { 'tags': ['Clients'], diff --git a/meraki/api/content_filtering_rules.py b/meraki/api/content_filtering_rules.py index a5ae50cf..1a5a6400 100644 --- a/meraki/api/content_filtering_rules.py +++ b/meraki/api/content_filtering_rules.py @@ -33,6 +33,10 @@ def updateNetworkContentFiltering(self, networkId: str, **kwargs): kwargs.update(locals()) + if 'urlCategoryListSize' in kwargs: + options = ['topSites', 'fullList'] + assert kwargs['urlCategoryListSize'] in options, f'''"urlCategoryListSize" cannot be "{kwargs['urlCategoryListSize']}", & must be set to one of: {options}''' + metadata = { 'tags': ['Content filtering rules'], 'operation': 'updateNetworkContentFiltering', diff --git a/meraki/api/devices.py b/meraki/api/devices.py index 609029f5..c81eda50 100644 --- a/meraki/api/devices.py +++ b/meraki/api/devices.py @@ -3,6 +3,28 @@ def __init__(self, session): super(Devices, self).__init__() self._session = session + def cycleDeviceSwitchPorts(self, serial: str, ports: list): + """ + **Cycle a set of switch ports** + https://api.meraki.com/api_docs#cycle-a-set-of-switch-ports + + - serial (string) + - ports (array): List of switch ports. Example: [1, 2-5, 1_MA-MOD-8X10G_1, 1_MA-MOD-8X10G_2-1_MA-MOD-8X10G_8] + """ + + kwargs = locals() + + metadata = { + 'tags': ['Devices'], + 'operation': 'cycleDeviceSwitchPorts', + } + resource = f'/devices/{serial}/switch/ports/cycle' + + body_params = ['ports'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return self._session.post(metadata, resource, payload) + def getNetworkDevices(self, networkId: str): """ **List the devices in a network** @@ -21,11 +43,12 @@ def getNetworkDevices(self, networkId: str): def claimNetworkDevices(self, networkId: str, **kwargs): """ - **Claim a device into a network** - https://api.meraki.com/api_docs#claim-a-device-into-a-network + **Claim devices into a network** + https://api.meraki.com/api_docs#claim-devices-into-a-network - networkId (string) - - serial (string): The serial of a device + - serials (array): A list of serials of devices to claim + - serial (string): [DEPRECATED] The serial of a device to claim """ kwargs.update(locals()) @@ -36,7 +59,7 @@ def claimNetworkDevices(self, networkId: str, **kwargs): } resource = f'/networks/{networkId}/devices/claim' - body_params = ['serial'] + body_params = ['serials', 'serial'] payload = {k: v for (k, v) in kwargs.items() if k in body_params} return self._session.post(metadata, resource, payload) diff --git a/meraki/api/intrusion_settings.py b/meraki/api/intrusion_settings.py index ae64ed0e..a97c4093 100644 --- a/meraki/api/intrusion_settings.py +++ b/meraki/api/intrusion_settings.py @@ -32,6 +32,13 @@ def updateNetworkSecurityIntrusionSettings(self, networkId: str, **kwargs): kwargs.update(locals()) + if 'mode' in kwargs: + options = ['prevention', 'detection', 'disabled'] + assert kwargs['mode'] in options, f'''"mode" cannot be "{kwargs['mode']}", & must be set to one of: {options}''' + if 'idsRulesets' in kwargs: + options = ['connectivity', 'balanced', 'security'] + assert kwargs['idsRulesets'] in options, f'''"idsRulesets" cannot be "{kwargs['idsRulesets']}", & must be set to one of: {options}''' + metadata = { 'tags': ['Intrusion settings'], 'operation': 'updateNetworkSecurityIntrusionSettings', diff --git a/meraki/api/malware_settings.py b/meraki/api/malware_settings.py index e7d93908..026ec26c 100644 --- a/meraki/api/malware_settings.py +++ b/meraki/api/malware_settings.py @@ -19,7 +19,7 @@ def getNetworkSecurityMalwareSettings(self, networkId: str): return self._session.get(metadata, resource) - def updateNetworkSecurityMalwareSettings(self, networkId: str, **kwargs): + def updateNetworkSecurityMalwareSettings(self, networkId: str, mode: str, **kwargs): """ **Set the supported malware settings for an MX network** https://api.meraki.com/api_docs#set-the-supported-malware-settings-for-an-mx-network @@ -32,6 +32,10 @@ def updateNetworkSecurityMalwareSettings(self, networkId: str, **kwargs): kwargs.update(locals()) + if 'mode' in kwargs: + options = ['enabled', 'disabled'] + assert kwargs['mode'] in options, f'''"mode" cannot be "{kwargs['mode']}", & must be set to one of: {options}''' + metadata = { 'tags': ['Malware settings'], 'operation': 'updateNetworkSecurityMalwareSettings', diff --git a/meraki/api/monitored_media_servers.py b/meraki/api/monitored_media_servers.py new file mode 100644 index 00000000..32aeadb3 --- /dev/null +++ b/meraki/api/monitored_media_servers.py @@ -0,0 +1,102 @@ +class MonitoredMediaServers(object): + def __init__(self, session): + super(MonitoredMediaServers, self).__init__() + self._session = session + + def getOrganizationInsightMonitoredMediaServers(self, organizationId: str): + """ + **List the monitored media servers for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#list-the-monitored-media-servers-for-this-organization + + - organizationId (string) + """ + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'getOrganizationInsightMonitoredMediaServers', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers' + + return self._session.get(metadata, resource) + + def createOrganizationInsightMonitoredMediaServer(self, organizationId: str, name: str, address: str): + """ + **Add a media server to be monitored for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#add-a-media-server-to-be-monitored-for-this-organization + + - organizationId (string) + - name (string): The name of the VoIP provider + - address (string): The IP address (IPv4 only) or hostname of the media server to monitor + """ + + kwargs = locals() + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'createOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers' + + body_params = ['name', 'address'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return self._session.post(metadata, resource, payload) + + def getOrganizationInsightMonitoredMediaServer(self, organizationId: str, monitoredMediaServerId: str): + """ + **Return a monitored media server for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#return-a-monitored-media-server-for-this-organization + + - organizationId (string) + - monitoredMediaServerId (string) + """ + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'getOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}' + + return self._session.get(metadata, resource) + + def updateOrganizationInsightMonitoredMediaServer(self, organizationId: str, monitoredMediaServerId: str, **kwargs): + """ + **Update a monitored media server for this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#update-a-monitored-media-server-for-this-organization + + - organizationId (string) + - monitoredMediaServerId (string) + - name (string): The name of the VoIP provider + - address (string): The IP address (IPv4 only) or hostname of the media server to monitor + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'updateOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}' + + body_params = ['name', 'address'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return self._session.put(metadata, resource, payload) + + def deleteOrganizationInsightMonitoredMediaServer(self, organizationId: str, monitoredMediaServerId: str): + """ + **Delete a monitored media server from this organization. Only valid for organizations with Meraki Insight.** + https://api.meraki.com/api_docs#delete-a-monitored-media-server-from-this-organization + + - organizationId (string) + - monitoredMediaServerId (string) + """ + + metadata = { + 'tags': ['Monitored media servers'], + 'operation': 'deleteOrganizationInsightMonitoredMediaServer', + } + resource = f'/organizations/{organizationId}/insight/monitoredMediaServers/{monitoredMediaServerId}' + + return self._session.delete(metadata, resource) + diff --git a/meraki/api/mx_1_1_nat_rules.py b/meraki/api/mx_1_1_nat_rules.py index 038c20a3..188a1718 100644 --- a/meraki/api/mx_1_1_nat_rules.py +++ b/meraki/api/mx_1_1_nat_rules.py @@ -19,7 +19,7 @@ def getNetworkOneToOneNatRules(self, networkId: str): return self._session.get(metadata, resource) - def updateNetworkOneToOneNatRules(self, networkId: str, **kwargs): + def updateNetworkOneToOneNatRules(self, networkId: str, rules: list): """ **Set the 1:1 NAT mapping rules for an MX network** https://api.meraki.com/api_docs#set-the-11-nat-mapping-rules-for-an-mx-network @@ -28,7 +28,7 @@ def updateNetworkOneToOneNatRules(self, networkId: str, **kwargs): - rules (array): An array of 1:1 nat rules """ - kwargs.update(locals()) + kwargs = locals() metadata = { 'tags': ['MX 1:1 NAT rules'], diff --git a/meraki/api/mx_1_many_nat_rules.py b/meraki/api/mx_1_many_nat_rules.py index 2cc2a91c..e8e27b41 100644 --- a/meraki/api/mx_1_many_nat_rules.py +++ b/meraki/api/mx_1_many_nat_rules.py @@ -19,7 +19,7 @@ def getNetworkOneToManyNatRules(self, networkId: str): return self._session.get(metadata, resource) - def updateNetworkOneToManyNatRules(self, networkId: str, **kwargs): + def updateNetworkOneToManyNatRules(self, networkId: str, rules: list): """ **Set the 1:Many NAT mapping rules for an MX network** https://api.meraki.com/api_docs#set-the-1many-nat-mapping-rules-for-an-mx-network @@ -28,7 +28,7 @@ def updateNetworkOneToManyNatRules(self, networkId: str, **kwargs): - rules (array): An array of 1:Many nat rules """ - kwargs.update(locals()) + kwargs = locals() metadata = { 'tags': ['MX 1:Many NAT rules'], diff --git a/meraki/api/mx_port_forwarding_rules.py b/meraki/api/mx_port_forwarding_rules.py index c7e0b673..91c30f85 100644 --- a/meraki/api/mx_port_forwarding_rules.py +++ b/meraki/api/mx_port_forwarding_rules.py @@ -19,7 +19,7 @@ def getNetworkPortForwardingRules(self, networkId: str): return self._session.get(metadata, resource) - def updateNetworkPortForwardingRules(self, networkId: str, **kwargs): + def updateNetworkPortForwardingRules(self, networkId: str, rules: list): """ **Update the port forwarding rules for an MX network** https://api.meraki.com/api_docs#update-the-port-forwarding-rules-for-an-mx-network @@ -28,7 +28,7 @@ def updateNetworkPortForwardingRules(self, networkId: str, **kwargs): - rules (array): An array of port forwarding params """ - kwargs.update(locals()) + kwargs = locals() metadata = { 'tags': ['MX port forwarding rules'], diff --git a/meraki/api/mx_static_routes.py b/meraki/api/mx_static_routes.py index 96d0f677..354bc880 100644 --- a/meraki/api/mx_static_routes.py +++ b/meraki/api/mx_static_routes.py @@ -19,7 +19,7 @@ def getNetworkStaticRoutes(self, networkId: str): return self._session.get(metadata, resource) - def createNetworkStaticRoute(self, networkId: str, **kwargs): + def createNetworkStaticRoute(self, networkId: str, name: str, subnet: str, gatewayIp: str): """ **Add a static route for an MX or teleworker network** https://api.meraki.com/api_docs#add-a-static-route-for-an-mx-or-teleworker-network @@ -30,7 +30,7 @@ def createNetworkStaticRoute(self, networkId: str, **kwargs): - gatewayIp (string): The gateway IP (next hop) of the static route """ - kwargs.update(locals()) + kwargs = locals() metadata = { 'tags': ['MX static routes'], @@ -43,36 +43,36 @@ def createNetworkStaticRoute(self, networkId: str, **kwargs): return self._session.post(metadata, resource, payload) - def getNetworkStaticRoute(self, networkId: str, srId: str): + def getNetworkStaticRoute(self, networkId: str, staticRouteId: str): """ **Return a static route for an MX or teleworker network** https://api.meraki.com/api_docs#return-a-static-route-for-an-mx-or-teleworker-network - networkId (string) - - srId (string) + - staticRouteId (string) """ metadata = { 'tags': ['MX static routes'], 'operation': 'getNetworkStaticRoute', } - resource = f'/networks/{networkId}/staticRoutes/{srId}' + resource = f'/networks/{networkId}/staticRoutes/{staticRouteId}' return self._session.get(metadata, resource) - def updateNetworkStaticRoute(self, networkId: str, srId: str, **kwargs): + def updateNetworkStaticRoute(self, networkId: str, staticRouteId: str, **kwargs): """ **Update a static route for an MX or teleworker network** https://api.meraki.com/api_docs#update-a-static-route-for-an-mx-or-teleworker-network - networkId (string) - - srId (string) + - staticRouteId (string) - name (string): The name of the static route - subnet (string): The subnet of the static route - gatewayIp (string): The gateway IP (next hop) of the static route - - enabled (string): The enabled state of the static route - - fixedIpAssignments (string): The DHCP fixed IP assignments on the static route - - reservedIpRanges (string): The DHCP reserved IP ranges on the static route + - enabled (boolean): The enabled state of the static route + - fixedIpAssignments (object): The DHCP fixed IP assignments on the static route. This should be an object that contains mappings from MAC addresses to objects that themselves each contain "ip" and "name" string fields. See the sample request/response for more details. + - reservedIpRanges (array): The DHCP reserved IP ranges on the static route """ kwargs.update(locals()) @@ -81,27 +81,27 @@ def updateNetworkStaticRoute(self, networkId: str, srId: str, **kwargs): 'tags': ['MX static routes'], 'operation': 'updateNetworkStaticRoute', } - resource = f'/networks/{networkId}/staticRoutes/{srId}' + resource = f'/networks/{networkId}/staticRoutes/{staticRouteId}' body_params = ['name', 'subnet', 'gatewayIp', 'enabled', 'fixedIpAssignments', 'reservedIpRanges'] payload = {k: v for (k, v) in kwargs.items() if k in body_params} return self._session.put(metadata, resource, payload) - def deleteNetworkStaticRoute(self, networkId: str, srId: str): + def deleteNetworkStaticRoute(self, networkId: str, staticRouteId: str): """ **Delete a static route from an MX or teleworker network** https://api.meraki.com/api_docs#delete-a-static-route-from-an-mx-or-teleworker-network - networkId (string) - - srId (string) + - staticRouteId (string) """ metadata = { 'tags': ['MX static routes'], 'operation': 'deleteNetworkStaticRoute', } - resource = f'/networks/{networkId}/staticRoutes/{srId}' + resource = f'/networks/{networkId}/staticRoutes/{staticRouteId}' return self._session.delete(metadata, resource) diff --git a/meraki/api/networks.py b/meraki/api/networks.py index e1bd7822..f2205b5a 100644 --- a/meraki/api/networks.py +++ b/meraki/api/networks.py @@ -124,53 +124,6 @@ def bindNetwork(self, networkId: str, configTemplateId: str, **kwargs): return self._session.post(metadata, resource, payload) - def getNetworkBluetoothSettings(self, networkId: str): - """ - **Return the Bluetooth settings for a network. Bluetooth settings must be enabled on the network.** - https://api.meraki.com/api_docs#return-the-bluetooth-settings-for-a-network - - - networkId (string) - """ - - metadata = { - 'tags': ['Networks'], - 'operation': 'getNetworkBluetoothSettings', - } - resource = f'/networks/{networkId}/bluetoothSettings' - - return self._session.get(metadata, resource) - - def updateNetworkBluetoothSettings(self, networkId: str, **kwargs): - """ - **Update the Bluetooth settings for a network. See the docs page for Bluetooth settings.** - https://api.meraki.com/api_docs#update-the-bluetooth-settings-for-a-network - - - networkId (string) - - scanningEnabled (boolean): Whether APs will scan for Bluetooth enabled clients. (true, false) - - advertisingEnabled (boolean): Whether APs will advertise beacons. (true, false) - - uuid (string): The UUID to be used in the beacon identifier. - - majorMinorAssignmentMode (string): The way major and minor number should be assigned to nodes in the network. ('Unique', 'Non-unique') - - major (integer): The major number to be used in the beacon identifier. Only valid in 'Non-unique' mode. - - minor (integer): The minor number to be used in the beacon identifier. Only valid in 'Non-unique' mode. - """ - - kwargs.update(locals()) - - if 'majorMinorAssignmentMode' in kwargs: - options = ['Unique', 'Non-unique'] - assert kwargs['majorMinorAssignmentMode'] in options, f'''"majorMinorAssignmentMode" cannot be "{kwargs['majorMinorAssignmentMode']}", & must be set to one of: {options}''' - - metadata = { - 'tags': ['Networks'], - 'operation': 'updateNetworkBluetoothSettings', - } - resource = f'/networks/{networkId}/bluetoothSettings' - - body_params = ['scanningEnabled', 'advertisingEnabled', 'uuid', 'majorMinorAssignmentMode', 'major', 'minor'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.put(metadata, resource, payload) - def getNetworkSiteToSiteVpn(self, networkId: str): """ **Return the site-to-site VPN settings of a network. Only valid for MX networks.** diff --git a/meraki/api/organizations.py b/meraki/api/organizations.py index f34ee6bb..57e8cd92 100644 --- a/meraki/api/organizations.py +++ b/meraki/api/organizations.py @@ -179,8 +179,8 @@ def getOrganizationInventory(self, organizationId: str, **kwargs): def getOrganizationLicenseState(self, organizationId: str): """ - **Return the license state for an organization** - https://api.meraki.com/api_docs#return-the-license-state-for-an-organization + **Return an overview of the license state for an organization** + https://api.meraki.com/api_docs#return-an-overview-of-the-license-state-for-an-organization - organizationId (string) """ diff --git a/meraki/api/sm.py b/meraki/api/sm.py index 63e0c134..cf58019e 100644 --- a/meraki/api/sm.py +++ b/meraki/api/sm.py @@ -331,236 +331,6 @@ def unenrollNetworkSmDevice(self, networkId: str, deviceId: str): return self._session.post(metadata, resource) - def createNetworkSmProfileClarity(self, networkId: str, name: str, scope: str, VendorConfig: list, **kwargs): - """ - **Create a new profile containing a Cisco Clarity payload** - https://api.meraki.com/api_docs#create-a-new-profile-containing-a-cisco-clarity-payload - - - networkId (string) - - name (string): The name to be given to the new profile - - scope (string): The scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be assigned - - VendorConfig (array): The specific VendorConfig to be passed to the filtering framework, in the form of an array of objects (as JSON). - - PluginBundleID (string): The bundle ID of the application, defaults to com.cisco.ciscosecurity.app - - FilterBrowsers (boolean): Whether or not to enable browser traffic filtering (one of true, false). Default true. - - FilterSockets (boolean): Whether or not to enable socket traffic filtering (one of true, false). Default true. - """ - - kwargs.update(locals()) - - metadata = { - 'tags': ['SM'], - 'operation': 'createNetworkSmProfileClarity', - } - resource = f'/networks/{networkId}/sm/profile/clarity' - - body_params = ['name', 'scope', 'PluginBundleID', 'FilterBrowsers', 'FilterSockets', 'VendorConfig'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.post(metadata, resource, payload) - - def updateNetworkSmProfileClarity(self, networkId: str, profileId: str, **kwargs): - """ - **Update an existing profile containing a Cisco Clarity payload** - https://api.meraki.com/api_docs#update-an-existing-profile-containing-a-cisco-clarity-payload - - - networkId (string) - - profileId (string) - - name (string): optional: A new name for the profile - - scope (string): optional: A new scope for the profile (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be assigned - - PluginBundleID (string): optional: The new bundle ID of the application - - FilterBrowsers (boolean): optional: Whether or not to enable browser traffic filtering (one of true, false). - - FilterSockets (boolean): optional: Whether or not to enable socket traffic filtering (one of true, false). - - VendorConfig (array): optional: The specific VendorConfig to be passed to the filtering framework, in the form of an array of objects (as JSON). - """ - - kwargs.update(locals()) - - metadata = { - 'tags': ['SM'], - 'operation': 'updateNetworkSmProfileClarity', - } - resource = f'/networks/{networkId}/sm/profile/clarity/{profileId}' - - body_params = ['name', 'scope', 'PluginBundleID', 'FilterBrowsers', 'FilterSockets', 'VendorConfig'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.put(metadata, resource, payload) - - def addNetworkSmProfileClarity(self, networkId: str, profileId: str, VendorConfig: list, **kwargs): - """ - **Add a Cisco Clarity payload to an existing profile** - https://api.meraki.com/api_docs#add-a-cisco-clarity-payload-to-an-existing-profile - - - networkId (string) - - profileId (string) - - VendorConfig (array): The specific VendorConfig to be passed to the filtering framework, in the form of an array of objects (as JSON). - - PluginBundleID (string): The bundle ID of the application, defaults to com.cisco.ciscosecurity.app - - FilterBrowsers (boolean): Whether or not to enable browser traffic filtering (one of true, false). Defaults to true - - FilterSockets (boolean): Whether or not to enable socket traffic filtering (one of true, false). Defaults to true - """ - - kwargs.update(locals()) - - metadata = { - 'tags': ['SM'], - 'operation': 'addNetworkSmProfileClarity', - } - resource = f'/networks/{networkId}/sm/profile/clarity/{profileId}' - - body_params = ['PluginBundleID', 'FilterBrowsers', 'FilterSockets', 'VendorConfig'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.post(metadata, resource, payload) - - def getNetworkSmProfileClarity(self, networkId: str, profileId: str): - """ - **Get details for a Cisco Clarity payload** - https://api.meraki.com/api_docs#get-details-for-a-cisco-clarity-payload - - - networkId (string) - - profileId (string) - """ - - metadata = { - 'tags': ['SM'], - 'operation': 'getNetworkSmProfileClarity', - } - resource = f'/networks/{networkId}/sm/profile/clarity/{profileId}' - - return self._session.get(metadata, resource) - - def deleteNetworkSmProfileClarity(self, networkId: str, profileId: str): - """ - **Delete a Cisco Clarity payload. Deletes the entire profile if it's empty after removing the payload.** - https://api.meraki.com/api_docs#delete-a-cisco-clarity-payload - - - networkId (string) - - profileId (string) - """ - - metadata = { - 'tags': ['SM'], - 'operation': 'deleteNetworkSmProfileClarity', - } - resource = f'/networks/{networkId}/sm/profile/clarity/{profileId}' - - return self._session.delete(metadata, resource) - - def createNetworkSmProfileUmbrella(self, networkId: str, name: str, scope: str, ProviderConfiguration: list, **kwargs): - """ - **Create a new profile containing a Cisco Umbrella payload** - https://api.meraki.com/api_docs#create-a-new-profile-containing-a-cisco-umbrella-payload - - - networkId (string) - - name (string): The name to be given to the new profile - - scope (string): The scope (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be assigned - - ProviderConfiguration (array): The specific ProviderConfiguration to be passed to the filtering framework, in the form of an array of objects (as JSON). - - AppBundleIdentifier (string): The bundle ID of the application, defaults to com.cisco.ciscosecurity.app - - ProviderBundleIdentifier (string): The bundle ID of the provider, defaults to com.cisco.ciscosecurity.app.CiscoUmbrella - - usesCert (boolean): Whether the certificate should be attached to this profile (one of true, false). False by default - """ - - kwargs.update(locals()) - - metadata = { - 'tags': ['SM'], - 'operation': 'createNetworkSmProfileUmbrella', - } - resource = f'/networks/{networkId}/sm/profile/umbrella' - - body_params = ['name', 'scope', 'AppBundleIdentifier', 'ProviderBundleIdentifier', 'ProviderConfiguration', 'usesCert'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.post(metadata, resource, payload) - - def updateNetworkSmProfileUmbrella(self, networkId: str, profileId: str, **kwargs): - """ - **Update an existing profile containing a Cisco Umbrella payload** - https://api.meraki.com/api_docs#update-an-existing-profile-containing-a-cisco-umbrella-payload - - - networkId (string) - - profileId (string) - - name (string): optional: A new name for the profile - - scope (string): optional: A new scope for the profile (one of all, none, withAny, withAll, withoutAny, or withoutAll) and a set of tags of the devices to be assigned - - AppBundleIdentifier (string): optional: The bundle ID of the application - - ProviderBundleIdentifier (string): optional: The bundle ID of the provider - - ProviderConfiguration (array): optional: The specific ProviderConfiguration to be passed to the filtering framework, in the form of an array of objects (as JSON). - - usesCert (boolean): optional: Whether the certificate should be attached to this profile (one of true, false) - """ - - kwargs.update(locals()) - - metadata = { - 'tags': ['SM'], - 'operation': 'updateNetworkSmProfileUmbrella', - } - resource = f'/networks/{networkId}/sm/profile/umbrella/{profileId}' - - body_params = ['name', 'scope', 'AppBundleIdentifier', 'ProviderBundleIdentifier', 'ProviderConfiguration', 'usesCert'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.put(metadata, resource, payload) - - def addNetworkSmProfileUmbrella(self, networkId: str, profileId: str, ProviderConfiguration: list, **kwargs): - """ - **Add a Cisco Umbrella payload to an existing profile** - https://api.meraki.com/api_docs#add-a-cisco-umbrella-payload-to-an-existing-profile - - - networkId (string) - - profileId (string) - - ProviderConfiguration (array): The specific ProviderConfiguration to be passed to the filtering framework, in the form of an array of objects (as JSON). - - AppBundleIdentifier (string): The bundle ID of the application, defaults to com.cisco.ciscosecurity.app - - ProviderBundleIdentifier (string): The bundle ID of the provider, defaults to com.cisco.ciscosecurity.app.CiscoUmbrella - - usesCert (boolean): Whether the certificate should be attached to this profile (one of true, false). False by default - """ - - kwargs.update(locals()) - - metadata = { - 'tags': ['SM'], - 'operation': 'addNetworkSmProfileUmbrella', - } - resource = f'/networks/{networkId}/sm/profile/umbrella/{profileId}' - - body_params = ['AppBundleIdentifier', 'ProviderBundleIdentifier', 'ProviderConfiguration', 'usesCert'] - payload = {k: v for (k, v) in kwargs.items() if k in body_params} - - return self._session.post(metadata, resource, payload) - - def getNetworkSmProfileUmbrella(self, networkId: str, profileId: str): - """ - **Get details for a Cisco Umbrella payload** - https://api.meraki.com/api_docs#get-details-for-a-cisco-umbrella-payload - - - networkId (string) - - profileId (string) - """ - - metadata = { - 'tags': ['SM'], - 'operation': 'getNetworkSmProfileUmbrella', - } - resource = f'/networks/{networkId}/sm/profile/umbrella/{profileId}' - - return self._session.get(metadata, resource) - - def deleteNetworkSmProfileUmbrella(self, networkId: str, profileId: str): - """ - **Delete a Cisco Umbrella payload. Deletes the entire profile if it's empty after removing the payload** - https://api.meraki.com/api_docs#delete-a-cisco-umbrella-payload - - - networkId (string) - - profileId (string) - """ - - metadata = { - 'tags': ['SM'], - 'operation': 'deleteNetworkSmProfileUmbrella', - } - resource = f'/networks/{networkId}/sm/profile/umbrella/{profileId}' - - return self._session.delete(metadata, resource) - def getNetworkSmProfiles(self, networkId: str): """ **List all the profiles in the network** @@ -807,9 +577,9 @@ def getNetworkSmConnectivity(self, network_id: str, id: str, total_pages=1, dire - id (string) - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages - direction (string): direction to paginate, either "next" (default) or "prev" page - - perPage (string): The number of entries per page returned - - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. - - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. """ kwargs.update(locals()) @@ -835,9 +605,9 @@ def getNetworkSmDesktopLogs(self, network_id: str, id: str, total_pages=1, direc - id (string) - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages - direction (string): direction to paginate, either "next" (default) or "prev" page - - perPage (string): The number of entries per page returned - - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. - - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. """ kwargs.update(locals()) @@ -867,9 +637,9 @@ def getNetworkSmDeviceCommandLogs(self, network_id: str, id: str, total_pages=1, - id (string) - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages - direction (string): direction to paginate, either "next" (default) or "prev" page - - perPage (string): The number of entries per page returned - - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. - - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. """ kwargs.update(locals()) @@ -895,9 +665,9 @@ def getNetworkSmPerformanceHistory(self, network_id: str, id: str, total_pages=1 - id (string) - total_pages (integer or string): total number of pages to retrieve, -1 or "all" for all pages - direction (string): direction to paginate, either "next" (default) or "prev" page - - perPage (string): The number of entries per page returned - - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. - - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, next or prev page in the HTTP Link header should define it. + - perPage (integer): The number of entries per page returned. Acceptable range is 3 - 1000. Default is 1000. + - startingAfter (string): A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. + - endingBefore (string): A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. """ kwargs.update(locals()) diff --git a/meraki/api/ssids.py b/meraki/api/ssids.py index 333771f1..b4f378e1 100644 --- a/meraki/api/ssids.py +++ b/meraki/api/ssids.py @@ -66,7 +66,7 @@ def updateNetworkSsid(self, networkId: str, number: str, **kwargs): - enterpriseAdminAccess (string): Whether or not an SSID is accessible by 'enterprise' administrators ('access disabled' or 'access enabled') - encryptionMode (string): The psk encryption mode for the SSID ('wep' or 'wpa'). This param is only valid if the authMode is 'psk' - psk (string): The passkey for the SSID. This param is only valid if the authMode is 'psk' - - wpaEncryptionMode (string): The types of WPA encryption. ('WPA1 and WPA2' or 'WPA2 only') + - wpaEncryptionMode (string): The types of WPA encryption. ('WPA1 only', 'WPA1 and WPA2', 'WPA2 only', 'WPA3 Transition Mode' or 'WPA3 only') - splashPage (string): The type of splash page for the SSID ('None', 'Click-through splash page', 'Billing', 'Password-protected with Meraki RADIUS', 'Password-protected with custom RADIUS', 'Password-protected with Active Directory', 'Password-protected with LDAP', 'SMS authentication', 'Systems Manager Sentry', 'Facebook Wi-Fi', 'Google OAuth' or 'Sponsored guest'). This attribute is not supported for template children. - radiusServers (array): The RADIUS 802.1x servers to be used for authentication. This param is only valid if the authMode is 'open-with-radius' or '8021x-radius' - radiusCoaEnabled (boolean): If true, Meraki devices will act as a RADIUS Dynamic Authorization Server and will respond to RADIUS Change-of-Authorization and Disconnect messages sent by the RADIUS server. @@ -103,7 +103,7 @@ def updateNetworkSsid(self, networkId: str, number: str, **kwargs): options = ['wep', 'wpa'] assert kwargs['encryptionMode'] in options, f'''"encryptionMode" cannot be "{kwargs['encryptionMode']}", & must be set to one of: {options}''' if 'wpaEncryptionMode' in kwargs: - options = ['WPA1 and WPA2', 'WPA2 only'] + options = ['WPA1 only', 'WPA1 and WPA2', 'WPA2 only', 'WPA3 Transition Mode', 'WPA3 only'] assert kwargs['wpaEncryptionMode'] in options, f'''"wpaEncryptionMode" cannot be "{kwargs['wpaEncryptionMode']}", & must be set to one of: {options}''' if 'splashPage' in kwargs: options = ['None', 'Click-through splash page', 'Billing', 'Password-protected with Meraki RADIUS', 'Password-protected with custom RADIUS', 'Password-protected with Active Directory', 'Password-protected with LDAP', 'SMS authentication', 'Systems Manager Sentry', 'Facebook Wi-Fi', 'Google OAuth', 'Sponsored guest'] diff --git a/meraki/api/switch_ports.py b/meraki/api/switch_ports.py index 59b9e5f8..bfb3b79e 100644 --- a/meraki/api/switch_ports.py +++ b/meraki/api/switch_ports.py @@ -26,6 +26,29 @@ def getDeviceSwitchPortStatuses(self, serial: str, **kwargs): return self._session.get(metadata, resource, params) + def getDeviceSwitchPortStatusesPackets(self, serial: str, **kwargs): + """ + **Return the packet counters for all the ports of a switch** + https://api.meraki.com/api_docs#return-the-packet-counters-for-all-the-ports-of-a-switch + + - serial (string) + - t0 (string): The beginning of the timespan for the data. The maximum lookback period is 1 day from today. + - timespan (number): The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 1 day. The default is 1 day. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch ports'], + 'operation': 'getDeviceSwitchPortStatusesPackets', + } + resource = f'/devices/{serial}/switchPortStatuses/packets' + + query_params = ['t0', 'timespan'] + params = {k: v for (k, v) in kwargs.items() if k in query_params} + + return self._session.get(metadata, resource, params) + def getDeviceSwitchPorts(self, serial: str): """ **List the switch ports for a switch** @@ -69,14 +92,14 @@ def updateDeviceSwitchPort(self, serial: str, number: str, **kwargs): - name (string): The name of the switch port - tags (string): The tags of the switch port - enabled (boolean): The status of the switch port - - type (string): The type of the switch port ("access" or "trunk") + - type (string): The type of the switch port ('trunk' or 'access') - vlan (integer): The VLAN of the switch port. A null value will clear the value set for trunk ports. - voiceVlan (integer): The voice VLAN of the switch port. Only applicable to access ports. - allowedVlans (string): The VLANs allowed on the switch port. Only applicable to trunk ports. - poeEnabled (boolean): The PoE status of the switch port - isolationEnabled (boolean): The isolation status of the switch port - rstpEnabled (boolean): The rapid spanning tree protocol status - - stpGuard (string): The state of the STP guard ("disabled", "Root guard", "BPDU guard", "Loop guard") + - stpGuard (string): The state of the STP guard ('disabled', 'root guard', 'bpdu guard' or 'loop guard') - accessPolicyNumber (integer): The number of the access policy of the switch port. Only applicable to access ports. - linkNegotiation (string): The link speed for the switch port - portScheduleId (string): The ID of the port schedule. A value of null will clear the port schedule. @@ -89,6 +112,12 @@ def updateDeviceSwitchPort(self, serial: str, number: str, **kwargs): kwargs.update(locals()) + if 'type' in kwargs: + options = ['trunk', 'access'] + assert kwargs['type'] in options, f'''"type" cannot be "{kwargs['type']}", & must be set to one of: {options}''' + if 'stpGuard' in kwargs: + options = ['disabled', 'root guard', 'bpdu guard', 'loop guard'] + assert kwargs['stpGuard'] in options, f'''"stpGuard" cannot be "{kwargs['stpGuard']}", & must be set to one of: {options}''' if 'udld' in kwargs: options = ['Alert only', 'Enforce'] assert kwargs['udld'] in options, f'''"udld" cannot be "{kwargs['udld']}", & must be set to one of: {options}''' diff --git a/meraki/api/switch_settings.py b/meraki/api/switch_settings.py index 624f882c..fa4fc865 100644 --- a/meraki/api/switch_settings.py +++ b/meraki/api/switch_settings.py @@ -164,6 +164,45 @@ def updateNetworkSwitchSettingsMtu(self, networkId: str, **kwargs): return self._session.put(metadata, resource, payload) + def getNetworkSwitchSettingsMulticast(self, networkId: str): + """ + **Return multicast settings for a network** + https://api.meraki.com/api_docs#return-multicast-settings-for-a-network + + - networkId (string) + """ + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'getNetworkSwitchSettingsMulticast', + } + resource = f'/networks/{networkId}/switch/settings/multicast' + + return self._session.get(metadata, resource) + + def updateNetworkSwitchSettingsMulticast(self, networkId: str, **kwargs): + """ + **Update multicast settings for a network** + https://api.meraki.com/api_docs#update-multicast-settings-for-a-network + + - networkId (string) + - defaultSettings (object): Default multicast setting for entire network. IGMP snooping and Flood unknown multicast traffic settings are enabled by default. + - overrides (array): Array of paired switches/stacks/profiles and corresponding multicast settings. An empty array will clear the multicast settings. + """ + + kwargs.update(locals()) + + metadata = { + 'tags': ['Switch settings'], + 'operation': 'updateNetworkSwitchSettingsMulticast', + } + resource = f'/networks/{networkId}/switch/settings/multicast' + + body_params = ['defaultSettings', 'overrides'] + payload = {k: v for (k, v) in kwargs.items() if k in body_params} + + return self._session.put(metadata, resource, payload) + def getNetworkSwitchSettingsQosRules(self, networkId: str): """ **List quality of service rules** diff --git a/meraki/config.py b/meraki/config.py index 08ea0fef..2a698ca1 100644 --- a/meraki/config.py +++ b/meraki/config.py @@ -21,10 +21,13 @@ # Create an output log file? OUTPUT_LOG = True +# Path to output log; by default, working directory of script if not specified +LOG_PATH = '' + # Log file name appended with date and timestamp LOG_FILE_PREFIX = 'meraki_api_' -# If output log used, output to console too? +# Print output logging to console? PRINT_TO_CONSOLE = True # Simulate POST/PUT/DELETE calls to prevent changes? diff --git a/meraki/convert_to_aio.py b/meraki/convert_to_aio.py new file mode 100644 index 00000000..653a03c5 --- /dev/null +++ b/meraki/convert_to_aio.py @@ -0,0 +1,141 @@ +''' +SPECIAL THANKS to Heimo Stieg (https://github.com/coreGreenberet) for implementing the "aio_" examples as well as this +script, which generates the contents of the "aio" directory for running asynchronously. +''' + + +import csv +from datetime import datetime +import os +import logging +import re +import io + +_logger = logging.Logger("") + + +def create_logger(log_file_prefix, print_console) -> logging.Logger: + logger = logging.getLogger(__name__) + log_file = f"{log_file_prefix}_log__{datetime.now():%Y-%m-%d_%H-%M-%S}.log" + logging.basicConfig( + filename=log_file, + level=logging.DEBUG, + format="%(asctime)s %(name)12s: %(levelname)8s > %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + if print_console: + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + formatter = logging.Formatter("%(name)12s: %(levelname)8s > %(message)s") + console.setFormatter(formatter) + logging.getLogger("").addHandler(console) + + return logger + + +def get_aio_path(path, filename) -> str: + """helper function to return the correct for a converted file based on the original file path""" + + if not os.path.isfile(os.path.join(path, filename)): + raise ValueError(f"{os.path.join(path,filename)} is not a file") + + if "api" in path: + path, _ = os.path.split(path) + return os.path.join(path, "aio", "api", filename) + else: + return os.path.join(path, "aio", filename) + + +def read_file(filepath): + """reads the file into memory and returns it contents""" + + _logger.info(f"Reading {filepath}") + # read file into memory + contents = None + with open(filepath, "r") as f: + contents = f.read() + return contents + + +def compile_regex(): + """this function will compile all needed regex patterns for the conversion + returns a tuple of dictionaries for the meraki/__init__.py file and all files under the api directory + """ + patternInitFile = {} + patternAPIFile = {} + + # all patterns for meraki/__init__.py + patternInitFile[re.compile("from \.legacy import \*\n")] = "" + patternInitFile[re.compile("from \.config import")] = "from ..config import" + patternInitFile[ + re.compile("class DashboardAPI\(object\):") + ] = "class AsyncDashboardAPI:" + patternInitFile[re.compile("(from \.api\..*import )(.*)")] = r"\1Async\2" + patternInitFile[ + re.compile("self\._session = RestSession\(") + ] = "self._session = AsyncRestSession(" + patternInitFile[re.compile("(self\..*) = (.*\(self\._session\))")] = r"\1 = Async\2" + patternInitFile[ + re.compile("\n$") + ] = """ + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self._session.close() +""" + + # patterns for meraki/api/*.py files + patternAPIFile[ + re.compile("super\([a-zA-Z0-9_]+, self\)\.__init__\(\)") + ] = "super().__init__()" + patternAPIFile[re.compile("class ([a-zA-Z0-9]+)\(object\):")] = r"class Async\1:" + patternAPIFile[re.compile("def ([^_].*)")] = r"async def \1" + patternAPIFile[ + re.compile("return self\._session\.") + ] = "return await self._session." + + return patternInitFile, patternAPIFile + + +def convert_file(path, filename, patternDict): + content = read_file(os.path.join(path, filename)) + + _logger.info("Starting Conversion") + + for p, v in patternDict.items(): + content, count = p.subn(v, content) + _logger.debug(f"Applied pattern {p.pattern} {count} times") + + _logger.info("Finished Conversion") + + aioFile = get_aio_path(path, filename) + with open(aioFile, "w") as f: + f.write(content) + _logger.info(f"File {aioFile} saved") + + +def main(): + # make sure that the aio/api directory does exist + if not os.path.exists("meraki/aio"): + os.makedirs("meraki/aio") + if not os.path.exists("meraki/aio/api"): + os.makedirs("meraki/aio/api") + + patternInitFile, patternAPIFile = compile_regex() + convert_file("meraki", "__init__.py", patternInitFile) + apifolder = "meraki/api" + + for file in os.listdir("meraki/api"): + if os.path.isfile(os.path.join(apifolder, file)) and file[-3:] == ".py": + convert_file(apifolder, file, patternAPIFile) + + +if __name__ == "__main__": + start_time = datetime.now() + _logger = create_logger(log_file_prefix=__file__[:-3], print_console=True) + main() + end_time = datetime.now() + _logger.info(f"\nScript complete, total runtime {end_time - start_time}") diff --git a/meraki/exceptions.py b/meraki/exceptions.py index e8dbcf9a..ca9e804a 100644 --- a/meraki/exceptions.py +++ b/meraki/exceptions.py @@ -14,13 +14,32 @@ def __init__(self, metadata, response): self.response = response self.tag = metadata['tags'][0] self.operation = metadata['operation'] - self.status = self.response.status_code - self.reason = self.response.reason + self.status = self.response.status_code if self.response is not None and self.response.status_code else None + self.reason = self.response.reason if self.response is not None and self.response.reason else None try: - self.message = self.response.json() + self.message = self.response.json() if self.response is not None and self.response.json() else None except ValueError: self.message = self.response.text[:100] super(APIError, self).__init__(f'{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}') def __repr__(self): return f'{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}' + +# To catch exceptions while making AIO API calls +class AsyncAPIError(Exception): + def __init__(self, metadata, response, message): + self.response = response + self.tag = metadata['tags'][0] + self.operation = metadata['operation'] + self.status = self.response.status if self.response is not None and self.response.status else None + self.reason = self.response.reason if self.response is not None and self.response.reason else None + try: + self.message = self.response.json() if self.response is not None and self.response.json() else None + except ValueError: + self.message = self.response.text[:100] + super().__init__( + f'{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}' + ) + + def __repr__(self): + return f'{self.tag}, {self.operation} - {self.status} {self.reason}, {self.message}' diff --git a/meraki/rest_session.py b/meraki/rest_session.py index ab44e3db..e5816a3f 100644 --- a/meraki/rest_session.py +++ b/meraki/rest_session.py @@ -9,9 +9,17 @@ # Main module interface class RestSession(object): - def __init__(self, logger, api_key, base_url=DEFAULT_BASE_URL, single_request_timeout=SINGLE_REQUEST_TIMEOUT, - certificate_path=CERTIFICATE_PATH, wait_on_rate_limit=WAIT_ON_RATE_LIMIT, - maximum_retries=MAXIMUM_RETRIES, simulate=SIMULATE_API_CALLS): + def __init__( + self, + logger, + api_key, + base_url=DEFAULT_BASE_URL, + single_request_timeout=SINGLE_REQUEST_TIMEOUT, + certificate_path=CERTIFICATE_PATH, + wait_on_rate_limit=WAIT_ON_RATE_LIMIT, + maximum_retries=MAXIMUM_RETRIES, + simulate=SIMULATE_API_CALLS, + ): super(RestSession, self).__init__() # Initialize attributes and properties @@ -67,6 +75,7 @@ def request(self, metadata, method, url, **kwargs): self._logger.info(f'{tag}, {operation} - SIMULATED') return None else: + response = None while retries > 0: # Make the HTTP request to the API endpoint try: @@ -132,8 +141,24 @@ def request(self, metadata, method, url, **kwargs): message = response.json() except ValueError: message = response.text[:100] - self._logger.error(f'{tag}, {operation} - {status} {reason}, {message}') - raise APIError(metadata, response) + + # Check specifically for action batch concurrency error + action_batch_concurrency_error = { + 'errors': [ + 'Too many concurrently executing batches. Maximum is 5 confirmed but not yet executed batches.' + ] + } + if message == action_batch_concurrency_error: + self._logger.warning(f'{tag}, {operation} - {status} {reason}, retrying in 60 seconds') + time.sleep(60) + retries -= 1 + if retries == 0: + raise APIError(metadata, response) + + # All other client-side errors + else: + self._logger.error(f'{tag}, {operation} - {status} {reason}, {message}') + raise APIError(metadata, response) def get(self, metadata, url, params=None): metadata['method'] = 'GET' diff --git a/setup.py b/setup.py index b1d56601..85cd3e03 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,39 @@ """Setup script for meraki""" import os.path +import re from setuptools import setup, find_packages HERE = os.path.abspath(os.path.dirname(__file__)) +PACKAGE_INIT = os.path.abspath(os.path.join('meraki', '__init__.py')) with open(os.path.join(HERE, 'README.md')) as fid: README = fid.read() + +def find_version(fname): + '''Attempts to find the version number in the file names fname. + Raises RuntimeError if not found. + ''' + version = '' + with open(fname, 'r') as fp: + reg = re.compile(r'__version__ = [\'"]([^\'"]*)[\'"]') + for line in fp: + m = reg.match(line) + if m: + version = m.group(1) + break + if not version: + raise RuntimeError('Cannot find version information') + return version + + +__version__ = find_version(PACKAGE_INIT) + + setup( name='meraki', - version='0.70.5', + version=__version__, packages=find_packages(), include_package_data=True, install_requires=['requests'],