Wednesday, June 19, 2019

Meraki Action Batches in Action

As promised in the previous post, here's a quick sample Action Batches script.

I've actually got two for you. Both scripts create two new networks, and then create five VLANs inside those two networks. The script 'example1.py' creates all of this using individual API calls for each create action. The 'example2.py' script uses action batches instead of individual API calls.

For fun I'm also using timeit to compare how long each script takes to do the same thing.

Let's jump right to the Owen Wilson "Wow" part of this and show the run times for the two scripts:


That's an over 50% reduction in running time to perform the exact same actions!

Not shown in that example is me going into my Org in the Dashboard and deleting the networks after I ran example1.py. You'll see below that they create the same networks, and the same VLANs in those networks, and there's no error checking whatsoever. If I hadn't deleted the networks after the first run the second script would have thrown an error out since everything already existed.

Now, API calls vary quite a bit in time to return, so YMMV on the times you see, but I am very comfortable saying that by using Action Batches there's significant time to be saved. Well done Meraki! This will only get better as they make more API endpoints available for Action Batches.

To close out, below are the two scripts I used in this example. Feel free to run your own comparisons!

One day I'll figure out how to GitHub... But until then...

Here is example1.py:

#!/usr/bin/python3

import requests
import json
import timeit


api_key = 'your_key_goes_here'
# Note, Org ID is changing from an int to a str on Jun 24 2019
orgid = 1234567890

base_url = "https://api.meraki.com/api/v0/"

headers = {
    "X-Cisco-Meraki-API-Key": api_key,
    "Content-Type": "application/json",
}

# Network Info
site1 = {"name": "Site Number 1", "type": "appliance", "tags": "tag1 tag2", "timezone": "America/Edmonton"}
site2 = {"name": "Site Number 2", "type": "appliance", "tags": "tag1 tag2", "timezone": "America/Edmonton"}

sites = [site1, site2]

# VLAN Info
vlan100 = {"id": "100", "name": "VLAN100", "subnet": "192.168.100.0/24", "applianceIp": "192.168.100.1"}
vlan101 = {"id": "101", "name": "VLAN101", "subnet": "192.168.101.0/24", "applianceIp": "192.168.101.1"}
vlan102 = {"id": "102", "name": "VLAN102", "subnet": "192.168.102.0/24", "applianceIp": "192.168.102.1"}
vlan103 = {"id": "103", "name": "VLAN103", "subnet": "192.168.103.0/24", "applianceIp": "192.168.103.1"}
vlan104 = {"id": "104", "name": "VLAN104", "subnet": "192.168.104.0/24", "applianceIp": "192.168.104.1"}

vlans = [vlan100, vlan102, vlan102, vlan103, vlan104]


def create():
    for site in sites:
        s = requests.post(f"{base_url}organizations/{orgid}/networks", data=json.dumps(site), headers=headers)
        netid = json.loads(s.text)['id']
        ev = requests.put(f"{base_url}networks/{netid}/vlansEnabledState",
                          data=json.dumps({"enabled": True}), headers=headers)
        for vlan in vlans:
            v = requests.post(f"{base_url}/networks/{netid}/vlans", data=json.dumps(vlan), headers=headers)


if __name__ == '__main__':
    print(timeit.timeit("create()", setup="from __main__ import create", number=1))


And here is example2.py:

#!/usr/bin/python3

import requests
import json
import timeit

api_key = 'your key goes here'
# Note, Org ID is changing from an int to a str on Jun 24 2019
orgid = 1234567890

base_url = "https://api.meraki.com/api/v0/"
action_url = f"{base_url}organizations/{orgid}/actionBatches"

headers = {
    "X-Cisco-Meraki-API-Key": api_key,
    "Content-Type": "application/json",
}


def create_sites():

    payload = {
        "confirmed": True,
        "synchronous": True,
        "actions": [
            {
                "resource": f"/organizations/{orgid}/networks",
                "operation": "create",
                "body": {
                    "name": "Site Number 1",
                    "type": "appliance",
                    "tags": "tag1 tag2",
                    "timezone": "America/Edmonton"
                }
            },
            {
                "resource": f"/organizations/{orgid}/networks",
                "operation": "create",
                "body": {
                    "name": "Site Number 2",
                    "type": "appliance",
                    "tags": "tag1 tag2",
                    "timezone": "America/Edmonton"
                }
            }
        ]
    }
    r = requests.post(action_url, json=payload, headers=headers)


def create_vlans():

    r = requests.get(f"{base_url}organizations/{orgid}/networks", headers=headers)
    netlist = json.loads(r.text)

    for net in netlist:
        if "Site Number" in net['name']:
            netid = net['id']
            ev = requests.put(f"{base_url}networks/{netid}/vlansEnabledState",
                              data=json.dumps({"enabled": True}), headers=headers)

            payload = {
                "confirmed": True,
                "synchronous": True,
                "actions": [
                    {
                        "resource": f"/networks/{netid}/vlans",
                        "operation": "create",
                        "body": {
                            "id": "100",
                            "name": "VLAN100",
                            "subnet": "192.168.100.0/24",
                            "applianceIp": "192.168.100.1"
                        }
                    },
                    {
                        "resource": f"/networks/{netid}/vlans",
                        "operation": "create",
                        "body": {
                            "id": "101",
                            "name": "VLAN101",
                            "subnet": "192.168.101.0/24",
                            "applianceIp": "192.168.101.1"
                        }
                    },
                    {
                        "resource": f"/networks/{netid}/vlans",
                        "operation": "create",
                        "body": {
                            "id": "102",
                            "name": "VLAN102",
                            "subnet": "192.168.102.0/24",
                            "applianceIp": "192.168.102.1"
                        }
                    },
                    {
                        "resource": f"/networks/{netid}/vlans",
                        "operation": "create",
                        "body": {
                            "id": "103",
                            "name": "VLAN103",
                            "subnet": "192.168.103.0/24",
                            "applianceIp": "192.168.103.1"
                        }
                    },
                ]
            }
            r = requests.post(action_url, json=payload, headers=headers)


def create():
    create_sites()
    create_vlans()


if __name__ == '__main__':
    print(timeit.timeit("create()", setup="from __main__ import create", number=1))

No comments:

Post a Comment