API - Network Combine array error

Solved
MaCATTEAU
Here to help

API - Network Combine array error

Hi,

 

I'm try to combine networks with the Network Combine API. I put the name of the combined network, the ids of networks, but the API send me an error : "'networkIds' must be an array", but for me it's already an array. Someone have an idea to help me with this ? 

 

This is my request body : 

{
    "name": "Test_SW_MX",
    "networkIds": [
    "N_691865492755826821", 
    "N_691865492765826857"
    ]
}
 
And this the error : 
{
"errors": [
"'networkIds' must be an array"
]
}
 
I use this API "/organizations/{organizationId}/networks/combine"
 
Thanks for your response,
1 Accepted Solution
BrechtSchamp
Kind of a big deal

I believe the cause of the problem is your header "application.json". Try changing it to "application/json".

 

Fyi, these are the headers I use:

headers = {
        'Accept': "*/*",
        'Content-Type': "application/json",
        'cache-control': "no-cache",
        'X-Cisco-Meraki-API-Key': api_key
    }

 

View solution in original post

14 Replies 14
BrechtSchamp
Kind of a big deal

What kind of networks are those? The reason I ask is because of this note:

Only one network of each type can be combined. For example, multiple wireless networks cannot be combined with other networks. An administrator would need to move all wireless devices into a single wireless network prior to the combination. The same applies for multiple switch networks, all devices would need to be moved into a single switch network. Only one MX can be added to a Combined network. 

At this time, VPN Concentrators cannot be added to a combined Dashboard network

 

Source: https://documentation.meraki.com/zGeneral_Administration/Organizations_and_Networks/Combined_Dashboa...

 

I just tested combining a switch and a wireless network with that API in postman and it worked fine for me. The body syntax was identical to yours.

MaCATTEAU
Here to help

I combined an MX with a switch network, the two are bound on a template. one MX and 1 switch.

 

When i combined the network with the dashboard GUI, it's work.

 

 

BrechtSchamp
Kind of a big deal

Okay, I just tested combining a switch network and an mx network via API and it worked. Both were bound to the same template.

 

Are you using postman or something else?

MaCATTEAU
Here to help

I'm using Postman for troubleshoot. Initially, i call the API in a Python script

 

I don't understand where is the problem with my 'networkIds'...

 

BrechtSchamp
Kind of a big deal

I don't understand either, seems fine. If you share your code I can give it a test here.

MaCATTEAU
Here to help

Python functions : 

 

def combine_networks(mx_networkid,temp_networkid):
params_combine = {"name" : mx_network_name,
"networkIds" : [mx_networkid,temp_networkid]
}
api_path_combine = "organizations/" + OrgID + "/networks/combine"
url_combine = serveur + api_path_combine
r_combine = requests.request("POST", url_combine, headers=headers, params=params_combine)
print ("les network sont combines")
print (r_combine)
return;

 

and the Postman URL : 

{{baseUrl}}/organizations/{{organizationId}}/networks/combine?name =MAG&networkIds= ['N_691865492754826821' , 'N_691865492754826857']

 

 

Thanks for your help

 

CBurkhead
Building a reputation

That is the same error I have been seeing using a different endpoint (/networks/{networkId}/events) for the includedEventTypes parameter. No matter how I specify the data, I am told that that it must be an array. Hopefully, the answer for this problem will be the same for this other endpoint.

BrechtSchamp
Kind of a big deal

Okay, there's two things wrong with your code.

 

You haven't json dumped your data payload.

 

And you named your payload "params" instead of "data".

 

This is the working code:

 

 

def combine_networks(mx_networkid, temp_networkid):
    params_combine = {
        "name": mx_network_name,
        "networkIds": [
            mx_networkid,
            temp_networkid ]
    }

    params_json  = json.dumps(params_combine)

    api_path_combine = "organizations/" + OrgID + "/networks/combine"
    url_combine = serveur + api_path_combine

    r_combine = requests.request("POST", url_combine, headers=headers, data=params_json)

    print(str(r_combine.status_code) + " - " + r_combine.text)
    return r_combine.status_code

 

 

I removed the print("les networks sont combines") line because it's actually not true. Whether or not the networks have succesfully combined depends on whether the call was successful or not. If r_combine.status_code equals 200 then it was successful. So perhaps you can return that value, or evaluate it in your function and return 1 or 0 based on the result.

