Skip to content

Commit 2594f6f

Browse files
committed
Add support for type=config&action=multi-config XML API request which
provides a mechanism to perform multiple configuration API requests with transactional support. Effort started by Garfield Freeman with addition of multi_config() to pan.xapi.
1 parent 6c73028 commit 2594f6f

File tree

5 files changed

+108
-2
lines changed

5 files changed

+108
-2
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ Patches and Suggestions
99
- Andrew Stanton
1010
- Darlene Wong
1111
- Michael Richardson
12+
- Garfield Freeman

bin/panxapi.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,16 @@ def main():
216216
print_status(xapi, action)
217217
print_response(xapi, options)
218218

219+
if options['multi-config']:
220+
action = 'multi-config'
221+
if options['ad_hoc'] is not None:
222+
extra_qs_used = True
223+
xapi.multi_config(element=options['element'],
224+
strict=options['strict'],
225+
extra_qs=options['ad_hoc'])
226+
print_status(xapi, action)
227+
print_response(xapi, options)
228+
219229
if options['export'] is not None:
220230
action = 'export'
221231
if options['ad_hoc'] is not None:
@@ -387,6 +397,8 @@ def parse_opts():
387397
'rename': False,
388398
'clone': False,
389399
'override': False,
400+
'multi-config': False,
401+
'strict': None,
390402
'api_username': None,
391403
'api_password': None,
392404
'hostname': None,
@@ -424,12 +436,12 @@ def parse_opts():
424436

425437
valid_where = ['after', 'before', 'top', 'bottom']
426438

