Skip to content

Commit cf790c6

Browse files
committed
add synchronous commit capability.
TODO: more complete show job message parsing, especially for commit-all.
1 parent 47b4d84 commit cf790c6

File tree

3 files changed

+103
-6
lines changed

3 files changed

+103
-6
lines changed

bin/panxapi.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ def main():
209209

210210
kwargs = {
211211
'cmd': cmd,
212+
'sync': options['sync'],
213+
'interval': options['interval'],
214+
'timeout': options['job_timeout'],
212215
}
213216
if options['commit_all']:
214217
kwargs['action'] = 'all'
@@ -238,6 +241,7 @@ def parse_opts():
238241
'commit': False,
239242
'force': False,
240243
'partial': [],
244+
'sync': False,
241245
'vsys': [],
242246
'commit_all': False,
243247
'ad_hoc': None,
@@ -286,7 +290,7 @@ def parse_opts():
286290

287291
short_options = 'de:gksS:U:C:A:o:l:h:P:K:xpjrXHGDt:T:'
288292
long_options = ['version', 'help',
289-
'ad-hoc=', 'modify', 'force', 'partial=',
293+
'ad-hoc=', 'modify', 'force', 'partial=', 'sync',
290294
'vsys=', 'src=', 'dst=', 'move=', 'rename',
291295
'clone', 'export=', 'log=', 'recursive',
292296
'cafile=', 'capath=', 'ls', 'serial=',
@@ -329,6 +333,8 @@ def parse_opts():
329333
if arg:
330334
l = get_parts(arg)
331335
[options['partial'].append(s) for s in l]
336+
elif opt == '--sync':
337+
options['sync'] = True
332338
elif opt == '--vsys':
333339
if arg:
334340
l = get_vsys(arg)
@@ -637,6 +643,7 @@ def usage():
637643
-C cmd commit candidate configuration
638644
--force force commit when conflict
639645
--partial part commit specified part
646+
--sync synchronous commit
640647
-A cmd commit-all (Panorama)
641648
--ad-hoc query perform ad hoc request
642649
--modify insert known fields in ad hoc query
@@ -663,8 +670,8 @@ def usage():
663670
--nlogs num retrieve num logs
664671
--skip num skip num logs
665672
--filter filter log selection filter
666-
--interval log job query interval
667-
--timeout log job query timeout
673+
--interval log/commit job query interval
674+
--timeout log/commit job query timeout
668675
-K api_key
669676
-x print XML response to stdout
670677
-p print XML response in Python to stdout

doc/pan.xapi.rst

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,44 @@ user_id(cmd=None, vsys=None)
281281
mappings and address objects. **vsys** can be used to target the
282282
dynamic update to a specific Virtual System.
283283

284-
commit(cmd=None, action=None)
285-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
284+
commit(cmd=None, action=None, sync=False, interval=None, timeout=None)
285+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
286286

287287
The commit() method performs the ``type=commit`` commit configuration
288288
API request with the **cmd** argument and optional **action**
289289
argument. This schedules a job to execute a configuration mode
290290
**commit** command to commit the candidate configuration.
291291

292+
**cmd** is an XML document used to specify commit arguments.
293+
294+
**action** can be set to "all" to perform a ``commit-all`` on
295+
Panorama.
296+
297+
Additional arguments include:
298+
299+
- **sync**
300+
301+
Perform a synchronous commit when set to *True*.
302+
303+
The XML API schedules a job to perform the commit operation; the
304+
commit() method will then periodically perform an API request to
305+
determine if the job ID returned in the initial request is complete
306+
and return with the job status. Additional arguments to control
307+
the polling include:
308+
309+
- **interval**
310+
311+
A floating point number specifying the query interval in seconds
312+
between each non-finished job status response.
313+
314+
The default is 0.5 seconds.
315+
316+
- **timeout**
317+
318+
The maximum number of seconds to wait for the job to finish.
319+
320+
The default is to try forever (**timeout** is set to *None* or 0).
321+
292322
op(cmd=None, vsys=None, cmd_xml=False)
293323
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
294324

lib/pan/xapi.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,10 +700,29 @@ def user_id(self, cmd=None, vsys=None):
700700
if not self.__set_response(response):
701701
raise PanXapiError(self.status_detail)
702702

703-
def commit(self, cmd=None, action=None):
703+
def commit(self, cmd=None, action=None, sync=False,
704+
interval=None, timeout=None):
704705
self.__set_api_key()
705706
self.__clear_response()
706707

708+
if interval is not None:
709+
try:
710+
interval = float(interval)
711+
if interval < 0:
712+
raise ValueError
713+
except ValueError:
714+
raise PanXapiError('Invalid interval: %s' % interval)
715+
else:
716+
interval = _job_query_interval
717+
718+
if timeout is not None:
719+
try:
720+
timeout = int(timeout)
721+
if timeout < 0:
722+
raise ValueError
723+
except ValueError:
724+
raise PanXapiError('Invalid timeout: %s' % timeout)
725+
707726
query = {}
708727
query['type'] = 'commit'
709728
query['key'] = self.api_key
@@ -719,6 +738,47 @@ def commit(self, cmd=None, action=None):
719738
if not self.__set_response(response):
720739
raise PanXapiError(self.status_detail)
721740

741+
if sync is not True:
742+
return
743+
744+
job = self.element_root.find('./result/job')
745+
if job is None:
746+
return
747+
748+
if self.debug2:
749+
print('commit job:', job.text, file=sys.stderr)
750+
751+
cmd = 'show jobs id "%s"' % job.text
752+
start_time = time.time()
753+
754+
while True:
755+
try:
756+
self.op(cmd=cmd, cmd_xml=True)
757+
except PanXapiError as msg:
758+
raise PanXapiError('commit %s: %s' % (cmd, msg))
759+
760+
path = './result/job/status'
761+
status = self.element_root.find(path)
762+
if status is None:
763+
raise PanXapiError('no status element in ' +
764+
"'%s' response" % cmd)
765+
if status.text == 'FIN':
766+
# XXX commit vs. commit-all job status
767+
return
768+
769+
if self.debug2:
770+
print('job %s status %s' % (job.text, status.text),
771+
file=sys.stderr)
772+
773+
if (timeout is not None and timeout != 0 and
774+
time.time() > start_time + timeout):
775+
raise PanXapiError('timeout waiting for ' +
776+
'job %s completion' % job.text)
777+
778+
if self.debug2:
779+
print('sleep %.2f seconds' % interval, file=sys.stderr)
780+
time.sleep(interval)
781+
722782
def op(self, cmd=None, vsys=None, cmd_xml=False):
723783
if cmd is not None and cmd_xml:
724784
cmd = self.cmd_xml(cmd)

0 commit comments

Comments
 (0)