Skip to content

Commit 81e2871

Browse files
committed
Merge branch 'release/0.6.4'
2 parents a577f43 + c3b6fd1 commit 81e2871

File tree

12 files changed

+271
-50
lines changed

12 files changed

+271
-50
lines changed

HISTORY.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
History
44
=======
55

6+
0.6.4
7+
-----
8+
9+
Released: 2018-07-10
10+
11+
Status: Alpha
12+
13+
- Added .move() function to move config elements
14+
- Added objects.SecurityProfileGroup
15+
- Added "devices" param to panorama.TemplateStack
16+
- Added dynamic NAT translation support for PAN-OS 8.1+
17+
- Fixed ha.HighAvailability for PAN-OS 8.1+
18+
619
0.6.3
720
-----
821

pandevice/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
__author__ = 'Palo Alto Networks'
2525
__email__ = '[email protected]'
26-
__version__ = '0.6.3'
26+
__version__ = '0.6.4'
2727

2828

2929
import logging

pandevice/base.py

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,80 @@ def update(self, variable):
627627
device.xapi.edit(xpath, ET.tostring(element, encoding='utf-8'),
628628
retry_on_peer=self.HA_SYNC)
629629

630+
def move(self, location, ref=None, update=True):
631+
"""Moves the current object.
632+
633+
**Modifies the live device**
634+
635+
This is useful for stuff like moving one security policy above another.
636+
637+
If this object's parent is a rulebase object, then this object is also
638+
moved to the appropriate position in the local pandevice object tree.
639+
640+
Args:
641+
location (str): Any of the following: before, after, top, or bottom
642+
ref (PanObject/str): If location is "before" or "after", move this object before/after the ref object. If this is a string, then the string should just be the name of the object.
643+
update (bool): If this is set to False, then only move this object in the pandevice object tree, do not actually perform the MOVE operation on the live device. Note that in order for this object to be moved in the pandevice object tree, the parent object must be a rulebase object.
644+
645+
Raises:
646+
ValueError
647+
648+
"""
649+
d = self.nearest_pandevice()
650+
dst = None
651+
new_index = None
652+
rbs = ('Rulebase', 'PreRulebase', 'PostRulebase')
653+
ref_locs = ('before', 'after')
654+
standalone_locs = ('top', 'bottom')
655+
parent = self.parent
656+
657+
# Sanity checks + determine move location.
658+
if parent is None:
659+
raise ValueError('No parent for object {0}'.format(self.uid))
660+
elif location in standalone_locs:
661+
if ref is not None:
662+
raise ValueError('ref should be None for {0} move'.format(
663+
location))
664+
if parent.__class__.__name__ in rbs:
665+
new_index = 0 if location == 'top' else len(parent.children) - 1
666+
elif location in ref_locs:
667+
if ref is None:
668+
raise ValueError('ref must be specified for {0} move'.format(
669+
location))
670+
dst = str(ref)
671+
if self.uid == dst:
672+
raise ValueError('Cannot move rule in relation to self')
673+
if parent.__class__.__name__ in rbs:
674+
offset = 0
675+
for i, x in enumerate(parent.children):
676+
if self == x:
677+
offset = 1
678+
elif type(x) == type(self) and x.uid == dst:
679+
new_index = (
680+
i - offset
681+
if location == 'before'
682+
else i - offset + 1)
683+
break
684+
else:
685+
raise ValueError('Location must be one of: {0} or {1}'.format(
686+
ref_locs, standalone_locs))
687+
688+
logger.debug('{0}: move called on {1} "{2}"'.format(
689+
d.id, type(self), self.uid))
690+
691+
# Move the rule in the pandevice object tree, if applicable.
692+
if new_index is not None:
693+
parent.remove(self)
694+
parent.insert(new_index, self)
695+
696+
# Done if we're not updating.
697+
if not update:
698+
return
699+
700+
# Perform the move on the nearest pandevice.
701+
d.set_config_changed()
702+
d.xapi.move(self.xpath(), location, dst)
703+
630704
def _get_param_specific_info(self, variable):
631705
"""Gets a tuple of info for the given parameter.
632706
@@ -2544,7 +2618,9 @@ def element(self, elm, settings, comparable=False):
25442618
continue
25452619
if token.startswith('entry '):
25462620
junk, var_to_use = token.split()
2547-
child = ET.Element('entry', {'name': settings[var_to_use]})
2621+
sol_val = pandevice.string_or_list(settings[var_to_use])[0]
2622+
child = ET.Element('entry',
2623+
{'name': str(sol_val)})
25482624
elif token == "entry[@name='localhost.localdomain']":
25492625
child = ET.Element('entry', {'name': 'localhost.localdomain'})
25502626
else:
@@ -2620,7 +2696,8 @@ def parse_xml(self, xml, settings, possibilities):
26202696
if ans is None:
26212697
return
26222698
settings[entry_var] = ans.attrib['name']
2623-
path_str = "entry[@name='{0}']".format(settings[entry_var])
2699+
sol_val = pandevice.string_or_list(settings[entry_var])[0]
2700+
path_str = "entry[@name='{0}']".format(sol_val)
26242701
else:
26252702
# Standard path part
26262703
try:

pandevice/device.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class Vsys(VersionedPanObject):
110110
"objects.ApplicationObject",
111111
"objects.ApplicationGroup",
112112
"objects.ApplicationFilter",
113+
"objects.SecurityProfileGroup",
113114
"policies.Rulebase",
114115
"network.EthernetInterface",
115116
"network.AggregateInterface",

pandevice/firewall.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Firewall(PanDevice):
7575
"objects.ApplicationObject",
7676
"objects.ApplicationGroup",
7777
"objects.ApplicationFilter",
78+
"objects.SecurityProfileGroup",
7879
"policies.Rulebase",
7980
"network.EthernetInterface",
8081
"network.AggregateInterface",

pandevice/ha.py

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
from pandevice import getlogger, isstring
2727
from pandevice.base import PanObject, PanDevice, Root, MEMBER, ENTRY
2828
from pandevice.base import VarPath as Var
29+
from pandevice.base import VersionedPanObject
30+
from pandevice.base import VersionedParamPath
2931
from pandevice import network, firewall
3032
import pandevice.errors as err
3133

@@ -264,12 +266,13 @@ def variables(cls):
264266
)
265267

266268

267-
class HighAvailability(PanObject):
269+
class HighAvailability(VersionedPanObject):
268270
"""High availability configuration base object
269271
270272
All high availability configuration is in this object or is a child of this object
271273
272274
Args:
275+
name: (unused, and may be omitted)
273276
enabled (bool): Enable HA (Default: True)
274277
group_id (int): The group identifier
275278
description (str): Description for HA pairing
@@ -284,42 +287,99 @@ class HighAvailability(PanObject):
284287
285288
"""
286289
ROOT = Root.DEVICE
287-
XPATH = "/deviceconfig/high-availability"
290+
SUFFIX = None
288291
HA_SYNC = False
289292
CHILDTYPES = (
290-
"ha.HA1",
291-
"ha.HA1Backup",
292-
"ha.HA2",
293-
"ha.HA2Backup",
294-
"ha.HA3",
293+
'ha.HA1',
294+
'ha.HA1Backup',
295+
'ha.HA2',
296+
'ha.HA2Backup',
297+
'ha.HA3',
295298
)
296299

297-
ACTIVE_PASSIVE = "active-passive"
298-
ACTIVE_ACTIVE = "active-active"
299-
300-
@classmethod
301-
def variables(cls):
302-
return (
303-
# Enabled flag
304-
Var("enabled", vartype="bool", default=True),
305-
# Group
306-
Var("group", "group_id", vartype="entry", default=(1,)),
307-
Var("{{group_id}}/description"),
308-
Var("{{group_id}}/configuration-synchronization/enabled", "config_sync", vartype="bool"),
309-
Var("{{group_id}}/peer-ip"),
310-
# HA Mode (A/P, A/A)
311-
Var("{{group_id}}/mode/(active-passive|active-active)", "mode", default="active-passive"),
312-
Var("{{group_id}}/mode/{{mode}}/passive-link-state"),
313-
# State Synchronization
314-
Var("{{group_id}}/state-synchronization/enabled", "state_sync", vartype="bool", default=False),
315-
# HA2 Keep-alive
316-
Var("{{group_id}}/state-synchronization/ha2-keep-alive/enabled", "ha2_keepalive", vartype="bool"),
317-
Var("{{group_id}}/state-synchronization/ha2-keep-alive/action", "ha2_keepalive_action"),
318-
Var("{{group_id}}/state-synchronization/ha2-keep-alive/threshold", "ha2_keepalive_threshold", vartype="int"),
319-
Var("interface", vartype="none"),
320-
Var("interface/ha1", vartype="none"),
321-
Var("interface/ha1-backup", vartype="none"),
322-
Var("interface/ha2", vartype="none"),
323-
Var("interface/ha2-backup", vartype="none"),
324-
Var("interface/ha3", vartype="none"),
325-
)
300+
ACTIVE_PASSIVE = 'active-passive'
301+
ACTIVE_ACTIVE = 'active-active'
302+
303+
def _setup(self):
304+
# xpaths
305+
self._xpaths.add_profile(value='/deviceconfig/high-availability')
306+
307+
# params
308+
params = []
309+
310+
params.append(VersionedParamPath(
311+
'enabled', default=True, vartype='yesno', path='enabled'))
312+
params.append(VersionedParamPath(
313+
'group_id', default=1, vartype='entry', path='group'))
314+
params[-1].add_profile(
315+
'8.1.0',
316+
vartype='int', path='group/group-id')
317+
params.append(VersionedParamPath(
318+
'description', path='group/entry group_id/description'))
319+
params[-1].add_profile(
320+
'8.1.0',
321+
path='group/description')
322+
params.append(VersionedParamPath(
323+
'config_sync', vartype='yesno',
324+
path='group/entry group_id/configuration-synchronization/enabled'))
325+
params[-1].add_profile(
326+
'8.1.0',
327+
vartype='yesno',
328+
path='group/configuration-synchronization/enabled')
329+
params.append(VersionedParamPath(
330+
'peer_ip', path='group/entry group_id/peer-ip'))
331+
params[-1].add_profile(
332+
'8.1.0',
333+
path='group/peer-ip')
334+
params.append(VersionedParamPath(
335+
'mode', default='active-passive',
336+
values=('active-passive', 'active-active'),
337+
path='group/entry group_id/mode/{mode}'))
338+
params[-1].add_profile(
339+
'8.1.0',
340+
values=('active-passive', 'active-active'),
341+
path='group/mode/{mode}')
342+
params.append(VersionedParamPath(
343+
'passive_link_state', condition={'mode': 'active-passive'},
344+
path='group/entry group_id/mode/{mode}/passive-link-state'))
345+
params[-1].add_profile(
346+
'8.1.0',
347+
condition={'mode': 'active-passive'},
348+
path='group/mode/{mode}/passive-link-state')
349+
params.append(VersionedParamPath(
350+
'state_sync', vartype='yesno', default=False,
351+
path='group/entry group_id/state-synchronization/enabled'))
352+
params[-1].add_profile(
353+
'8.1.0',
354+
vartype='yesno',
355+
path='group/state-synchronization/enabled')
356+
params.append(VersionedParamPath(
357+
'ha2_keepalive', vartype='yesno',
358+
path='group/entry group_id/state-synchronization/ha2-keep-alive/enabled'))
359+
params[-1].add_profile(
360+
'8.1.0',
361+
vartype='yesno',
362+
path='group/state-synchronization/ha2-keep-alive/enabled')
363+
params.append(VersionedParamPath(
364+
'ha2_keepalive_action', values=('log-only', 'split-datapath'),
365+
path='group/entry group_id/state-synchronization/ha2-keep-alive/action'))
366+
params[-1].add_profile(
367+
'8.1.0',
368+
values=('log-only', 'split-datapath'),
369+
path='group/state-synchronization/ha2-keep-alive/action')
370+
params.append(VersionedParamPath(
371+
'ha2_keepalive_threshold', vartype='int',
372+
path='group/entry group_id/state-synchronization/ha2-keep-alive/threshold'))
373+
params[-1].add_profile(
374+
'8.1.0',
375+
vartype='int',
376+
path='group/state-synchronization/ha2-keep-alive/threshold')
377+
378+
self._params = tuple(params)
379+
380+
# stubs
381+
self._stubs.add_profile(
382+
'0.0.0',
383+
'interface/ha1', 'interface/ha1-backup',
384+
'interface/ha2', 'interface/ha2-backup',
385+
'interface/ha3')

pandevice/objects.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,45 @@ def _setup(self):
470470
'applications', path='functions', vartype='member'))
471471

472472
self._params = tuple(params)
473+
474+
475+
class SecurityProfileGroup(VersionedPanObject):
476+
"""Security Profile Group object
477+
478+
Args:
479+
name (str): The group name
480+
virus (str): Antivirus profile
481+
spyware (str): Anti-spyware profile
482+
vulnerability (str): Vulnerability protection profile
483+
url_filtering (str): URL filtering profile
484+
file_blocking (str): File blocking profile
485+
data_filtering (str): Data filtering profile
486+
wildfire_analysis (str): WildFire analysis profile
487+
488+
"""
489+
ROOT = Root.VSYS
490+
SUFFIX = ENTRY
491+
492+
def _setup(self):
493+
# xpaths
494+
self._xpaths.add_profile(value='/profile-group')
495+
496+
# params
497+
params = []
498+
499+
params.append(VersionedParamPath(
500+
'virus', path='virus', vartype='member'))
501+
params.append(VersionedParamPath(
502+
'spyware', path='spyware', vartype='member'))
503+
params.append(VersionedParamPath(
504+
'vulnerability', path='vulnerability', vartype='member'))
505+
params.append(VersionedParamPath(
506+
'url_filtering', path='url-filtering', vartype='member'))
507+
params.append(VersionedParamPath(
508+
'file_blocking', path='file-blocking', vartype='member'))
509+
params.append(VersionedParamPath(
510+
'data_filtering', path='data-filtering', vartype='member'))
511+
params.append(VersionedParamPath(
512+
'wildfire_analysis', path='wildfire-analysis', vartype='member'))
513+
514+
self._params = tuple(params)

pandevice/panorama.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class DeviceGroup(VersionedPanObject):
6565
"objects.ApplicationObject",
6666
"objects.ApplicationGroup",
6767
"objects.ApplicationFilter",
68+
"objects.SecurityProfileGroup",
6869
)
6970

7071
def _setup(self):
@@ -181,6 +182,7 @@ class TemplateStack(VersionedPanObject):
181182
name: Stack name
182183
description: The description
183184
templates (str/list): The list of templates in this stack
185+
devices (str/list): The list of serial numbers in this template
184186
185187
"""
186188
ROOT = Root.DEVICE
@@ -197,6 +199,8 @@ def _setup(self):
197199
'description', path='description'))
198200
params.append(VersionedParamPath(
199201
'templates', path='templates', vartype='member'))
202+
params.append(VersionedParamPath(
203+
'devices', vartype='entry', path='devices'))
200204

201205
self._params = tuple(params)
202206

0 commit comments

Comments
 (0)