I have been making a script to interact with a library I created before. I have ended up with a working script, but feel that the argparsing could be done a lot cleaner, and better.
First of all, some details about the script. These are the different processes that I try to support, using * to show it's required:
Login - target*, username*, password*
Query - target*, username*, password*, query*, starttime, endtime, discoverfields, summaryfields, fieldssummary, localsearch, searchtype, timeout, wait
Status - target*, username*, password*, status*, searchid*, wait
Histogram - target*, username*, password*, histogram*, searchid*
Drilldown - target*, username*, password*, drilldown*, searchid*, starttime, endtime
Event - target*, username*, password*, event*, searchid*, dir, fields, length, offset
Raw event - target*, username*, password*, rawevent*, searchid*, rowid*
Chart data - target*, username*, password*, chartdata*, searchid*, fields, length, offset
So my questions are these:
- Would using sub parsers be better, if so should I define the same sub parsers for each "parent" parser? So if two or more requires
searchid
then should I define it on all the parents? - Is there a better way to require to use one, and only one of the parents when running the script? So they cannot be combined, and they can't be missing.
- Is there a better way to write help for sub parsers? For example
help query starttime
. - Is using
.format
still useful in Python 3? - Currently if a parent argument is called, it will use all optional arguments in the calls, even if empty, is this okay? Or you would end up with unlimited amounts of
if
statements. - Any coding standards around parsers like this that can be followed?
Here is my code, currently print is used for output, but will support CSV and JSON in the future:
#!/usr/bin/env python3
"""Script to generate searches on the ArcSight Logger"""
import arcsightrest
import argparse
parser = argparse.ArgumentParser(description='Script used to send search '
'queries to ArcSight Logger API')
"""
Login information
"""
parser.add_argument('-t', '--target',
help='IP Address of the Loggger', required=True)
parser.add_argument('-u', '--username',
help='Username to access the logger', required=True)
parser.add_argument('-p', '--password',
help='Password to access the logger', required=True)
"""
SSL Settings
"""
parser.add_argument('-ussl', '--unsecuressl', action='store_true',
help='Disable ssl warnings', )
"""
Query settings
"""
parser.add_argument('--query',
help='Query to be used in the search')
parser.add_argument('--starttime',
help='From which time the query should look')
parser.add_argument('--endtime',
help='To which time the query should look')
parser.add_argument('--discoverfields',
help='Try to discover fields in the events found')
parser.add_argument('--summaryfields',
help='The list of fields')
parser.add_argument('--fieldssummary',
help='Use fields summary')
parser.add_argument('--localsearch',
help='Indicates the search is local only')
parser.add_argument('--searchtype',
help='Interactive search or not')
parser.add_argument('--timeout',
help='The number of milliseconds to keep the search '
'after it has finished running')
"""
Define search id if it is not a new search
"""
parser.add_argument('--searchid',
help='Search id of a currently running search')
"""
Status settings
"""
parser.add_argument('--status',
help='Status of running search')
parser.add_argument('--wait', action='store_true',
help='Wait for search to finish', )
"""
Histogram Settings
"""
parser.add_argument('--histogram',
help='Get histogram overview of specific earch')
"""
Drilldown Settings
"""
parser.add_argument('--drilldown',
help='Gets drilldown of specific search')
"""
Event Settings
"""
parser.add_argument('--event',
help='Get all information from a finished search')
parser.add_argument('--dir',
help='Sort direction based on event time')
"""
Raw Event Settings
"""
parser.add_argument('--rawevent',
help='Get the raw event results from a search')
parser.add_argument('--rowid',
help='Specific row id for the raw event')
"""
Chart Data Settings
"""
parser.add_argument('--chartdata',
help='Returns data in a chart format')
"""
Store all arguments
"""
args = (parser.parse_args())
"""
Sets the target Logger Server
"""
arcsightrest.ArcsightLogger.TARGET = args.target
"""
Gets login token from the Logger API
"""
arc = arcsightrest.ArcsightLogger(args.username, args.password,
args.unsecuressl)
"""
Checks if query is used, and starts a search
"""
if args.query:
search_id, response = arc.search(args.query, start_time=args.starttime,
end_time=args.endtime,
discover_fields=args.discoverfields,
summary_fields=args.summaryfields,
fields_summary=args.fieldssummary,
local_search=args.localsearch,
search_type=args.searchtype,
timeout=args.timeout,
)
if args.wait:
arc.wait(search_id)
if args.rawevents:
print(arc.raw_events(search_id, row_ids=args.rowids))
print(arc.events(search_id, dir=args.dir, fields=args.fields,
length=args.length, offset=args.offset))
print('The search id is {}'.format(search_id))
if args.histogram:
print(arc.histogram(search_id=args.searchid))
if args.drilldown:
print(arc.drilldown(search_id=args.searchid, start_time=args.starttime,
end_time=args.endtime))
if args.event:
print(arc.events(search_id=args.searchid, dir=args.dir, fields=args.fields,
length=args.length, offset=args.offset))
if args.chartdata:
print(arc.events(search_id=args.searchid, length=args.length,
offset=args.offset))
if args.status:
print(arc.search_complete(search_id=args.searchid))