06-20-2024 05:34 AM
We have a rather large setup with thousands of organizations (we're an ISP) and one of the challenges we encounter is adding local admins to each org. We have to do this due to the limitation of some actions that can only be done by such an admin.
We've built some automation (using python) to allow us to quickly add/remove admins to every organization, however we're struggling to find an answer to an annoying issue.
The payload is fine, the script is fine, it works for as many orgs as we can throw at it, we get 200s on most of them. Randomly though, we'll get about 70-80% of the way through and the API Endpoint will start returning 400 Bad Request with a message of:
organizations, createOrganizationAdmin - 400 Bad Request, {'errors': ['Email <omitted> is already registered with a Cisco Meraki Dashboard account. For security purposes, that user must verify their email address before administrator permissions can be granted here.']}That email does not exist in the org that returned the error, the user has already verified their email, and the weird part, if we run the script again, it works for that failed Org and then starts to fail later on in the list of orgs with the same thing. Sometimes it works flawlessly and we'll mass add the user to over 1000 orgs, other times we may get 50 orgs before it gives the 400 error.
We'd expect a 429 if it was rate-limited, and b/c each iteration of the loop uses the same payload it doesn't seem like the payload itself is bad (confirmed through debugging).
We're not really sure what the cause is here, but figured I'd throw it out into the wind and see if anybody had any thoughts.
Relevant code snippet:
# Imports
import json
import time
import asyncio
import platform
import meraki.aio
import tqdm.asyncio
from InquirerPy import inquirer
< irrelevant code omitted >
# Worker's task, done at each iteration (for each org, using the same args).
try:
response = await aiomeraki.organizations.createOrganizationAdmin(org["id"], admin_email, admin_name, org_access, tags=[])
except meraki.AsyncAPIError as error:
print(f"{org['name']}: {error}")
06-21-2024 02:20 PM
My thoughts on the best chance of getting this to work; extract out all of the organisations and then sort them by the shard.
Process them in shard order. That way you do all your changes to a single shard at a time before moving onto the next shard.
Only do the asyncio on orgs within a single shard - not across shards. So you would have a loop (non-async) looping through the shards, and then process the orgs using asyncio, wait for all the asyncio tasks to finish, and then move onto the next shard.
06-21-2024 02:43 PM
I'll have to give it a shot; seems reasonable. We do pull all orgs, but at most we only do a basic sorted list of orgs by customer type flag we have (Enterprise, SMB, etc), then iterate through that customer type. We're not taking into account any distribution of where things are today, but I do know our orgs span multiple based on just seeing the n# change in the path, so I think it makes sense.
Thank you for the direction, I'll try it next time I'm in there messing with it.
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide