Example: Meraki - Control Device Policy via Exec and Python

This is a near identical guide to the awesome work of @Gordon_Geist I have used the same text as the original and only changed bits I needed to.

I couldnt quite get the original tutorial to work, so I had a go at it and I have made some adjustments and tuning of the same solution

  • This is just for device policies

  • Uses Python instead of BASH

  • It uses just one exec binding thing

  • It supports passing mac addresses and policies

  • It supports standard policies (normal,blocked,whitelisted)

  • I used the Meraki API namespace instead of dashboard

My use case is:

  1. Allow my wife/rules to turn off streaming content and similar when our kids should get back to the real world
  2. set up Cron rules to change policies based on time of day - Meraki only allows you to set a “day” period meaning if I block the kids at 10.30pm - 11:59pm, at midnight they can get back up and go nuts on youtube till 10.30pm the next day

You should know how to manipulate your linux environment and secure your installation along with good RBAC controls to your configs.

DevicePolicy.items

  • Create items to manipulate/display in the sitemap.
//Device Policy
String	Policy_Jackson	"Jackson Laptop"
String	Policy_Hamish	"Hamish Laptop"

Things
I do all my things in PaperUI, so add a new Command thing from the exec binding

Exec.items

  • Maraki has three default policies Normal, Blocked and Whitelisted then your group policies are exposed in order of creation by 102,103, etc - u can find the # of your policy by editing the policy within the Meraki portal and looking at the url in your browser:
//Device Policy change
String     ExecMerakiDevicePolicyChange_Output          "Output"           {channel="exec:command:ExecMerakiDevicePolicyChange:output"}
String     ExecMerakiDevicePolicyChange_Input           "Input"            {channel="exec:command:ExecMerakiDevicePolicyChange:input"}
Number     ExecMerakiDevicePolicyChange_Exit            "Exit Value"       {channel="exec:command:ExecMerakiDevicePolicyChange:exit"}
Switch     ExecMerakiDevicePolicyChange_Run             "Running"          {channel="exec:command:ExecMerakiDevicePolicyChange:run"}
DateTime   ExecMerakiDevicePolicyChange_Lastexecution   "Last Execution"   {channel="exec:command:ExecMerakiDevicePolicyChange:lastexecution"}

Devicepolicy.rules

  • Rules to implement changes when a new policy is selected via the sitemap. This could be shortened by the bash script using multiple variables but just havent gotten around to changing it (hint hint)
  • MAC address substituted here for each device you want to control by policy. MAC is right there in the Meraki portal -copy paste
    note the sendCommand the format is macaddress|policy The exec binding only supports sending one parameter so I seperate with a pipe and split it in the receiving script
////////////////////
//Policy_Jackson
/////////////////////
rule "Policy_Jackson Actions"
	when Item Policy_Jackson changed
	then
		if (Policy_Jackson.state == "norm") {
			ExecMerakiDevicePolicyChange_Input.sendCommand("ff:ff:ff:ff:ff:ff|Normal")
			ExecMerakiDevicePolicyChange_Run.sendCommand(ON)
			}
		if (Policy_Jackson.state == "block") {
			ExecMerakiDevicePolicyChange_Input.sendCommand("ff:ff:ff:ff:ff:ff|Blocked")
			ExecMerakiDevicePolicyChange_Run.sendCommand(ON)
			}
		if (Policy_Jackson.state == "white") {
			ExecMerakiDevicePolicyChange_Input.sendCommand("ff:ff:ff:ff:ff:ff|Whitelisted")
			ExecMerakiDevicePolicyChange_Run.sendCommand(ON)
			}	
		if (Policy_Jackson.state == "p_103") { 
			ExecMerakiDevicePolicyChange_Input.sendCommand("ff:ff:ff:ff:ff:ff|103")
			ExecMerakiDevicePolicyChange_Run.sendCommand(ON)
			}
		if (Policy_Jackson.state == "p_104") { 
			ExecMerakiDevicePolicyChange_Input.sendCommand("ff:ff:ff:ff:ff:ff|104")
			ExecMerakiDevicePolicyChange_Run.sendCommand(ON)
			}
		
end
//rinse repeat for all devices

Home.sitemap

  • Simple to make this pin code protected but thats out of scope here
			Group item=Device_Policy_Group {
				Switch item=Policy_Jackson mappings=[norm="Norm",block="Block",white="White",p_103="No Youtube",p_104="Homework"]
				}

Python script

  • The exec item sends the MAC address and policy as the variable
  • < NetworkID > is your Network ID that contains the Meraki devices you are managing.Read the Meraki API manual
  • <api_key> is the unique api-key for your organization and received after you apply for api access. Consider this as important as securing your root access password i.e. where the script is and the users/groups that can read.
  • You just need to change these two variables and the rest is taken care of
  • I found the application postman really useful to find out how to get the script to work (and better debugging - this application also allows you to export as various formats.
    Postman application
    Postman Meraki Collection

meraki1.py

import requests, sys

strMacaddress,strPolicy = sys.argv[1].split("|")
strNetworkID = "<NetworkID>"
strAPIKey = "<api_key>"

url = "https://api.meraki.com/api/v0/networks/" + strNetworkID + "/clients/" + strMacaddress +"/policy"
headers = {
    'Content-Type': "application/json",
    'X-Cisco-Meraki-API-Key': "" + strAPIKey + "",
    }

if strPolicy == "Normal" or strPolicy == "Blocked" or strPolicy == "Whitelisted":
    payload = "{\n    \"devicePolicy\": \"" + strPolicy + "\"\n}"
else:
    payload = "{\n    \"devicePolicy\": \"group\",\n    \"type\": \"Group policy\",\n    \"groupPolicyId\": \"" + strPolicy + "\"\n}"

response = requests.request("PUT", url, data=payload, headers=headers)
3 Likes

You should try HABApp, you can create a Rule which listens directly to the your items and then issue the according request.

The new rule engine and scripted automation with Jython would work too.

I added a PIN for the sitemap