427-
short_options = 'de:gksS:U:C:A:o:l:h:P:K:xpjrXHGDt:T:'
439+
short_options = 'de:gksS:U:C:A:o:M:l:h:P:K:xpjrXHGDt:T:'
428440
long_options = ['version', 'help',
429441
'ad-hoc=', 'modify', 'validate', 'force', 'partial=',
430442
'sync', 'vsys=', 'src=', 'dst=', 'move=', 'rename',
431443
'clone', 'override=', 'export=', 'log=', 'recursive',
432-
'cafile=', 'capath=', 'ls', 'serial=',
444+
'strict=', 'cafile=', 'capath=', 'ls', 'serial=',
433445
'group=', 'merge', 'nlogs=', 'skip=', 'filter=',
434446
'interval=', 'timeout=',
435447
'stime=', 'pcapid=', 'text',
@@ -512,6 +524,15 @@ def parse_opts():
512524
elif opt == '--override':
513525
options['override'] = True
514526
options['element'] = get_element(arg)
527+
elif opt == '-M':
528+
options['multi-config'] = True
529+
options['element'] = get_element(arg)
530+
elif opt == '--strict':
531+
if arg in ['yes', 'no']:
532+
options['strict'] = True if arg == 'yes' else False
533+
else:
534+
print('--strict must be yes|no', file=sys.stderr)
535+
sys.exit(1)
515536
elif opt == '-l':
516537
try:
517538
(options['api_username'],
@@ -858,6 +879,8 @@ def usage():
858879
--rename rename object at xpath to dst
859880
--clone clone object at xpath, src xpath
860881
--override element override template object at xpath
882+
-M element multi-config XML element
883+
--strict yes|no multi-config strict-transactional
861884
--vsys vsys VSYS for dynamic update/partial commit/
862885
operational command/report
863886
-l api_username[:api_password]

doc/pan.xapi.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,27 @@ override(xpath=None, element=None)
282282
Only certain nodes in the Network and Device categories can
283283
be overridden.
284284

285+
multi_config(element=None, strict=None)
286+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
287+
288+
The multi_config() method performs the ``action=multi-config`` device
289+
configuration API request with the **element** and optional
290+
**strict-transactional** argument. multi_config() is used to perform
291+
multiple configuration API requests with transactional support.
292+
293+
When a request in the multi-config operation fails, no configuration
294+
changes are performed.
295+
296+
When **strict** is set to *True* the **strict-transactional** API
297+
request argument is set to *yes* and additional checks are performed:
298+
299+
- When a commit operation is active or a commit is pending, the
300+
operation will fail.
301+
302+
- When there are uncommitted changes for the user performing the
303+
operation, they will be rolled back before performing the
304+
multi-config operation.
305+
285306
user_id(cmd=None, vsys=None)
286307
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
287308

@@ -653,6 +674,9 @@ SEE ALSO
653674
PAN-OS and Panorama API Guide
654675
https://docs.paloaltonetworks.com/pan-os/10-2/pan-os-panorama-api.html
655676

677+
PAN-OS XML API multi-config Request
678+
https://gist.github.com/kevinsteves/c175854d44324f5c0a006798929e1a76
679+
656680
AUTHORS
657681
=======
658682

doc/panxapi.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ SYNOPSIS
6363
--rename rename object at xpath to dst
6464
--clone clone object at xpath, src xpath
6565
--override element override template object at xpath
66+
-M element multi-config XML element
67+
--strict yes|no multi-config strict-transactional
6668
--vsys vsys VSYS for dynamic update/partial commit/
6769
operational command/report
6870
-l api_username[:api_password]
@@ -353,6 +355,27 @@ DESCRIPTION
353355
**element** can be an XML string, a path to a file containing XML,
354356
or the value **-** to specify the XML is on *stdin*.
355357

358+
``-M`` *element*
359+
Performs the ``action=multi-config`` device configuration API
360+
request with the **element** and optional **strict-transactional**
361+
argument. ``multi-config`` is used to perform multiple
362+
configuration API requests with transactional support.
363+
364+
**element** can be an XML string, a path to a file containing XML,
365+
or the value **-** to specify the XML is on *stdin*.
366+
367+
``--strict`` *yes|no*
368+
When **--strict** is *yes* the **strict-transactional**
369+
``multi-config`` API request argument is set to *yes* and additional
370+
checks are performed:
371+
372+
- When a commit operation is active or a commit is pending, the
373+
operation will fail.
374+
375+
- When there are uncommitted changes for the user performing the
376+
operation, they will be rolled back before performing the
377+
multi-config operation.
378+
356379
``--vsys`` *vsys*
357380
Specify optional **vsys** for dynamic update (**-U**), partial vsys
358381
commit (**--partial** vsys), commit-all (**-A**) and operational
@@ -722,6 +745,9 @@ SEE ALSO
722745
PAN-OS and Panorama API Guide
723746
https://docs.paloaltonetworks.com/pan-os/10-2/pan-os-panorama-api.html
724747

748+
PAN-OS XML API multi-config Request
749+
https://gist.github.com/kevinsteves/c175854d44324f5c0a006798929e1a76
750+
725751
PAN-OS XML API Labs with pan-python
726752
http://api-lab.paloaltonetworks.com/
727753

lib/pan/xapi.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,30 @@ def __get_response_msg(self):
395395
lines.append(elem2.text)
396396
return '\n'.join(lines) if lines else None
397397

398+
# multi-config responses have nested response tags under the
399+
# main response tag
400+
path = './response'
401+
elem = self.element_root.findall(path)
402+
if len(elem) > 0:
403+
self._log(DEBUG2, 'path: %s', path)
404+
for resp in elem:
405+
attributes = ''
406+
for x in ['status', 'code', 'id']:
407+
if x in resp.attrib:
408+
attributes += '%s="%s" ' % (x, resp.attrib[x])
409+
msg = resp.find('./msg')
410+
if msg is None:
411+
lines.append(attributes.rstrip())
412+
continue
413+
line = msg.find('./line')
414+
if line is not None and line.text is not None:
415+
lines.append(attributes + line.text)
416+
elif msg.text is not None:
417+
lines.append(attributes + msg.text)
418+
elif attributes:
419+
lines.append(attributes.rstrip())
420+
return '\n'.join(lines) if lines else None
421+
398422
return None
399423

400424
# XXX store tostring() results?
@@ -734,6 +758,14 @@ def override(self, xpath=None, element=None, extra_qs=None):
734758
query['element'] = element
735759
self.__type_config('override', query, extra_qs)
736760

761+
def multi_config(self, element=None, strict=None, extra_qs=None):
762+
query = {}
763+
if element is not None:
764+
query['element'] = element
765+
if strict is not None:
766+
query['strict-transactional'] = 'yes' if strict else 'no'
767+
self.__type_config('multi-config', query, extra_qs)
768+
737769
def __type_config(self, action, query, extra_qs=None):
738770
self.__set_api_key()
739771
self.__clear_response()

0 commit comments

Comments
 (0)