MaCATTEAU
Here to help

Thank you a lot for your correction on my code, it's still on draft phase

 

I don't json dumped my data on the other API call i do,

 

if i json dumped my data payload with keyword "data" i receive : 

400 - {"errors":["The following required parameters are missing: 'name' and 'networkIds'"]}

print (params_json) : {"name": "5895", "networkIds": ["N_691865492754826870", "N_691865492754826891"]}

 

If i keep the json but with "params" keyword, same error

 

I use python 3.7.0 on Windows, requests 2.21.0

 

Thanks

 

 

BrechtSchamp
Kind of a big deal

Hmm strange. It works fine for me. Can you share your full code? I'll try to debug it again.

MaCATTEAU
Here to help

My code try to resolve a client problem : he put 1000 switchs into one network but he have already one network per site with the mx. So my code :
1 - find the mx network with the site id

2 - get the list port of the switch

3 - create a network for the switch

4 - Remove the switch of the big network

5 - put in the switch network i create

6 - Bind it to the global template (Combined template, mx network already in)

7 - Combine the two networks

8 - push the port config on switch to avoid problems on site

 

My code is still under construction, but if you find the combine problems, it's help me a lot : 

 

#Migration_Switchs_Meraki

 

import json

import sys

import requests

import csv

 

#Déclaration des variables pour l'ensemble des Requests

 

headers = {

'Content-Type' : 'application.json',

'X-Cisco-Meraki-API-Key': "*"

}

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

 

#Déclaration des variables globales

OrgID = "*"

switch_networkid = "N_69186549275482820"

switch_info = []

 

 

#Récupération des informations de l'inventaire

with open('inventory.csv') as csvfile:

inventory = csv.reader(csvfile, delimiter=',')

for line in inventory:

info = {

"serial" : line[1],

"name" : line[7],

}

switch_info.append(info)

csvfile.close()

del switch_info[0]

 

#récupération_des_premiers_caractères_du nom

#print (switch_info[0]['name'][:4])

 

#Récupération des networks pour recherche du network MX Magasin

 

api_path_mx_network = "organizations/" + OrgID + "/networks"

url_mx_network = serveur + api_path_mx_network

mx_networks = requests.request("GET", url_mx_network, headers=headers)

if mx_networks.status_code == 200:

print ("Liste des reseaux : [OK]")

else:

print ("Liste des reseaux : [NOK]")

sys.exit()

networks_data = mx_networks.json()

 

#Départ de déclaration des fonctions

 

#Fonction de recherche de l'ID Site dans les noms de Network Meraki MX

 

def find_mx_network(mag_id):

for n in networks_data:

if mag_id in n['name']:

mx_networkid = n['id']

templateid = n['configTemplateId']

print ("Le nom du réseau MX Magasin : " + n['name'])

break




return mx_networkid,templateid;

 

#Fonction de listing de configuration des ports du switch migré

 

def listport(switch_serial):

api_path_list_port = "devices/" + str(switch_serial) + "/switchPorts"

url_list_port = serveur + api_path_list_port

s_list_port = requests.request("GET", url_list_port, headers=headers)

if s_list_port.status_code == 200:

print ("Liste des ports switch : [OK]")

else:

sys.exit()

s_list_port_data = s_list_port.json()

return s_list_port_data;

 

#Fonction de création du network temporaire du switch migré

 

def create_network(switch_id_name):

params_create_net = {"name" : switch_id_name,

"type" : "switch",

"timeZone" : "Europe/Paris"

}

api_path_cnet = "organizations/" + OrgID + "/networks"

url_cnet = serveur + api_path_cnet

cnet = requests.request("POST", url_cnet, headers=headers, params=params_create_net)

if cnet.status_code == 201:

print ("Creation network temporaire : [OK]")

else:

print ("Creation network temporaire : [NOK]")

sys.exit()

cnet_data = cnet.json()

return cnet_data;

 

#Fonction de suppression du switch du network SWITCH

 

def remove_switch(switch_serial):

api_path_remove = "networks/" + switch_networkid + "/devices/" + switch_serial + "/remove"

url_remove = serveur + api_path_remove

r_remove_switch = requests.request("POST", url_remove, headers=headers)

print ("le switch est supprimé du network global")

print (r_remove_switch)

return;

 

#Fonction d'ajout dans le network temporaire

 

