Appending lists and dictionaries

Hello, new to python and coding in general and need some help please :slight_smile:

I am trying to write a Meraki API script to add a new firewall rule to a network.

I first GET the existing rules and save the response (json) into “existingrules” which I think is a list?

I then create a new list for the new rule I want to add “newrule” and try to append it.

Problem is my new rule isnt actually a list, its a dictionary.

The reason its a dictionary is that I had a problem earlier with the script and it was fixed by changing the “newrule” into a dictionary. I got the syntax from a meraki API dashboard example.

any idea what I can do? or if im just looking at it the wrong way?

cheers,

import requests
import security
import json


api_key = security.MERAKI_API_KEY
organizationId = security.ORG_ID
network_id = "xxxxxxxxxxxxxxxxxxxxxx"


# API endpoint to add firewall rule
url = f"https://api.meraki.com/api/v1/networks/{network_id}/appliance/firewall/l3FirewallRules"


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

# Make POST request to add firewall rule
response = requests.get(url, headers=headers, verify=False)

existingrules = response.json()

print(response.status_code)
print(response.text.encode('utf8'))

with open('ExistingRules.json', 'w') as json_file:
    json.dump(response.json(), json_file, indent=4)


newrule = '''{
    "rules": [
        {
            "comment": "Test RuleNEW.",
            "policy": "deny",
            "protocol": "any",
            "destPort": "any",
            "destCidr": "192.200.1.0/24",
            "srcPort": "Any",
            "srcCidr": "Any",
            "syslogEnabled": false
        }
    ]
}'''

existingrules.append(newrule)

response = requests.put(url, headers=headers, json=existingrules, verify=False)

cheers, I was confused why the text was all differnet sizes lol

Hello,

Thanks for your reply. The dump to file of the json is because i need a record of what the existing rules are before the code changes them.

“you need to create a new dictionary for the new rule”

isnt that what my existing code does?
newrule = '''{ "rules": [ { "comment": "Test RuleNEW.", "policy": "deny", "protocol": "any", "destPort": "any", "destCidr": "192.200.1.0/24", "srcPort": "Any", "srcCidr": "Any", "syslogEnabled": false } ] }'''

“append new rule inside the dictionary.”

something like this?
existingrules["rules"].append(newrule)

thanks!

I’m just getting a clearer picture of this issue :stuck_out_tongue:

would it make sense if, after I dump the jason but before I define the new rule, I convert the json into a dictionary with "existingrule = json.loads(response.text) ?

that way I can add the new rule dictionary to it ? although Im not entirely sure of the syntax of that - the example I can find seem to be about adding a single keypair to the dictionary, rather than nesting a whole other dictionary into the first.

minor break through - I have successfully combined the dictionaries but I don’t think its in a format that is compatible with the put request -

import requests
import security
import json


api_key = security.MERAKI_API_KEY
organizationId = security.ORG_ID
network_id = "xxxxxxxxxxxxxxxx"


# API endpoint to add firewall rule
url = f"https://api.meraki.com/api/v1/networks/{network_id}/appliance/firewall/l3FirewallRules"


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

# Make GET request to get existing rule list
response = requests.get(url, headers=headers, verify=False)

# The response contains nested "rules" lists. This bit on the end stops an unnessary layer of nesting.
existingrules = response.json()["rules"]

print(response.status_code)
print(existingrules)

# Dump response to a file for reference if required later
with open('ExistingRules.json', 'w') as json_file:
    json.dump(response.json(), json_file, indent=4)


# Define new rule to be added
newrule = {
            "comment": "Test RuleNEW.",
            "policy": "deny",
            "protocol": "any",
            "destPort": "any",
            "destCidr": "192.200.1.0/24",
            "srcPort": "Any",
            "srcCidr": "Any",
            "syslogEnabled": False
        }

# Create new list by combining the other two
finalrules = existingrules + [newrule]
print(finalrules)




# Send update API call
response = requests.put(url, headers=headers, data=finalrules, verify=False)
print(response.status_code)

this generates several errors such as
line 371, in prepare self.prepare_body(data, files, json)
ValueError: too many values to unpack (expected 2)

I tried to convert finalrules to json
finalrules_json = json.dumps(finalrules)

but jst gave me a 400 error

This line was not supposed to be changed. The original line created a dictionary like you need.

This is correct.

This is not correct. newrule needs to be added to the list (named rules) in the existingrules dictionary. You need to reference this list and add a new item (newrule) to it.

Lastly, you need to convert existingrules (that now has the extra rule in the rules list back into a JSON string. You are correct about using json.dumps() but you need to pass the correct value to it.

thats done it thanks very much!!!

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.