Relentless Relentless - 2 months ago 10
JSON Question

Updating already existing json file python

I have a json file and I want to update 'filename' field with the filenames I scp from a remote server. I am pretty new to python but learning as I go.

JSON file:

{"path":"/home/Document/Python",
"md5s":[{"filename":"",
"md5":"",
"timestamp":""},
{"filename":"",
"md5":"",
"timestamp":""},
{"filename":"",
"md5":"",
"timestamp":""}
]}


My python code so far:

def filemd5():
try:
config = json.load(open(config_file))
#print(str(json.dumps(config, indent=4)))
for server in config['servers']:
ssh = SSHClient()
ssh.load_system_host_keys()

ssh.connect(server['ip'], username=server['username'],
password=server['password'])
#print(str(server))
print('Connecting to servers')
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('ls /tmp/')
error = str(ssh_stderr.read())
if len(error) ==0:
for files in config['servers']:
filename = file_location + server['file']
scp = SCPClient(ssh.get_transport())
scp.get(filename)
if os.path.isfile(server['file']):
updateJsonFile(filename)
print(filename)
else:
print('KO')

def updateJsonFile(filename):
with open('md5.json', 'r') as f:
data = json.load(f)

subdata = data['md5s']
for check in subdata:
check["filename"] = filename

with open('md5.json', 'w') as f:
f.write(json.dumps(data))

filemd5()


Formatting has not really came out well here but I am nearly sure it is good in my python script.
What is happening now is that it populates all fields 'filename' with the same file when I am SCP three files from different servers.

Any help would be great. Thanks.

EDIT(updated question as adding to file works but it fills all values with same filename.

Expected result:

{"path":"/home/Document/Python",
"md5s":[{"filename":"text1.txt",
"md5":"",
"timestamp":""},
{"filename":"text2.txt",
"md5":"",
"timestamp":""},
{"filename":"text3.txt",
"md5":"",
"timestamp":""}
]}


Actual:

{"path":"/home/Document/Python",
"md5s":[{"filename":"text1.txt",
"md5":"",
"timestamp":""},
{"filename":"text1.txt",
"md5":"",
"timestamp":""},
{"filename":"text1.txt",
"md5":"",
"timestamp":""}
]}}

Answer

This is as close as I can come to sorting the code for you. I don't know why you get KeyError but you didn't implement a counter as suggested in the comments. Since I don't have access to config['servers'], the counter might be in the wrong place, in which case put it in the inner for loop. I tested this on your json string and it does work as you intended so the principle is correct, you just have to make sure you pass the desired values for counter.

def filemd5():
    try:
        config = json.load(open(config_file))

        counter = 0 # Add a counter here
        for server in config['servers']:
            ssh = SSHClient() 
            ssh.load_system_host_keys()

            ssh.connect(server['ip'], username=server['username'], 
                            password=server['password'])

            print('Connecting to servers')
            ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('ls /tmp/')
            error = str(ssh_stderr.read())
            if not error: 
                for files in config['servers']: 
                    filename = file_location + server['file']
                    scp = SCPClient(ssh.get_transport())
                    scp.get(filename)
                if os.path.isfile(server['file']):
                    updateJsonFile(filename, counter)
                    counter += 1 # increment the counter
                    print(filename)
                else:
                    print('KO')
    except:
        # I don't understand why you don't get an error for missing except?
        pass  

def updateJsonFile(filename, counter):
    with open('md5.json', 'r') as f:
        data = json.load(f)

    subdata = data['md5s']
    # The code below would update every value since you loop through whole list
    #for check in subdata:
    #   check["filename"] = filename
    subdata[counter]['filename'] = filename

    with open('md5.json', 'w') as f:
        f.write(json.dumps(data))