The objective of this code is to contact a server with a reporting API and run the specified report from the user generated configuration file, once the report has been requested to server responds with a job id for the requested report. The code takes the job id, sends another API call with the specified id to retrieve the generated report in XML format and save to file. If there are multiple configuration files it will iterate though the files. https://github.com/Marct27/PAN_reporter

This is my first Python project, I have no formal coding experience. The script works as intended but I would like to understand if I am using the functions optimally there are sections of code specifically relating to calling the url and parsing the resultant xml which are repeated but there are subtle changes in the way it requests the url. Also would like understand if there are inefficiencies that could be improved on.

import urllib.request
import urllib.error
import urllib.parse
import ssl
import xml.etree.ElementTree as ET
import json
import time
import os
import glob

# Workaround for self signed cerificates
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
rootdir = os.getcwd()

def parseXML(arg1, arg2, arg3):
    req = urllib.request.Request(
                                host+arg3, data=None,
                                headers={"Accept": "application/xml"})
    resp = urllib.request.urlopen(req, context=ctx)
# Parse xml and get root key value
    tree = ET.parse(resp)
    root = tree.getroot()
    # From return xml find job id of report
    j = root.find(arg1)
    return j.find(arg2)

def urlRequest(arg1):
    # Request url and open
    req = urllib.request.Request(
                                host+arg1, data=None,
                                headers={"Accept": "application/xml"})
    return urllib.request.urlopen(req, context=ctx)

for config in glob.glob("*.conf"):  # Read configs from directory
    # if config.endswith(".conf"):
    with open(config) as json_data_file:
        cfg = json.load(json_data_file)

    # Define local variables from config file
    path = os.path.join(cfg['save_folder'], cfg['customer_folder'], cfg['report_folder'])
    host = 'https://'+cfg['fw']['host']
    apiKey = cfg['fw']['apiKey']
    reports = cfg['fw']['reports']['reportName']
    vsys = cfg['fw']['vsys']
    custom = cfg['fw']['custom_reports']['required']
    custom_reports = cfg['fw']['custom_reports']['reports']
    operational = cfg['fw']['operational_reports']['required']
    operational_reports = cfg['fw']['operational_reports']['reports']
    rname = {}

    if not os.path.exists(path):

    print('Generating Report Jobs for {}'.format(config))

    # Loop through reports
    for i in reports:
        if vsys == "": # Verify if a vsys is required
            apiRunReport = '/api/?type=report&async=yes&reporttype=custom&reportname=%s&key=%s' % (i, apiKey)
            apiRunReport = '/api/?type=report&async=yes&reporttype=custom&vsys=%s&reportname=%s&key=%s' % (vsys, i, apiKey)
        jID = parseXML('result', 'job', apiRunReport)
        rname[i] = jID.text

    if custom == "yes":
        for i, v in custom_reports.items():
            uri = urllib.parse.quote(v,safe='/', encoding='utf-8', errors=None)
            customRunReport = '/api/?type=report&async=yes&reporttype=dynamic&reportname=custom-dynamic-report&cmd=%s&key=%s' % (uri, apiKey)
            jID = parseXML('result', 'job', customRunReport)
            rname[i] = jID.text

    if operational == "yes":
        for i, v in operational_reports.items():
            print('Writing operations report - {}'.format(i))
            operationRunReport = '%s&key=%s' % (v, apiKey)
            resp = urlRequest(operationRunReport)
            tree = ET.parse(resp)
            fpath = os.path.basename(os.getcwd())
            reportdir = os.path.join(path, '{}-{}.xml'.format(i, fpath))

    for i, v in rname.items():
        state = ""
        while state != 'FIN':
        # From xml get job status
            apiPullReport = '/api/?type=report&action=get&job-id=%s&key=%s' % (v, apiKey)
            # print(apiPullReport)
            resp = urlRequest(apiPullReport)
            tree = ET.parse(resp)
            root = tree.getroot()
            for s in root.iter('status'):
                state = s.text
            if state != 'FIN':
                print('Job status: {} retry in 5 sec'.format(s.text))
                # Write report to file
                    "Writing to file: Job# {} for report : {} - Status: {}".format
                    (jID.text, i, s.text))
                fpath = os.path.basename(os.getcwd())
                reportdir = os.path.join(path, '{}-{}.xml'.format(i, fpath))

print("FINISHED !!")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.