def add_switch(temp_networkid,switch_serial):

params_addswitch = {"serial" : switch_serial}

api_path_addswitch = "networks/" + temp_networkid + "/devices/claim"

url_add = serveur + api_path_addswitch

r_add_switch = requests.request("POST", url_add, headers=headers, params=params_addswitch)

print ("le switch est ajoute au network temporaire")

print (r_add_switch)

return;

 

#Fonction de liaison du network temporaire avec le template global

 

def Template_bind(templateid, networkid):

params_btemp = {"configTemplateId" : templateid,

"autoBind": "True"

}

api_path_btemp = "networks/" + networkid + "/bind"

url_btemp = serveur + api_path_btemp

btemp = requests.request("POST", url_btemp, headers=headers, params=params_btemp)

print ("le reseau temporaire est binde :")

print (btemp)

return;

 

#Fonction de combinaison du network temporaire avec le network MX

 

def combine_networks(mx_networkid,temp_networkid,dest_network_name):

params_combine = {"name" : dest_network_name,

"networkIds" : [

mx_networkid,

temp_networkid

]

}

params_combine_json = json.dumps(params_combine)




api_path_combine = "organizations/" + OrgID + "/networks/combine"

url_combine = serveur + api_path_combine

r_combine = requests.request("POST", url_combine, headers=headers, data=params_combine_json)

print(str(r_combine.status_code) + " - " + r_combine.text)

return r_combine.status_code;




#Ajout de la config initial au switch migré

 

def update_config(list_port,switch_serial):

for p in list_port:

api_path_update_config = "devices/" + switch_serial + "/switchPorts/" + str(p['number'])

url_update_config = serveur + api_path_update_config

params_update_config = {"name" : p['name'],

"tags" : p['tags'],

"enabled" : p['enabled'],

"type" : p['type'],

"vlan" : p['vlan'],

"voiceVlan" : p['voiceVlan'],

"allowedVlans" : p['allowedVlans'],

"poeEnabled" : p['poeEnabled'],

"isolationEnabled" : p['isolationEnabled'],

"rstpEnabled" : p['rstpEnabled'],

"stpGuard" : p['stpGuard'],

"accessPolicyNumber" : p['accessPolicyNumber'],

"linkNegotiation" : p['linkNegotiation'],

"portScheduleId" : p['portScheduleId'],

"udld" : p['udld'],

"macWhitelist" : p['macWhitelist'],

"stickyMacWhitelist" : p['stickyMacWhitelist'],

"stickyMacWhitelistLimit" : p['stickyMacWhitelistLimit']

}

r_update = requests.request("PUT", url_update_config, headers=headers, params=params_update_config)

print ("Interface " + str(p['number']) + " est mise à jour")

print (r_update)

return;




for device in switch_info:

mag_id = device['name'][:4]




dest_network_name = mag_id + "-Magasins"




#récupération de l'ID du network MX

mx_networkid, templateid = find_mx_network(mag_id)




#Stockage de la liste des ports actuelle

list_port = listport(device['serial'])

#

#Création du network temporaire

cnet_data = create_network(mag_id)

#

#Récupération de l'ID

temp_networkid = cnet_data['id']

#

#Suppression du switch d'un network

remove_switch(device['serial'])

#

#Ajout du switch au network temporaire

add_switch(temp_networkid,device['serial'])

#

#Liaison au template global

Template_bind(templateid, temp_networkid)

#

#Combinaison des réseaux

combine_networks(mx_networkid,temp_networkid,dest_network_name)

#

#Update de la config de ports

update_config(list_port,device['serial'])

 

Thanks, 

 

BrechtSchamp
Kind of a big deal

I believe the cause of the problem is your header "application.json". Try changing it to "application/json".

 

Fyi, these are the headers I use:

headers = {
        'Accept': "*/*",
        'Content-Type': "application/json",
        'cache-control': "no-cache",
        'X-Cisco-Meraki-API-Key': api_key
    }

 

MaCATTEAU
Here to help

Thanks !!!!

 

All of that for a little "/",  thank you !

Nash
Kind of a big deal


@MaCATTEAU wrote:

Thanks !!!!

 

All of that for a little "/",  thank you !


It's always that missing or wrong punctuation that gets you. My particular nemesis is using greater than instead of less than. 🙂

Get notified when there are additional replies to this discussion.