PaloAltoFirewall:部分api

  1 import datetime
  2 import time
  3 import logging
  4 
  5 import requests
  6 
  7 
  8 class PaloAltoFirewallAPI(object):
  9     error_codes = {
 10         '400': 'Bad request: A required parameter is missing, an illegal parameter value is used.',
 11         '403': ('Forbidden: '
 12                 'Authentication or authorization errors including invalid key or insufficient admin access rights. '
 13                 'Learn how to Get Your API Key.'
 14                 ),
 15         '1': 'Unknown command: The specific config or operational command is not recognized.',
 16         '2': 'Unknown command: The specific config or operational command is not recognized.',
 17         '3': 'Unknown command: The specific config or operational command is not recognized.',
 18         '4': 'Unknown command: The specific config or operational command is not recognized.',
 19         '5': 'Unknown command: The specific config or operational command is not recognized.',
 20         '6': ('Bad Xpath: '
 21               'The xpath specified in one or more attributes of the command is invalid. '
 22               'Check the API browser for proper xpath values.'
 23               ),
 24         '7': ('Object not present: '
 25               'Object specified by the xpath is not present. '
 26               'For example, entry[@name="value"] where no object with name "value" is present.'
 27               ),
 28         '8': 'Object not unique: For commands that operate on a single object, the specified object is not unique.',
 29         '10': ('Reference count not zero: '
 30                'Object cannot be deleted as there are other objects that refer to it. '
 31                'For example, address object still in use in policy.'
 32                ),
 33         '11': 'Internal error: Check with technical support when seeing these errors.',
 34         '12': 'Invalid object: Xpath or element values provided are not complete.',
 35         '14': ('Operation not possible: '
 36                'Operation is allowed but not possible in this case. '
 37                'For example, moving a rule up one position when it is already at the top.'
 38                ),
 39         '15': ('Operation denied: '
 40                'Operation is allowed. For example, Admin not allowed to delete own account, '
 41                'Running a command that is not allowed on a passive device.'
 42                ),
 43         '16': 'Unauthorized: The API role does not have access rights to run this query.',
 44         '17': 'Invalid command: Invalid command or parameters.',
 45         '18': 'Malformed command: The XML is malformed.',
 46         '19': 'Success: Command completed successfully.',
 47         '20': 'Success: Check with technical support when seeing these errors.',
 48         '21': 'Internal error: ',
 49         '22': 'Session timed out: The session for this query timed out.',
 50     }
 51 
 52     def __init__(self, ip, username='', password='', api_key=''):
 53         """
 54         :param ip:
 55         :param username:
 56         :param password:
 57         :param api_key: if exist, ignore username and password
 58         """
 59         self.ip = ip
 60         if api_key:
 61             self.key = api_key
 62         else:
 63             key_url = 'https://{ip}/api/?type=keygen&user={username}&password={password}'.format(
 64                 ip=ip, username=username, password=password
 65             )
 66             self.key = xmltodict.parse(
 67                 requests.post(key_url, verify=False).content
 68             ).get('response').get('result').get('key')
 69         self.url = 'https://{ip}/api'.format(ip=ip)
 70 
 71     def _request(self, params, method='post'):
 72         """
 73         :param params:
 74         {
 75             'type': 'config',
 76             'action': 'get',
 77             'key': self.key,
 78             'xpath': xpath,
 79         }
 80         :return:
 81         {
 82             'code': '19',
 83             'msg': 'Success: Command completed successfully.',
 84             'success': True,
 85             'result': Dict,
 86         }
 87         """
 88         response = xmltodict.parse(
 89             requests.request(
 90                 method=method, url=self.url, params=params, verify=False
 91             ).text
 92         ).get('response')
 93         code = response.get('@code')
 94         if code in ('19', '20', None):
 95             msg = response.get('msg')
 96         else:
 97             msg = self.error_codes.get(code)
 98         result = {
 99             'code': code,
100             'msg': msg,
101             'success': False,
102             'result': None,
103         }
104         if response.get('@status') == 'success':
105             result['success'] = True
106             result['result'] = response.get('result')
107         else:
108             result['success'] = False
109         return result
110 
111     def get_report(self, report_name, period='last-hour', top_n=5, wait_for_result=30):
112         """
113         :param report_name:
114             acc-summary
115             custom-dynamic-report
116             top-app-summary
117             top-application-categories-summary
118             top-application-risk-summary
119             top-application-subcategories-summary
120             top-application-tech-summary
121             top-applications-summary
122             top-applications-trsum
123             top-attacker-countries-summary
124             top-attackers-summary
125             top-attacks-acc
126             top-blocked-url-categories-summary
127             top-blocked-url-summary
128             top-blocked-url-user-behavior-summary
129             top-data-dst-countries-summary
130             top-data-dst-summary
131             top-data-egress-zones-summary
132             top-data-filename-summary
133             top-data-filetype-summary
134             top-data-ingress-zones-summary
135             top-data-src-countries-summary
136             top-data-src-summary
137             top-data-type-summary
138             top-dst-countries-summary
139             top-dst-summary
140             top-egress-zones-summary
141             top-hip-objects-details
142             top-hip-objects-summary
143             top-hip-profiles-details
144             top-hip-profiles-summary
145             top-hip-report-links
146             top-hr-applications-summary
147             top-ingress-zones-summary
148             top-rule-summary
149             top-spyware-phonehome-summary
150             top-spyware-threats-summary
151             top-src-countries-summary
152             top-src-summary
153             top-threat-egress-zones-summary
154             top-threat-ingress-zones-summary
155             top-threats-type-summary
156             top-url-categories-summary
157             top-url-summary
158             top-url-user-behavior-summary
159             top-victim-countries-summary
160             top-victims-summary
161             top-viruses-summary
162             top-vulnerabilities-summary
163         :param period:
164             last-60-seconds
165             last-15-minutes
166             last-hour
167             last-12-hrs
168             last-7-days,
169             last-calendar-day
170         :param top_n:
171         :param wait_for_result: Return report-result within 30 seconds, otherwise return job id
172         :return: Dict
173         """
174         params = {
175             'reportname': report_name,
176             'type': 'report',
177             'reporttype': 'dynamic',
178             'period': period,
179             'topn': top_n,
180             'key': self.key,
181         }
182 
183         res = self._request(params=params)
184         result = {
185             'job_id': None,
186             'report': {},
187             'success': True
188         }
189         data = res.get('result') or {}
190         if not res.get('success'):
191             result['success'] = False
192             result['msg'] = data.get('msg')
193             return result
194         else:
195             result['job_id'] = job_id = data.get('job')
196             if wait_for_result:
197                 report = {}
198                 while not report and wait_for_result > 0:
199                     time.sleep(1)
200                     wait_for_result -= 1
201                     res = self.get_job(job_id, job_type='report')
202                     if res.get('success'):
203                         report = res.get('result')
204                         result['success'] = True
205                     else:
206                         result['success'] = False
207 
208                 result.update(**report)
209             if not result['report']:
210                 result['report'] = {}
211         return result
212 
213     def get_job(self, job_id, job_type='report'):
214         """
215         :param job_id: def get_report:
216         :param job_type: default = report
217         :return:
218         """
219         params = {
220             'action': 'get',
221             'type': job_type,
222             'job-id': job_id,
223             'key': self.key,
224         }
225         return self._request(params=params)
226 
227     def _sp_config(self, _type, rel_path, entry_name='', action='get', **kwargs):
228         """
229         :param _type:
230         :param rel_path:
231         :param entry_name:
232         :param action:
233         :param kwargs: extra params
234         :return:
235         """
236         limit_types = ('deviceconfig', 'network', 'platform', 'vsys')
237         if _type not in limit_types:
238             raise Exception('"_type" must be one of {limit_types}'.format(limit_types=limit_types))
239         rel_path = rel_path.strip('/')
240         if entry_name and not isinstance(entry_name, (list, tuple)):
241             entry_name = [entry_name]
242         if _type in ('deviceconfig', 'network', 'platform'):
243             rel_path = os.path.join(_type, rel_path).replace('\\', '/')
244             if entry_name:
245                 entries = ' or '.join(["@name='{name}'".format(name=name) for name in entry_name])
246                 xpath = (
247                     "/config/devices/entry[@name='localhost.localdomain']/{rel_path}/entry[{entries}]"
248                 ).format(rel_path=rel_path, entries=entries)
249             else:
250                 xpath = "/config/devices/entry[@name='localhost.localdomain']/{rel_path}".format(rel_path=rel_path)
251         else:  # 'vsys':
252             if entry_name:
253                 entries = ' or '.join(["@name='{name}'".format(name=name) for name in entry_name])
254                 xpath = (
255                     "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}/"
256                     "entry[{entries}]"
257                 ).format(rel_path=rel_path, entries=entries)
258             else:
259                 xpath = (
260                     "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}"
261                 ).format(rel_path=rel_path)
262         params = {
263             'type': 'config',
264             'action': action,
265             'key': self.key,
266             'xpath': xpath,
267         }
268         params.update(**kwargs)
269         return self._request(params=params)
270 
271     def set_config(self, _type, rel_path, element='', action='set'):
272         """
273         :param _type:
274                     deviceconfig
275                     network
276                     platform
277                     vsys
278         :param rel_path: 'interface/ethernet'
279         :param element: <xml>
280             <entry name="ethernet1/1">
281                 <layer3>
282                 <lldp>
283                     <profile>lenovo_lldp</profile>
284                     <enable>yes</enable>
285                     </lldp>
286                 </layer3>
287             </entry>
288         :param action: Should be one of : [
289                 clone, complete, delete, edit, get, multi-clone, multi-move, override, rename, set, show
290             ]
291         :return: {
292                 'code': '19',
293                 'msg': 'Success: Command completed successfully.',
294                 'success': True,
295                 'result': Dict,
296             }
297         Usage:
298             >>> pa = PaloAltoFirewallAPI(api_key='x')
299             >>> element =
300                 <entry name="ethernet1/1">
301                     <layer3><lldp><enable>yes</enable><profile>lenovo_lldp</profile></lldp></layer3>
302                 </entry>
303             >>> pa.set_config(_type='network', rel_path='interface/ethernet', element=element)
304             >>>
305             >>> element =
306                 <entry name="SDWAN-Vedge-02-Public-IP">
307                     <ip-netmask>192.168.1.2</ip-netmask>
308                     <description>SDWAN-Vedge-02-Public-IP</description>
309                 </entry>
310             >>> pa.set_config(_type='vsys', rel_path='address', element=element)
311             >>>
312             >>> element =
313                 <entry name="SDWAN-Vedge-02-NAT">
314                     <to>
315                         <member>Internet_zone</member>
316                     </to>
317                     <from>
318                         <member>Office_zone</member>
319                     </from>
320                     <source>
321                         <member>SDWAN-Vedge-02-Int-Port-IP</member>
322                     </source>
323                     <destination>
324                         <member>any</member>
325                     </destination>
326                     <service>any</service>
327                     <description>SDWAN-Ser2-vEdge</description>
328                     <to-interface>ethernet1/2</to-interface>
329                     <disabled>no</disabled>
330                     <source-translation>
331                         <static-ip>
332                             <bi-directional>yes</bi-directional>
333                             <translated-address>SDWAN-Vedge-02-Public-IP</translated-address>
334                         </static-ip>
335                     </source-translation>
336                 </entry>
337             >>> pa.set_config(_type='vsys', rel_path='rulebase/nat/rules', element=element)
338         """
339         limit_types = ('deviceconfig', 'network', 'platform', 'vsys')
340         if _type not in limit_types:
341             raise Exception('"_type" must be one of {limit_types}'.format(limit_types=limit_types))
342         rel_path = rel_path.strip('/')
343 
344         if _type in ('deviceconfig', 'network', 'platform'):
345             rel_path = os.path.join(_type, rel_path).replace('\\', '/')
346             xpath = "/config/devices/entry[@name='localhost.localdomain']/{rel_path}".format(
347                 rel_path=rel_path
348             )
349         else:  # 'vsys':
350             xpath = (
351                 "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}"
352             ).format(rel_path=rel_path)
353         params = {
354             'type': 'config',
355             'action': action,
356             'key': self.key,
357             'xpath': xpath,
358             'element': element
359         }
360         return self._request(params=params)
361 
362     def get_config(self, _type, rel_path, entry_name=''):
363         """
364         :param _type:
365                     deviceconfig
366                     network
367                     platform
368                     vsys
369         :param rel_path: 'interface/ethernet'
370         :param entry_name: 'ethernet1/1'
371         :return: {
372             'code': '19',
373             'msg': 'Success: Command completed successfully.',
374             'success': True,
375             'result': Dict,
376         }
377         Usage:
378             >>> pa = PaloAltoFirewallAPI(api_key='x')
379             >>> pa.get_config(_type='network', rel_path='interface/ethernet', entry_name='ethernet name')
380             >>> pa.get_config(_type='vsys', rel_path='address', entry_name='address name')
381             >>> pa.get_config(_type='vsys', rel_path='rulebase/nat/rules', entry_name='rule name')
382         """
383         return self._sp_config(_type=_type, rel_path=rel_path, entry_name=entry_name, action='get')
384 
385     def get_entry_members(self, _type, rel_path, entry_name, member_names=None):
386         """
387         :param _type:
388                 deviceconfig
389                 network
390                 platform
391                 vsys
392         :param rel_path: 'interface/ethernet'
393         :param entry_name: 'CT-Address-Group'
394         :param member_names: ['ethernet1/1', ]
395         :return: {
396             'code': '19',
397             'msg': 'Success: Command completed successfully.',
398             'success': True,
399             'result': Dict,
400         }
401         Usage:
402             >>> pa = PaloAltoFirewallAPI(api_key='x')
403             >>> pa.get_entry_members(_type='vsys', rel_path='address-group', entry_name='CT-Address-Group', member_names=['CT-Address-0060', 'CT-Address-0061'])
404         """
405         limit_types = ('deviceconfig', 'network', 'platform', 'vsys')
406         if _type not in limit_types:
407             raise Exception('"_type" must be one of {limit_types}'.format(limit_types=limit_types))
408         rel_path = rel_path.strip('/')
409 
410         if _type in ('deviceconfig', 'network', 'platform'):
411             rel_path = os.path.join(_type, rel_path).replace('\\', '/')
412             if member_names:
413                 members = ' or '.join(["text()='{name}'".format(name=name) for name in member_names])
414                 xpath = (
415                     "/config/devices/entry[@name='localhost.localdomain']/{rel_path}/entry[@name='{entry_name}']/"
416                     "static/member[{members}]"
417                 ).format(rel_path=rel_path, entry_name=entry_name, members=members)
418             else:
419                 xpath = (
420                     "/config/devices/entry[@name='localhost.localdomain']/{rel_path}/entry[@name='{entry_name}']"
421                 ).format(rel_path=rel_path, entry_name=entry_name)
422         else:  # 'vsys':
423             if member_names:
424                 members = ' or '.join(["text()='{name}'".format(name=name) for name in member_names])
425                 xpath = (
426                     "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}/"
427                     "entry[@name='{entry_name}']/static/member[{members}]"
428                 ).format(rel_path=rel_path, entry_name=entry_name, members=members)
429             else:
430                 xpath = (
431                     "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}/"
432                     "entry[@name='{entry_name}']/static/member"
433                 ).format(rel_path=rel_path, entry_name=entry_name)
434         params = {
435             'type': 'config',
436             'action': 'get',
437             'key': self.key,
438             'xpath': xpath,
439         }
440         return self._request(params=params)
441 
442     def delete_entry_members(self, _type, rel_path, entry_name, member_names=None):
443         """
444         :param _type:
445                 deviceconfig
446                 network
447                 platform
448                 vsys
449         :param rel_path: 'address-group'
450         :param entry_name: 'CT-Address-Group'
451         :param member_names: ['ethernet1/1', ]
452         :return: {
453             'code': '19',
454             'msg': 'Success: Command completed successfully.',
455             'success': True,
456             'result': Dict,
457         }
458         Usage:
459             >>> pa = PaloAltoFirewallAPI(api_key='x')
460             >>> pa.get_config(
461             >>>     _type='vsys', rel_path='address-group', entry_name='CT-Address-Group',
462             >>>     member_names=['CT-Address-0060', 'CT-Address-0061']
463             >>> )
464             >>>
465         """
466         limit_types = ('deviceconfig', 'network', 'platform', 'vsys')
467         if _type not in limit_types:
468             raise Exception('"_type" must be one of {limit_types}'.format(limit_types=limit_types))
469         rel_path = rel_path.strip('/')
470 
471         if _type in ('deviceconfig', 'network', 'platform'):
472             rel_path = os.path.join(_type, rel_path).replace('\\', '/')
473             if member_names:
474                 members = ' or '.join(["text()='{name}'".format(name=name) for name in member_names])
475                 xpath = (
476                     "/config/devices/entry[@name='localhost.localdomain']/{rel_path}/entry[@name='{entry_name}']/"
477                     "static/member[{members}]"
478                 ).format(rel_path=rel_path, entry_name=entry_name, members=members)
479             else:
480                 xpath = (
481                     "/config/devices/entry[@name='localhost.localdomain']/{rel_path}/entry[@name='{entry_name}']"
482                 ).format(rel_path=rel_path, entry_name=entry_name)
483         else:  # 'vsys':
484             if member_names:
485                 members = ' or '.join(["text()='{name}'".format(name=name) for name in member_names])
486                 xpath = (
487                     "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}/"
488                     "entry[@name='{entry_name}']/static/member[{members}]"
489                 ).format(rel_path=rel_path, entry_name=entry_name, members=members)
490             else:
491                 xpath = (
492                     "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/{rel_path}/"
493                     "entry[@name='{entry_name}']/static/member"
494                 ).format(rel_path=rel_path, entry_name=entry_name)
495         params = {
496             'type': 'config',
497             'action': 'delete',
498             'key': self.key,
499             'xpath': xpath,
500         }
501         return self._request(params=params)
502 
503     def delete_config(self, _type, rel_path, entry_name):
504         """
505         :param _type:
506                     deviceconfig
507                     network
508                     platform
509                     vsys
510         :param rel_path: 'interface/ethernet'
511         :param entry_name: 'ethernet1/1' or ['ethernet1/1', 'ethernet1/2']
512         :return: {
513             'code': '19',
514             'msg': 'Success: Command completed successfully.',
515             'success': True,
516             'result': Dict,
517         }
518         # Usage:
519             >>> pa = PaloAltoFirewallAPI(api_key='x')
520             >>> pa.delete_config(_type='network', rel_path='interface/ethernet', entry_name='ethernet name')
521             >>> pa.delete_config(_type='vsys', rel_path='service', entry_name='service name')
522             >>> pa.delete_config(_type='vsys', rel_path='address', entry_name='address name')
523             >>> pa.delete_config(_type='vsys', rel_path='address-group', entry_name='address-group name')
524             >>> pa.delete_config(_type='vsys', rel_path='rulebase/nat/rules', entry_name='rule name')
525         """
526         return self._sp_config(_type=_type, rel_path=rel_path, entry_name=entry_name, action='delete')
527 
528     def move_config_position(self, rel_path, entry_name, where='top', _type='vsys'):
529         """
530         :param rel_path:
531         :param entry_name:
532         :param where:
533         :param _type:
534         :return:
535         """
536         return self._sp_config(
537             _type=_type, rel_path=rel_path, entry_name=entry_name, action='move', where=where
538         )
539 
540     def is_backup(self):
541         cmd = '<show><high-availability><state></state></high-availability></show>'
542         params = {
543             'type': 'op',
544             'key': self.key,
545             'cmd': cmd,
546         }
547         try:
548             res = requests.post(url=self.url, params=params, verify=False)
549             state = xmltodict.parse(res.content).get('response').get('result').get('group').get('local-info').get(
550                 'state')
551             if state == 'passive':
552                 return True
553         except:
554             pass
555         return False
556 
557     def revert(self, command='<revert><config></config></revert>'):
558         """
559         :param command: <revert><config></config></revert>
560         :return:
561         """
562         return self.operational_commands(command=command)
563 
564     def commit(self, command='<commit></commit>'):
565         """
566         :param command: '<commit></commit>'
567         :return: str
568         """
569         params = {
570             'type': 'commit',
571             'key': self.key,
572             'cmd': command
573         }
574         return self._request(params=params)
575 
576     def acquire_lock(self, comment):
577         command = '''
578             <request>
579                 <config-lock>
580                     <add><comment>{comment}</comment></add>
581                 </config-lock>
582             </request>
583         '''.format(comment=comment)
584         return self.operational_commands(command)
585 
586     def release_lock(self, command='<request><config-lock><remove></remove></config-lock></request>'):
587         return self.operational_commands(command)
588 
589     def operational_commands(self, command):
590         """
591         :param command: '<show><high-availability><state></state></high-availability></show>'
592         :return:
593         """
594         params = {
595             'type': 'op',
596             'key': self.key,
597             'cmd': command,
598         }
599         return self._request(params=params)
600 
601     def export_configuration(self):
602         """
603         :return: xml
604         """
605         params = {
606             'type': 'export',
607             'key': self.key,
608             'category': 'configuration'
609         }
610         result = {
611             'success': False,
612         }
613         try:
614             xml = requests.get(url=self.url, params=params, verify=False).text
615             result.update(success=True, result=xml)
616         except Exception as e:
617             result.update(success=False, error=str(e))
618         return result
619 
620     def show_job_status(self, job_id):
621         command = '<show><jobs><id>{}</id></jobs></show>'.format(job_id)
622         return self.operational_commands(command)
623 
624 
625 def now_time():
626     return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
627 
628 
629 class PAChangeBase(object):
630     def __init__(self, ip, api_key, lock_comment='PYTHON automation deployment lock(object updates)'):
631         self.ip = ip
632         self.api_key = api_key
633         self._pa = PaloAltoFirewallAPI(ip, api_key=api_key)
634         self.lock_comment = lock_comment
635 
636     def has_pending_changes(self):
637         command = '<check><pending-changes></pending-changes></check>'
638         res = self._pa.operational_commands(command)
639         if not res.get('success') or res.get('result') != 'no':
640             return True
641         return False
642 
643     def has_lock(self):
644         command = '<show><config-locks></config-locks></show>'
645         res = self._pa.operational_commands(command)
646         if not res.get('success'):
647             return False
648         result = res.get('result')
649         locks = result.get('config-locks')
650         if not locks:
651             return False
652 
653         # 如果锁是本程序的锁, 则释放锁
654         if locks.get('entry').get('comment') == self.lock_comment:
655             self.release_lock()
656             return False
657         else:
658             return True
659 
660     def acquire_lock(self):
661         res = self._pa.acquire_lock(comment=self.lock_comment)
662         if not res.get('success'):
663             return False
664         if 'Successfully acquired lock' in res.get('result'):
665             return True
666         return False
667 
668     def release_lock(self):
669         res = self._pa.release_lock()
670         if not res.get('success'):
671             return False
672         if 'Config lock released' in res.get('result'):
673             return True
674         return False
675 
676     def commit(self, callback_res):
677         res = self._pa.commit()
678         if not res.get('success'):
679             return False
680         job_id = res.get('result').get('job')
681         while True:
682             res = self._pa.show_job_status(job_id=job_id)
683             if not res.get('success'):
684                 return False
685             job = res.get('result').get('job')
686             job_details = job.get('details')
687             if not job_details:
688                 time.sleep(1)
689                 continue
690             if 'Commit failed' in str(job_details):
691                 for line in job_details.get('line'):
692                     callback_res['msg'].append('{} {}'.format(now_time(), line))
693                 return False
694             return True
695         return True
696 
697     def revert(self):
698         res = self._pa.revert()
699         if not res.get('success'):
700             return False
701         return True
702 
703     def do_change(self, **kwargs):
704         raise Exception('Must be overwrite this function')
705 
706     def run(self, **kwargs):
707         result = {'success': True, 'ip': self.ip, 'msg': []}
708         try:
709             # 如果有pending changes, 则直接返回
710             if self.has_pending_changes():
711                 result['success'] = False
712                 result['msg'].append('{} There are pending changes'.format(now_time()))
713                 return result
714             result['msg'].append('{} There are no pending changes'.format(now_time()))
715 
716             if self.has_lock():
717                 result['success'] = False
718                 result['msg'].append('{} Config lock was not released'.format(now_time()))
719                 return result
720 
721             if not self.acquire_lock():
722                 result['success'] = False
723                 result['msg'].append('{} Acquire config lock failed'.format(now_time()))
724                 return result
725             result['msg'].append('{} Acquire config lock successful'.format(now_time()))
726             try:
727                 self.do_change(result=result, **kwargs)
728                 if self.commit(result):
729                     result['msg'].append('{} Commit successful'.format(now_time()))
730                 else:
731                     result['success'] = False
732                     result['msg'].append('{} Commit failed'.format(now_time()))
733             except Exception as e:
734                 logging.error(e)
735                 result['success'] = False
736                 result['msg'].append('{} {}'.format(now_time(), str(e)))
737             finally:
738                 self.release_lock()
739                 result['msg'].append('{} Release config lock successful'.format(now_time()))
740         except Exception as e:
741             result['success'] = False
742             result['msg'].append('{} {}'.format(now_time(), str(e)))
743         return result
744 
745 
746 def test():
747     # get top app
748     result = {
749         'top_app_src': [],
750         'top_app_dst': [],
751     }
752     try:
753         ip = '1.1.1.1'
754         username = 'username'
755         password = 'password'
756         api_key = 'api_key'
757         # PaloAltoFirewallAPI(ip=ip, username=username, password=password)
758         pa = PaloAltoFirewallAPI(ip=ip, api_key='key')
759         for direction in ['src', 'dst']:
760             res = pa.get_report(
761                 report_name='top-%s-summary' % direction, period='last-hour', top_n=10,
762                 wait_for_result=timeout
763             )
764             if res.get('success'):
765                 entries = res.get('report', {}).get('entry', [])
766                 if not entries:
767                     continue
768                 temp = []
769                 user_key = '%ssuer' % direction
770                 for entry in entries:
771                     user = entry.get(user_key) or 'unknown'
772                     volume_bytes = int(entry.get('bytes'))
773                     volume_mb = volume_bytes / 1000.0 / 1000.0
774                     temp.append({
775                         'Name': user,
776                         'volume': '%2s MB' % round(volume_mb, 2),
777                         'traffic': '%2s %%' % round(
778                             volume_mb * 8 / link_bandwidth / (60 * 60 * 24) * 100, 2
779                         )
780                     })
781                 result['top_app_%s' % direction] = temp
782     except Exception as e:
783         logging.error(e)
784 
785 
786 def test2():
787     class PBRObjectChanger(PAChangeBase):
788         def do_change(self, **kwargs):
789             # Business code
790             pass
791 
792 
793 if __name__ == '__main__':
794     test()
795     test2()

 

posted @ 2021-01-06 16:54  士为知己  阅读(131)  评论(0)    收藏  举报