1#!/usr/local/bin/python3.8 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17# 18 19from __future__ import (absolute_import, division, print_function) 20__metaclass__ = type 21 22DOCUMENTATION = ''' 23--- 24module: ce_info_center_trap 25short_description: Manages information center trap configuration on HUAWEI CloudEngine switches. 26description: 27 - Manages information center trap configurations on HUAWEI CloudEngine switches. 28author: 29 - wangdezhuang (@QijunPan) 30notes: 31 - This module requires the netconf system service be enabled on the remote device being managed. 32 - Recommended connection is C(netconf). 33 - This module also works with C(local) connections for legacy playbooks. 34options: 35 state: 36 description: 37 - Specify desired state of the resource. 38 default: present 39 choices: ['present','absent'] 40 trap_time_stamp: 41 description: 42 - Timestamp format of alarm information. 43 choices: ['date_boot', 'date_second', 'date_tenthsecond', 'date_millisecond', 'shortdate_second', 44 'shortdate_tenthsecond', 'shortdate_millisecond', 'formatdate_second', 'formatdate_tenthsecond', 45 'formatdate_millisecond'] 46 trap_buff_enable: 47 description: 48 - Whether a trap buffer is enabled to output information. 49 default: no_use 50 choices: ['no_use','true','false'] 51 trap_buff_size: 52 description: 53 - Size of a trap buffer. 54 The value is an integer ranging from 0 to 1024. The default value is 256. 55 module_name: 56 description: 57 - Module name of the rule. 58 The value is a string of 1 to 31 case-insensitive characters. The default value is default. 59 Please use lower-case letter, such as [aaa, acl, arp, bfd]. 60 channel_id: 61 description: 62 - Number of a channel. 63 The value is an integer ranging from 0 to 9. The default value is 0. 64 trap_enable: 65 description: 66 - Whether a device is enabled to output alarms. 67 default: no_use 68 choices: ['no_use','true','false'] 69 trap_level: 70 description: 71 - Trap level permitted to output. 72 choices: ['emergencies', 'alert', 'critical', 'error', 'warning', 'notification', 73 'informational', 'debugging'] 74''' 75 76EXAMPLES = ''' 77 78- name: CloudEngine info center trap test 79 hosts: cloudengine 80 connection: local 81 gather_facts: no 82 vars: 83 cli: 84 host: "{{ inventory_hostname }}" 85 port: "{{ ansible_ssh_port }}" 86 username: "{{ username }}" 87 password: "{{ password }}" 88 transport: cli 89 90 tasks: 91 92 - name: "Config trap buffer" 93 community.network.ce_info_center_trap: 94 state: present 95 trap_buff_enable: true 96 trap_buff_size: 768 97 provider: "{{ cli }}" 98 99 - name: "Undo trap buffer" 100 community.network.ce_info_center_trap: 101 state: absent 102 trap_buff_enable: true 103 trap_buff_size: 768 104 provider: "{{ cli }}" 105 106 - name: "Config trap module log level" 107 community.network.ce_info_center_trap: 108 state: present 109 module_name: aaa 110 channel_id: 1 111 trap_enable: true 112 trap_level: error 113 provider: "{{ cli }}" 114 115 - name: "Undo trap module log level" 116 community.network.ce_info_center_trap: 117 state: absent 118 module_name: aaa 119 channel_id: 1 120 trap_enable: true 121 trap_level: error 122 provider: "{{ cli }}" 123''' 124 125RETURN = ''' 126changed: 127 description: check to see if a change was made on the device 128 returned: always 129 type: bool 130 sample: true 131proposed: 132 description: k/v pairs of parameters passed into module 133 returned: always 134 type: dict 135 sample: {"state": "present", "trap_buff_enable": "true", "trap_buff_size": "768"} 136existing: 137 description: k/v pairs of existing aaa server 138 returned: always 139 type: dict 140 sample: {"icTrapBuffEn": "false", "trapBuffSize": "256"} 141end_state: 142 description: k/v pairs of aaa params after module execution 143 returned: always 144 type: dict 145 sample: {"icTrapBuffEn": "true", "trapBuffSize": "768"} 146updates: 147 description: command sent to the device 148 returned: always 149 type: list 150 sample: ["info-center trapbuffer", "info-center trapbuffer size 768"] 151''' 152 153from xml.etree import ElementTree 154from ansible.module_utils.basic import AnsibleModule 155from ansible_collections.community.network.plugins.module_utils.network.cloudengine.ce import get_nc_config, set_nc_config, ce_argument_spec 156 157 158# get info center trap global 159CE_GET_TRAP_GLOBAL_HEADER = """ 160 <filter type="subtree"> 161 <syslog xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 162 <globalParam> 163""" 164CE_GET_TRAP_GLOBAL_TAIL = """ 165 </globalParam> 166 </syslog> 167 </filter> 168""" 169# merge info center trap global 170CE_MERGE_TRAP_GLOBAL_HEADER = """ 171 <config> 172 <syslog xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 173 <globalParam operation="merge"> 174""" 175CE_MERGE_TRAP_GLOBAL_TAIL = """ 176 </globalParam> 177 </syslog> 178 </config> 179""" 180 181# get info center trap source 182CE_GET_TRAP_SOURCE_HEADER = """ 183 <filter type="subtree"> 184 <syslog xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 185 <icSources> 186 <icSource> 187""" 188CE_GET_TRAP_SOURCE_TAIL = """ 189 </icSource> 190 </icSources> 191 </syslog> 192 </filter> 193""" 194# merge info center trap source 195CE_MERGE_TRAP_SOURCE_HEADER = """ 196 <config> 197 <syslog xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 198 <icSources> 199 <icSource operation="merge"> 200""" 201CE_MERGE_TRAP_SOURCE_TAIL = """ 202 </icSource> 203 </icSources> 204 </syslog> 205 </config> 206""" 207# delete info center trap source 208CE_DELETE_TRAP_SOURCE_HEADER = """ 209 <config> 210 <syslog xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 211 <icSources> 212 <icSource operation="delete"> 213""" 214CE_DELETE_TRAP_SOURCE_TAIL = """ 215 </icSource> 216 </icSources> 217 </syslog> 218 </config> 219""" 220 221TIME_STAMP_DICT = {"date_boot": "boot", 222 "date_second": "date precision-time second", 223 "date_tenthsecond": "date precision-time tenth-second", 224 "date_millisecond": "date precision-time millisecond", 225 "shortdate_second": "short-date precision-time second", 226 "shortdate_tenthsecond": "short-date precision-time tenth-second", 227 "shortdate_millisecond": "short-date precision-time millisecond", 228 "formatdate_second": "format-date precision-time second", 229 "formatdate_tenthsecond": "format-date precision-time tenth-second", 230 "formatdate_millisecond": "format-date precision-time millisecond"} 231 232CHANNEL_DEFAULT_TRAP_STATE = {"0": "true", 233 "1": "true", 234 "2": "true", 235 "3": "true", 236 "4": "false", 237 "5": "true", 238 "6": "true", 239 "7": "true", 240 "8": "true", 241 "9": "true"} 242 243CHANNEL_DEFAULT_TRAP_LEVEL = {"0": "debugging", 244 "1": "debugging", 245 "2": "debugging", 246 "3": "debugging", 247 "4": "debugging", 248 "5": "debugging", 249 "6": "debugging", 250 "7": "debugging", 251 "8": "debugging", 252 "9": "debugging"} 253 254 255class InfoCenterTrap(object): 256 """ Manages info center trap configuration """ 257 258 def __init__(self, **kwargs): 259 """ Init function """ 260 261 # argument spec 262 argument_spec = kwargs["argument_spec"] 263 self.spec = argument_spec 264 self.module = AnsibleModule(argument_spec=self.spec, supports_check_mode=True) 265 266 # module args 267 self.state = self.module.params['state'] 268 self.trap_time_stamp = self.module.params['trap_time_stamp'] or None 269 self.trap_buff_enable = self.module.params['trap_buff_enable'] 270 self.trap_buff_size = self.module.params['trap_buff_size'] or None 271 self.module_name = self.module.params['module_name'] or None 272 self.channel_id = self.module.params['channel_id'] or None 273 self.trap_enable = self.module.params['trap_enable'] 274 self.trap_level = self.module.params['trap_level'] or None 275 276 # cur config 277 self.cur_global_cfg = dict() 278 self.cur_source_cfg = dict() 279 280 # state 281 self.changed = False 282 self.updates_cmd = list() 283 self.results = dict() 284 self.proposed = dict() 285 self.existing = dict() 286 self.end_state = dict() 287 288 def netconf_get_config(self, conf_str): 289 """ Netconf get config """ 290 291 xml_str = get_nc_config(self.module, conf_str) 292 293 return xml_str 294 295 def netconf_set_config(self, conf_str): 296 """ Netconf set config """ 297 298 xml_str = set_nc_config(self.module, conf_str) 299 300 return xml_str 301 302 def check_global_args(self): 303 """ Check global args """ 304 305 need_cfg = False 306 find_flag = False 307 self.cur_global_cfg["global_cfg"] = [] 308 309 if self.trap_time_stamp or self.trap_buff_enable != 'no_use' or self.trap_buff_size: 310 if self.trap_buff_size: 311 if self.trap_buff_size.isdigit(): 312 if int(self.trap_buff_size) < 0 or int(self.trap_buff_size) > 1024: 313 self.module.fail_json( 314 msg='Error: The value of trap_buff_size is out of [0 - 1024].') 315 else: 316 self.module.fail_json( 317 msg='Error: The trap_buff_size is not digit.') 318 319 conf_str = CE_GET_TRAP_GLOBAL_HEADER 320 321 if self.trap_time_stamp: 322 conf_str += "<trapTimeStamp></trapTimeStamp>" 323 if self.trap_buff_enable != 'no_use': 324 conf_str += "<icTrapBuffEn></icTrapBuffEn>" 325 if self.trap_buff_size: 326 conf_str += "<trapBuffSize></trapBuffSize>" 327 328 conf_str += CE_GET_TRAP_GLOBAL_TAIL 329 recv_xml = self.netconf_get_config(conf_str=conf_str) 330 331 if "<data/>" in recv_xml: 332 find_flag = False 333 else: 334 xml_str = recv_xml.replace('\r', '').replace('\n', '').\ 335 replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ 336 replace('xmlns="http://www.huawei.com/netconf/vrp"', "") 337 338 root = ElementTree.fromstring(xml_str) 339 global_cfg = root.findall("syslog/globalParam") 340 if global_cfg: 341 for tmp in global_cfg: 342 tmp_dict = dict() 343 for site in tmp: 344 if site.tag in ["trapTimeStamp", "icTrapBuffEn", "trapBuffSize"]: 345 tmp_dict[site.tag] = site.text 346 347 self.cur_global_cfg["global_cfg"].append(tmp_dict) 348 349 if self.cur_global_cfg["global_cfg"]: 350 for tmp in self.cur_global_cfg["global_cfg"]: 351 find_flag = True 352 353 if self.trap_time_stamp and tmp.get("trapTimeStamp").lower() != self.trap_time_stamp: 354 find_flag = False 355 if self.trap_buff_enable != 'no_use' and tmp.get("icTrapBuffEn") != self.trap_buff_enable: 356 find_flag = False 357 if self.trap_buff_size and tmp.get("trapBuffSize") != self.trap_buff_size: 358 find_flag = False 359 360 if find_flag: 361 break 362 else: 363 find_flag = False 364 365 if self.state == "present": 366 need_cfg = bool(not find_flag) 367 else: 368 need_cfg = bool(find_flag) 369 370 self.cur_global_cfg["need_cfg"] = need_cfg 371 372 def check_source_args(self): 373 """ Check source args """ 374 375 need_cfg = False 376 find_flag = False 377 self.cur_source_cfg["source_cfg"] = list() 378 379 if self.module_name: 380 if len(self.module_name) < 1 or len(self.module_name) > 31: 381 self.module.fail_json( 382 msg='Error: The module_name is out of [1 - 31].') 383 384 if not self.channel_id: 385 self.module.fail_json( 386 msg='Error: Please input channel_id at the same time.') 387 388 if self.channel_id: 389 if self.channel_id.isdigit(): 390 if int(self.channel_id) < 0 or int(self.channel_id) > 9: 391 self.module.fail_json( 392 msg='Error: The value of channel_id is out of [0 - 9].') 393 else: 394 self.module.fail_json( 395 msg='Error: The channel_id is not digit.') 396 397 conf_str = CE_GET_TRAP_SOURCE_HEADER 398 399 if self.module_name != "default": 400 conf_str += "<moduleName>%s</moduleName>" % self.module_name.upper() 401 else: 402 conf_str += "<moduleName>default</moduleName>" 403 404 if self.channel_id: 405 conf_str += "<icChannelId></icChannelId>" 406 if self.trap_enable != 'no_use': 407 conf_str += "<trapEnFlg></trapEnFlg>" 408 if self.trap_level: 409 conf_str += "<trapEnLevel></trapEnLevel>" 410 411 conf_str += CE_GET_TRAP_SOURCE_TAIL 412 recv_xml = self.netconf_get_config(conf_str=conf_str) 413 414 if "<data/>" in recv_xml: 415 find_flag = False 416 else: 417 xml_str = recv_xml.replace('\r', '').replace('\n', '').\ 418 replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ 419 replace('xmlns="http://www.huawei.com/netconf/vrp"', "") 420 421 root = ElementTree.fromstring(xml_str) 422 source_cfg = root.findall("syslog/icSources/icSource") 423 if source_cfg: 424 for tmp in source_cfg: 425 tmp_dict = dict() 426 for site in tmp: 427 if site.tag in ["moduleName", "icChannelId", "trapEnFlg", "trapEnLevel"]: 428 tmp_dict[site.tag] = site.text 429 430 self.cur_source_cfg["source_cfg"].append(tmp_dict) 431 432 if self.cur_source_cfg["source_cfg"]: 433 for tmp in self.cur_source_cfg["source_cfg"]: 434 find_flag = True 435 436 if self.module_name and tmp.get("moduleName").lower() != self.module_name.lower(): 437 find_flag = False 438 if self.channel_id and tmp.get("icChannelId") != self.channel_id: 439 find_flag = False 440 if self.trap_enable != 'no_use' and tmp.get("trapEnFlg") != self.trap_enable: 441 find_flag = False 442 if self.trap_level and tmp.get("trapEnLevel") != self.trap_level: 443 find_flag = False 444 445 if find_flag: 446 break 447 else: 448 find_flag = False 449 450 if self.state == "present": 451 need_cfg = bool(not find_flag) 452 else: 453 need_cfg = bool(find_flag) 454 455 self.cur_source_cfg["need_cfg"] = need_cfg 456 457 def get_proposed(self): 458 """ Get proposed """ 459 460 self.proposed["state"] = self.state 461 462 if self.trap_time_stamp: 463 self.proposed["trap_time_stamp"] = self.trap_time_stamp 464 if self.trap_buff_enable != 'no_use': 465 self.proposed["trap_buff_enable"] = self.trap_buff_enable 466 if self.trap_buff_size: 467 self.proposed["trap_buff_size"] = self.trap_buff_size 468 if self.module_name: 469 self.proposed["module_name"] = self.module_name 470 if self.channel_id: 471 self.proposed["channel_id"] = self.channel_id 472 if self.trap_enable != 'no_use': 473 self.proposed["trap_enable"] = self.trap_enable 474 if self.trap_level: 475 self.proposed["trap_level"] = self.trap_level 476 477 def get_existing(self): 478 """ Get existing """ 479 480 if self.cur_global_cfg["global_cfg"]: 481 self.existing["global_cfg"] = self.cur_global_cfg["global_cfg"] 482 if self.cur_source_cfg["source_cfg"]: 483 self.existing["source_cfg"] = self.cur_source_cfg["source_cfg"] 484 485 def get_end_state(self): 486 """ Get end state """ 487 488 self.check_global_args() 489 if self.cur_global_cfg["global_cfg"]: 490 self.end_state["global_cfg"] = self.cur_global_cfg["global_cfg"] 491 492 self.check_source_args() 493 if self.cur_source_cfg["source_cfg"]: 494 self.end_state["source_cfg"] = self.cur_source_cfg["source_cfg"] 495 496 def merge_trap_global(self): 497 """ Merge trap global """ 498 499 conf_str = CE_MERGE_TRAP_GLOBAL_HEADER 500 501 if self.trap_time_stamp: 502 conf_str += "<trapTimeStamp>%s</trapTimeStamp>" % self.trap_time_stamp.upper() 503 if self.trap_buff_enable != 'no_use': 504 conf_str += "<icTrapBuffEn>%s</icTrapBuffEn>" % self.trap_buff_enable 505 if self.trap_buff_size: 506 conf_str += "<trapBuffSize>%s</trapBuffSize>" % self.trap_buff_size 507 508 conf_str += CE_MERGE_TRAP_GLOBAL_TAIL 509 510 recv_xml = self.netconf_set_config(conf_str=conf_str) 511 512 if "<ok/>" not in recv_xml: 513 self.module.fail_json(msg='Error: Merge trap global failed.') 514 515 if self.trap_time_stamp: 516 cmd = "info-center timestamp trap " + TIME_STAMP_DICT.get(self.trap_time_stamp) 517 self.updates_cmd.append(cmd) 518 if self.trap_buff_enable != 'no_use': 519 if self.trap_buff_enable == "true": 520 cmd = "info-center trapbuffer" 521 else: 522 cmd = "undo info-center trapbuffer" 523 self.updates_cmd.append(cmd) 524 if self.trap_buff_size: 525 cmd = "info-center trapbuffer size %s" % self.trap_buff_size 526 self.updates_cmd.append(cmd) 527 528 self.changed = True 529 530 def delete_trap_global(self): 531 """ Delete trap global """ 532 533 conf_str = CE_MERGE_TRAP_GLOBAL_HEADER 534 535 if self.trap_time_stamp: 536 conf_str += "<trapTimeStamp>DATE_SECOND</trapTimeStamp>" 537 if self.trap_buff_enable != 'no_use': 538 conf_str += "<icTrapBuffEn>false</icTrapBuffEn>" 539 if self.trap_buff_size: 540 conf_str += "<trapBuffSize>256</trapBuffSize>" 541 542 conf_str += CE_MERGE_TRAP_GLOBAL_TAIL 543 544 recv_xml = self.netconf_set_config(conf_str=conf_str) 545 546 if "<ok/>" not in recv_xml: 547 self.module.fail_json(msg='Error: delete trap global failed.') 548 549 if self.trap_time_stamp: 550 cmd = "undo info-center timestamp trap" 551 self.updates_cmd.append(cmd) 552 if self.trap_buff_enable != 'no_use': 553 cmd = "undo info-center trapbuffer" 554 self.updates_cmd.append(cmd) 555 if self.trap_buff_size: 556 cmd = "undo info-center trapbuffer size" 557 self.updates_cmd.append(cmd) 558 559 self.changed = True 560 561 def merge_trap_source(self): 562 """ Merge trap source """ 563 564 conf_str = CE_MERGE_TRAP_SOURCE_HEADER 565 566 if self.module_name: 567 conf_str += "<moduleName>%s</moduleName>" % self.module_name 568 if self.channel_id: 569 conf_str += "<icChannelId>%s</icChannelId>" % self.channel_id 570 if self.trap_enable != 'no_use': 571 conf_str += "<trapEnFlg>%s</trapEnFlg>" % self.trap_enable 572 if self.trap_level: 573 conf_str += "<trapEnLevel>%s</trapEnLevel>" % self.trap_level 574 575 conf_str += CE_MERGE_TRAP_SOURCE_TAIL 576 577 recv_xml = self.netconf_set_config(conf_str=conf_str) 578 579 if "<ok/>" not in recv_xml: 580 self.module.fail_json(msg='Error: Merge trap source failed.') 581 582 cmd = "info-center source" 583 if self.module_name: 584 cmd += " %s" % self.module_name 585 if self.channel_id: 586 cmd += " channel %s" % self.channel_id 587 if self.trap_enable != 'no_use': 588 if self.trap_enable == "true": 589 cmd += " trap state on" 590 else: 591 cmd += " trap state off" 592 if self.trap_level: 593 cmd += " level %s" % self.trap_level 594 595 self.updates_cmd.append(cmd) 596 self.changed = True 597 598 def delete_trap_source(self): 599 """ Delete trap source """ 600 601 if self.trap_enable == 'no_use' and not self.trap_level: 602 conf_str = CE_DELETE_TRAP_SOURCE_HEADER 603 if self.module_name: 604 conf_str += "<moduleName>%s</moduleName>" % self.module_name 605 if self.channel_id: 606 conf_str += "<icChannelId>%s</icChannelId>" % self.channel_id 607 conf_str += CE_DELETE_TRAP_SOURCE_TAIL 608 else: 609 conf_str = CE_MERGE_TRAP_SOURCE_HEADER 610 if self.module_name: 611 conf_str += "<moduleName>%s</moduleName>" % self.module_name 612 if self.channel_id: 613 conf_str += "<icChannelId>%s</icChannelId>" % self.channel_id 614 if self.trap_enable != 'no_use': 615 conf_str += "<trapEnFlg>%s</trapEnFlg>" % CHANNEL_DEFAULT_TRAP_STATE.get(self.channel_id) 616 if self.trap_level: 617 conf_str += "<trapEnLevel>%s</trapEnLevel>" % CHANNEL_DEFAULT_TRAP_LEVEL.get(self.channel_id) 618 conf_str += CE_MERGE_TRAP_SOURCE_TAIL 619 620 recv_xml = self.netconf_set_config(conf_str=conf_str) 621 622 if "<ok/>" not in recv_xml: 623 self.module.fail_json(msg='Error: Delete trap source failed.') 624 625 cmd = "undo info-center source" 626 if self.module_name: 627 cmd += " %s" % self.module_name 628 if self.channel_id: 629 cmd += " channel %s" % self.channel_id 630 if self.trap_enable != 'no_use': 631 cmd += " trap state" 632 if self.trap_level: 633 cmd += " level" 634 635 self.updates_cmd.append(cmd) 636 self.changed = True 637 638 def work(self): 639 """ work function """ 640 641 self.check_global_args() 642 self.check_source_args() 643 self.get_proposed() 644 self.get_existing() 645 646 if self.state == "present": 647 if self.cur_global_cfg["need_cfg"]: 648 self.merge_trap_global() 649 if self.cur_source_cfg["need_cfg"]: 650 self.merge_trap_source() 651 652 else: 653 if self.cur_global_cfg["need_cfg"]: 654 self.delete_trap_global() 655 if self.cur_source_cfg["need_cfg"]: 656 self.delete_trap_source() 657 658 self.get_end_state() 659 660 self.results['changed'] = self.changed 661 self.results['proposed'] = self.proposed 662 self.results['existing'] = self.existing 663 self.results['end_state'] = self.end_state 664 self.results['updates'] = self.updates_cmd 665 666 self.module.exit_json(**self.results) 667 668 669def main(): 670 """ Module main """ 671 672 argument_spec = dict( 673 state=dict(choices=['present', 'absent'], default='present'), 674 trap_time_stamp=dict(choices=['date_boot', 'date_second', 'date_tenthsecond', 675 'date_millisecond', 'shortdate_second', 'shortdate_tenthsecond', 676 'shortdate_millisecond', 'formatdate_second', 'formatdate_tenthsecond', 677 'formatdate_millisecond']), 678 trap_buff_enable=dict(type='str', default='no_use', choices=['no_use', 'true', 'false']), 679 trap_buff_size=dict(type='str'), 680 module_name=dict(type='str'), 681 channel_id=dict(type='str'), 682 trap_enable=dict(type='str', default='no_use', choices=['no_use', 'true', 'false']), 683 trap_level=dict(choices=['emergencies', 'alert', 'critical', 'error', 'warning', 'notification', 684 'informational', 'debugging']) 685 ) 686 687 argument_spec.update(ce_argument_spec) 688 module = InfoCenterTrap(argument_spec=argument_spec) 689 module.work() 690 691 692if __name__ == '__main__': 693 main() 694