diff --git a/AddStaticRoute.py b/AddStaticRoute.py new file mode 100644 index 0000000..b6e3ec9 --- /dev/null +++ b/AddStaticRoute.py @@ -0,0 +1,37 @@ +# Test YML looks like: +# --- +# NetworkID: Z_9512345678 +# API_Key: c1234567890abcdef01234 +# Gateway: +# - GW: "1.2.3.4" +# Networks: +# - Network: "10.1.1.0/24" +# Name: "Net 10.1.1.0-24" +# - Network: "10.1.2.0/24" +# Name: "Net 10.1.2.0-24" +# - GW: "2.3.4.5" +# Networks: +# - Network: "10.2.1.0/24" +# Name: "10.2.1.0-24" +# - Network: "10.2.2.0/24" +# Name: "10.2.2.0-24" +import yaml, requests, json +with open ("StaticRoutes.yml") as file1: + config = yaml.load (file1) +url = "https://dashboard.meraki.com/api/v0/networks/%s/staticRoutes" % config["NetworkID"] +headers = { + 'X-Cisco-Meraki-API-Key': "%s" %config["API_Key"], + 'Content-Type': "application/json", + 'Cache-Control': "no-cache", + } +for gateway in config["Gateway"]: + GatewayIP=gateway["GW"] + for network in gateway["Networks"]: + payload = { + "name" : network["Name"], + "subnet": network["Network"], + "gatewayIp": gateway["GW"], + "enabled":"true" + } + response = requests.request("POST", url, data=json.dumps(payload), headers=headers) + print(response.status_code, response.text) \ No newline at end of file diff --git a/README.md b/README.md index 7974ea8..f7e0520 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Files contained in this repository: **Installing Python on Windows.txt:** General info for installing Python 3 on Windows +**AddStaticRoute.py:** This simple script reads a list of static routes from a YAML file and adds them to a Network. + **copymxvlans.py:** This script can be used to export MX VLAN configuration of a source org to a file and import it to a destination org. The script will look for the exact same network names as they were in the source org. Use copynetworks.py and movedevices.py to migrate networks and devices if needed. **copynetworks.py:** Copies networks and their base attributes from one organization to another. Does not move devices over or copy individual device configuration. Combined networks will be copied as "wireless switch appliance". diff --git a/meraki-export.py b/meraki-export.py new file mode 100755 index 0000000..2e7c3b0 --- /dev/null +++ b/meraki-export.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Before running this script you need to install these three modules: +# pip install meraki yaml argparse +from meraki import meraki +import argparse +import yaml + +config={} #Define config as a dictionary +config["Organization"]={} #Define organization as a dictionary +config["Organization"]["Network"]=[] #but Network is a list +def get_org_id(apikey,orgName,suppressprint): #Turns an org name into an org ID + result = meraki.myorgaccess(apikey, suppressprint) + for row in result: + if row['name'] == orgName: + return row['id'] + + raise ValueError('The organization name does not exist') + +def admins(apikey, orgid, suppressprint): # Retrieves a list of admins + myOrgAdmins=meraki.getorgadmins(apikey, orgid, suppressprint) + config["Organization"]["Admins"]=myOrgAdmins + print("Got admins") + +def mx_l3_fw_rules(apikey,networkid,suppressprint): #Retrieves the Layer 3 firewall rules on the MX + myRules=meraki.getmxl3fwrules(apikey, networkid, suppressprint)[0:-1] + network["L3-Firewall-Rules"]=myRules + print("Got Layer 3 firewall rules") + +def mx_cellular_fw_rules(apikey,networkid,suppressprint): # Retrieves the mobile firewall rules + myRules=meraki.getmxcellularfwrules(apikey, networkid, suppressprint)[0:-1] + network["Cell-Firewall-Rules"]=myRules + print("Got mobile firewall rules") + +def mx_vpn_fw_rules(apikey,orgid,suppressprint): # Retrieves the VPN firewall rules + myRules=meraki.getmxvpnfwrules(apikey, orgid, suppressprint)[0:-1] + config["Organization"]["MX-VPN-Firewall-Rules"]=myRules + print("Got VPN firewall rules") + +def vpn_settings(apikey,networkid,suppressprint): # Retrieves Meraki S2S VPN settings + myVPN=meraki.getvpnsettings(apikey, networkid, suppressprint) + network["VPN-Settings"]=myVPN + print("Got VPN settings") + +def snmp_settings(apikey,orgid,suppressprint): # Retrieves SNMP settings + mySNMP=meraki.getsnmpsettings(apikey, orgid, suppressprint) + config["Organization"]["SNMP"]=mySNMP + print("Got SNMP settings") + +def non_meraki_vpn_peers(apikey,orgid,suppressprint): # Retrieves non-Meraki site-to-site + myPeers=meraki.getnonmerakivpnpeers(apikey,orgid,suppressprint) + config["Organization"]["Non-Meraki-VPN"]=myPeers + print("Got non-Meraki VPN peers") + +def static_routes(apikey,networkid,suppressprint): # Retrieve any static routes + myRoutes=meraki.getstaticroutes(apikey,networkid,suppressprint) + if myRoutes is None: + return + network["Routes"]=myRoutes + print("Got static routes") + +def ssid_settings(apikey,networkid,suppressprint): # Retrieve all SSID settings + mySSIDs=meraki.getssids(apikey, networkid, suppressprint) + if mySSIDs is None: + return + for row in mySSIDs: + myRules=meraki.getssidl3fwrules(apikey, networkid, row['number'], suppressprint)[0:-2] + row["rules"]=myRules + network["SSID"].append(row) + print("Got SSID "+str(row["number"])) +#################################################### +# Main program +# ################################################## +parser = argparse.ArgumentParser(description='Backup a Meraki config to an offline file.') +parser.add_argument('-v', help='Enable verbose mode',action='store_true') +parser.add_argument('apiKey', help='The API Key') +parser.add_argument('orgName', help='The name of a Meraki organisation') +args = parser.parse_args() # Defines arguments passed on the command line when running program + +suppressprint=True +if args.v: + suppressprint=False + +apikey=args.apiKey +orgid=get_org_id(apikey,args.orgName,suppressprint) +file="%s.yml"%args.orgName # set the filename from the network name +config["Organization"]["Name"]=args.orgName +config["Organization"]["ID"]=orgid +admins(apikey, orgid, suppressprint) +mx_vpn_fw_rules(apikey,orgid,suppressprint) +snmp_settings(apikey,orgid,suppressprint) +non_meraki_vpn_peers(apikey,orgid,suppressprint) +myNetworks = meraki.getnetworklist(apikey, orgid, None, suppressprint) +for row in myNetworks: # Iterate through the networks in the org + tags=row['tags'] + if tags == None: + tags = "" + networkType=row['type'] + if networkType == 'combined': # Combined is not valid to upload! + networkType = 'wireless switch appliance phone' + if networkType == 'systems manager': # We don't care about MDM networks + continue + print("Processing network "+row['name']) + network={"name": row["name"], "networkType": networkType, "tags": tags, "timeZone":row["timeZone"]} + mx_cellular_fw_rules(apikey,row['id'],suppressprint) + mx_l3_fw_rules(apikey,row['id'],suppressprint) + vpn_settings(apikey,row['id'],suppressprint) + static_routes(apikey,row["id"],suppressprint) + network["SSID"]=[] + ssid_settings(apikey,row['id'],suppressprint) + config["Organization"]["Network"].append(network) +with open(file, 'w') as file: # open the file we defined earlier to write to + file.write("---\n") + file.write(yaml.dump(config)) # convert the config dict to yaml and save + file.flush() + file.close() \ No newline at end of file