diff --git a/lib/ansible/modules/network/cloudengine/ce_info_center_trap.py b/lib/ansible/modules/network/cloudengine/ce_info_center_trap.py new file mode 100644 index 0000000000..3beb5863d9 --- /dev/null +++ b/lib/ansible/modules/network/cloudengine/ce_info_center_trap.py @@ -0,0 +1,704 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'metadata_version': '1.0'} + +DOCUMENTATION = ''' +--- +module: ce_info_center_trap +version_added: "2.4" +short_description: Manages information center trap configuration on HUAWEI CloudEngine switches. +description: + - Manages information center trap configurations on HUAWEI CloudEngine switches. +author: + - wangdezhuang (@CloudEngine-Ansible) +options: + state: + description: + - Specify desired state of the resource. + required: false + default: present + choices: ['present','absent'] + trap_time_stamp: + description: + - Timestamp format of alarm information. + required: false + default: null + choices: ['date_boot', 'date_second', 'date_tenthsecond', 'date_millisecond', 'shortdate_second', + 'shortdate_tenthsecond', 'shortdate_millisecond', 'formatdate_second', 'formatdate_tenthsecond', + 'formatdate_millisecond'] + trap_buff_enable: + description: + - Whether a trap buffer is enabled to output information. + required: false + default: no_use + choices: ['no_use','true','false'] + trap_buff_size: + description: + - Size of a trap buffer. + The value is an integer ranging from 0 to 1024. The default value is 256. + required: false + default: null + module_name: + description: + - Module name of the rule. + The value is a string of 1 to 31 case-insensitive characters. The default value is default. + Please use lower-case letter, such as [aaa, acl, arp, bfd]. + required: false + default: null + channel_id: + description: + - Number of a channel. + The value is an integer ranging from 0 to 9. The default value is 0. + required: false + default: null + trap_enable: + description: + - Whether a device is enabled to output alarms. + required: false + default: no_use + choices: ['no_use','true','false'] + trap_level: + description: + - Trap level permitted to output. + required: false + default: null + choices: ['emergencies', 'alert', 'critical', 'error', 'warning', 'notification', + 'informational', 'debugging'] +''' + +EXAMPLES = ''' + +- name: CloudEngine info center trap test + hosts: cloudengine + connection: local + gather_facts: no + vars: + cli: + host: "{{ inventory_hostname }}" + port: "{{ ansible_ssh_port }}" + username: "{{ username }}" + password: "{{ password }}" + transport: cli + + tasks: + + - name: "Config trap buffer" + ce_info_center_trap: + state: present + trap_buff_enable: true + trap_buff_size: 768 + provider: "{{ cli }}" + + - name: "Undo trap buffer" + ce_info_center_trap: + state: absent + trap_buff_enable: true + trap_buff_size: 768 + provider: "{{ cli }}" + + - name: "Config trap module log level" + ce_info_center_trap: + state: present + module_name: aaa + channel_id: 1 + trap_enable: true + trap_level: error + provider: "{{ cli }}" + + - name: "Undo trap module log level" + ce_info_center_trap: + state: absent + module_name: aaa + channel_id: 1 + trap_enable: true + trap_level: error + provider: "{{ cli }}" +''' + +RETURN = ''' +changed: + description: check to see if a change was made on the device + returned: always + type: boolean + sample: true +proposed: + description: k/v pairs of parameters passed into module + returned: always + type: dict + sample: {"state": "present", "trap_buff_enable": "true", "trap_buff_size": "768"} +existing: + description: k/v pairs of existing aaa server + returned: always + type: dict + sample: {"icTrapBuffEn": "false", "trapBuffSize": "256"} +end_state: + description: k/v pairs of aaa params after module execution + returned: always + type: dict + sample: {"icTrapBuffEn": "true", "trapBuffSize": "768"} +updates: + description: command sent to the device + returned: always + type: list + sample: ["info-center trapbuffer", "info-center trapbuffer size 768"] +''' + +from xml.etree import ElementTree +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ce import get_nc_config, set_nc_config, ce_argument_spec + + +# get info center trap global +CE_GET_TRAP_GLOBAL_HEADER = """ + + + +""" +CE_GET_TRAP_GLOBAL_TAIL = """ + + + +""" +# merge info center trap global +CE_MERGE_TRAP_GLOBAL_HEADER = """ + + + +""" +CE_MERGE_TRAP_GLOBAL_TAIL = """ + + + +""" + +# get info center trap source +CE_GET_TRAP_SOURCE_HEADER = """ + + + + +""" +CE_GET_TRAP_SOURCE_TAIL = """ + + + + +""" +# merge info center trap source +CE_MERGE_TRAP_SOURCE_HEADER = """ + + + + +""" +CE_MERGE_TRAP_SOURCE_TAIL = """ + + + + +""" +# delete info center trap source +CE_DELETE_TRAP_SOURCE_HEADER = """ + + + + +""" +CE_DELETE_TRAP_SOURCE_TAIL = """ + + + + +""" + +TIME_STAMP_DICT = {"date_boot": "boot", + "date_second": "date precision-time second", + "date_tenthsecond": "date precision-time tenth-second", + "date_millisecond": "date precision-time millisecond", + "shortdate_second": "short-date precision-time second", + "shortdate_tenthsecond": "short-date precision-time tenth-second", + "shortdate_millisecond": "short-date precision-time millisecond", + "formatdate_second": "format-date precision-time second", + "formatdate_tenthsecond": "format-date precision-time tenth-second", + "formatdate_millisecond": "format-date precision-time millisecond"} + +CHANNEL_DEFAULT_TRAP_STATE = {"0": "true", + "1": "true", + "2": "true", + "3": "true", + "4": "false", + "5": "true", + "6": "true", + "7": "true", + "8": "true", + "9": "true"} + +CHANNEL_DEFAULT_TRAP_LEVEL = {"0": "debugging", + "1": "debugging", + "2": "debugging", + "3": "debugging", + "4": "debugging", + "5": "debugging", + "6": "debugging", + "7": "debugging", + "8": "debugging", + "9": "debugging"} + + +class InfoCenterTrap(object): + """ Manages info center trap configuration """ + + def __init__(self, **kwargs): + """ Init function """ + + # argument spec + argument_spec = kwargs["argument_spec"] + self.spec = argument_spec + self.module = AnsibleModule(argument_spec=self.spec, supports_check_mode=True) + + # module args + self.state = self.module.params['state'] + self.trap_time_stamp = self.module.params['trap_time_stamp'] or None + self.trap_buff_enable = self.module.params['trap_buff_enable'] + self.trap_buff_size = self.module.params['trap_buff_size'] or None + self.module_name = self.module.params['module_name'] or None + self.channel_id = self.module.params['channel_id'] or None + self.trap_enable = self.module.params['trap_enable'] + self.trap_level = self.module.params['trap_level'] or None + + # cur config + self.cur_global_cfg = dict() + self.cur_source_cfg = dict() + + # state + self.changed = False + self.updates_cmd = list() + self.results = dict() + self.proposed = dict() + self.existing = dict() + self.end_state = dict() + + def netconf_get_config(self, conf_str): + """ Netconf get config """ + + xml_str = get_nc_config(self.module, conf_str) + + return xml_str + + def netconf_set_config(self, conf_str): + """ Netconf set config """ + + xml_str = set_nc_config(self.module, conf_str) + + return xml_str + + def check_global_args(self): + """ Check global args """ + + need_cfg = False + find_flag = False + self.cur_global_cfg["global_cfg"] = [] + + if self.trap_time_stamp or self.trap_buff_enable != 'no_use' or self.trap_buff_size: + if self.trap_buff_size: + if self.trap_buff_size.isdigit(): + if int(self.trap_buff_size) < 0 or int(self.trap_buff_size) > 1024: + self.module.fail_json( + msg='Error: The value of trap_buff_size is out of [0 - 1024].') + else: + self.module.fail_json( + msg='Error: The trap_buff_size is not digit.') + + conf_str = CE_GET_TRAP_GLOBAL_HEADER + + if self.trap_time_stamp: + conf_str += "" + if self.trap_buff_enable != 'no_use': + conf_str += "" + if self.trap_buff_size: + conf_str += "" + + conf_str += CE_GET_TRAP_GLOBAL_TAIL + recv_xml = self.netconf_get_config(conf_str=conf_str) + + if "" in recv_xml: + find_flag = False + else: + xml_str = recv_xml.replace('\r', '').replace('\n', '').\ + replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ + replace('xmlns="http://www.huawei.com/netconf/vrp"', "") + + root = ElementTree.fromstring(xml_str) + global_cfg = root.findall("data/syslog/globalParam") + if global_cfg: + for tmp in global_cfg: + tmp_dict = dict() + for site in tmp: + if site.tag in ["trapTimeStamp", "icTrapBuffEn", "trapBuffSize"]: + tmp_dict[site.tag] = site.text + + self.cur_global_cfg["global_cfg"].append(tmp_dict) + + if self.cur_global_cfg["global_cfg"]: + for tmp in self.cur_global_cfg["global_cfg"]: + find_flag = True + + if self.trap_time_stamp and tmp.get("trapTimeStamp").lower() != self.trap_time_stamp: + find_flag = False + if self.trap_buff_enable != 'no_use' and tmp.get("icTrapBuffEn") != self.trap_buff_enable: + find_flag = False + if self.trap_buff_size and tmp.get("trapBuffSize") != self.trap_buff_size: + find_flag = False + + if find_flag: + break + else: + find_flag = False + + if self.state == "present": + need_cfg = bool(not find_flag) + else: + need_cfg = bool(find_flag) + + self.cur_global_cfg["need_cfg"] = need_cfg + + def check_source_args(self): + """ Check source args """ + + need_cfg = False + find_flag = False + self.cur_source_cfg["source_cfg"] = list() + + if self.module_name: + if len(self.module_name) < 1 or len(self.module_name) > 31: + self.module.fail_json( + msg='Error: The module_name is out of [1 - 31].') + + if not self.channel_id: + self.module.fail_json( + msg='Error: Please input channel_id at the same time.') + + if self.channel_id: + if self.channel_id.isdigit(): + if int(self.channel_id) < 0 or int(self.channel_id) > 9: + self.module.fail_json( + msg='Error: The value of channel_id is out of [0 - 9].') + else: + self.module.fail_json( + msg='Error: The channel_id is not digit.') + + conf_str = CE_GET_TRAP_SOURCE_HEADER + + if self.module_name != "default": + conf_str += "%s" % self.module_name.upper() + else: + conf_str += "default" + + if self.channel_id: + conf_str += "" + if self.trap_enable != 'no_use': + conf_str += "" + if self.trap_level: + conf_str += "" + + conf_str += CE_GET_TRAP_SOURCE_TAIL + recv_xml = self.netconf_get_config(conf_str=conf_str) + + if "" in recv_xml: + find_flag = False + else: + xml_str = recv_xml.replace('\r', '').replace('\n', '').\ + replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ + replace('xmlns="http://www.huawei.com/netconf/vrp"', "") + + root = ElementTree.fromstring(xml_str) + source_cfg = root.findall("data/syslog/icSources/icSource") + if source_cfg: + for tmp in source_cfg: + tmp_dict = dict() + for site in tmp: + if site.tag in ["moduleName", "icChannelId", "trapEnFlg", "trapEnLevel"]: + tmp_dict[site.tag] = site.text + + self.cur_source_cfg["source_cfg"].append(tmp_dict) + + if self.cur_source_cfg["source_cfg"]: + for tmp in self.cur_source_cfg["source_cfg"]: + find_flag = True + + if self.module_name and tmp.get("moduleName").lower() != self.module_name.lower(): + find_flag = False + if self.channel_id and tmp.get("icChannelId") != self.channel_id: + find_flag = False + if self.trap_enable != 'no_use' and tmp.get("trapEnFlg") != self.trap_enable: + find_flag = False + if self.trap_level and tmp.get("trapEnLevel") != self.trap_level: + find_flag = False + + if find_flag: + break + else: + find_flag = False + + if self.state == "present": + need_cfg = bool(not find_flag) + else: + need_cfg = bool(find_flag) + + self.cur_source_cfg["need_cfg"] = need_cfg + + def get_proposed(self): + """ Get proposed """ + + self.proposed["state"] = self.state + + if self.trap_time_stamp: + self.proposed["trap_time_stamp"] = self.trap_time_stamp + if self.trap_buff_enable != 'no_use': + self.proposed["trap_buff_enable"] = self.trap_buff_enable + if self.trap_buff_size: + self.proposed["trap_buff_size"] = self.trap_buff_size + if self.module_name: + self.proposed["module_name"] = self.module_name + if self.channel_id: + self.proposed["channel_id"] = self.channel_id + if self.trap_enable != 'no_use': + self.proposed["trap_enable"] = self.trap_enable + if self.trap_level: + self.proposed["trap_level"] = self.trap_level + + def get_existing(self): + """ Get existing """ + + if self.cur_global_cfg["global_cfg"]: + self.existing["global_cfg"] = self.cur_global_cfg["global_cfg"] + if self.cur_source_cfg["source_cfg"]: + self.existing["source_cfg"] = self.cur_source_cfg["source_cfg"] + + def get_end_state(self): + """ Get end state """ + + self.check_global_args() + if self.cur_global_cfg["global_cfg"]: + self.end_state["global_cfg"] = self.cur_global_cfg["global_cfg"] + + self.check_source_args() + if self.cur_source_cfg["source_cfg"]: + self.end_state["source_cfg"] = self.cur_source_cfg["source_cfg"] + + def merge_trap_global(self): + """ Merge trap global """ + + conf_str = CE_MERGE_TRAP_GLOBAL_HEADER + + if self.trap_time_stamp: + conf_str += "%s" % self.trap_time_stamp.upper() + if self.trap_buff_enable != 'no_use': + conf_str += "%s" % self.trap_buff_enable + if self.trap_buff_size: + conf_str += "%s" % self.trap_buff_size + + conf_str += CE_MERGE_TRAP_GLOBAL_TAIL + + recv_xml = self.netconf_set_config(conf_str=conf_str) + + if "" not in recv_xml: + self.module.fail_json(msg='Error: Merge trap global failed.') + + if self.trap_time_stamp: + cmd = "info-center timestamp trap " + TIME_STAMP_DICT.get(self.trap_time_stamp) + self.updates_cmd.append(cmd) + if self.trap_buff_enable != 'no_use': + if self.trap_buff_enable == "true": + cmd = "info-center trapbuffer" + else: + cmd = "undo info-center trapbuffer" + self.updates_cmd.append(cmd) + if self.trap_buff_size: + cmd = "info-center trapbuffer size %s" % self.trap_buff_size + self.updates_cmd.append(cmd) + + self.changed = True + + def delete_trap_global(self): + """ Delete trap global """ + + conf_str = CE_MERGE_TRAP_GLOBAL_HEADER + + if self.trap_time_stamp: + conf_str += "DATE_SECOND" + if self.trap_buff_enable != 'no_use': + conf_str += "false" + if self.trap_buff_size: + conf_str += "256" + + conf_str += CE_MERGE_TRAP_GLOBAL_TAIL + + recv_xml = self.netconf_set_config(conf_str=conf_str) + + if "" not in recv_xml: + self.module.fail_json(msg='Error: delete trap global failed.') + + if self.trap_time_stamp: + cmd = "undo info-center timestamp trap" + self.updates_cmd.append(cmd) + if self.trap_buff_enable != 'no_use': + cmd = "undo info-center trapbuffer" + self.updates_cmd.append(cmd) + if self.trap_buff_size: + cmd = "undo info-center trapbuffer size" + self.updates_cmd.append(cmd) + + self.changed = True + + def merge_trap_source(self): + """ Merge trap source """ + + conf_str = CE_MERGE_TRAP_SOURCE_HEADER + + if self.module_name: + conf_str += "%s" % self.module_name + if self.channel_id: + conf_str += "%s" % self.channel_id + if self.trap_enable != 'no_use': + conf_str += "%s" % self.trap_enable + if self.trap_level: + conf_str += "%s" % self.trap_level + + conf_str += CE_MERGE_TRAP_SOURCE_TAIL + + recv_xml = self.netconf_set_config(conf_str=conf_str) + + if "" not in recv_xml: + self.module.fail_json(msg='Error: Merge trap source failed.') + + cmd = "info-center source" + if self.module_name: + cmd += " %s" % self.module_name + if self.channel_id: + cmd += " channel %s" % self.channel_id + if self.trap_enable != 'no_use': + if self.trap_enable == "true": + cmd += " trap state on" + else: + cmd += " trap state off" + if self.trap_level: + cmd += " level %s" % self.trap_level + + self.updates_cmd.append(cmd) + self.changed = True + + def delete_trap_source(self): + """ Delete trap source """ + + if self.trap_enable == 'no_use' and not self.trap_level: + conf_str = CE_DELETE_TRAP_SOURCE_HEADER + if self.module_name: + conf_str += "%s" % self.module_name + if self.channel_id: + conf_str += "%s" % self.channel_id + conf_str += CE_DELETE_TRAP_SOURCE_TAIL + else: + conf_str = CE_MERGE_TRAP_SOURCE_HEADER + if self.module_name: + conf_str += "%s" % self.module_name + if self.channel_id: + conf_str += "%s" % self.channel_id + if self.trap_enable != 'no_use': + conf_str += "%s" % CHANNEL_DEFAULT_TRAP_STATE.get(self.channel_id) + if self.trap_level: + conf_str += "%s" % CHANNEL_DEFAULT_TRAP_LEVEL.get(self.channel_id) + conf_str += CE_MERGE_TRAP_SOURCE_TAIL + + recv_xml = self.netconf_set_config(conf_str=conf_str) + + if "" not in recv_xml: + self.module.fail_json(msg='Error: Delete trap source failed.') + + cmd = "undo info-center source" + if self.module_name: + cmd += " %s" % self.module_name + if self.channel_id: + cmd += " channel %s" % self.channel_id + if self.trap_enable != 'no_use': + cmd += " trap state" + if self.trap_level: + cmd += " level" + + self.updates_cmd.append(cmd) + self.changed = True + + def work(self): + """ work function """ + + self.check_global_args() + self.check_source_args() + self.get_proposed() + self.get_existing() + + if self.state == "present": + if self.cur_global_cfg["need_cfg"]: + self.merge_trap_global() + if self.cur_source_cfg["need_cfg"]: + self.merge_trap_source() + + else: + if self.cur_global_cfg["need_cfg"]: + self.delete_trap_global() + if self.cur_source_cfg["need_cfg"]: + self.delete_trap_source() + + self.get_end_state() + + self.results['changed'] = self.changed + self.results['proposed'] = self.proposed + self.results['existing'] = self.existing + self.results['end_state'] = self.end_state + self.results['updates'] = self.updates_cmd + + self.module.exit_json(**self.results) + + +def main(): + """ Module main """ + + argument_spec = dict( + state=dict(choices=['present', 'absent'], default='present'), + trap_time_stamp=dict(choices=['date_boot', 'date_second', 'date_tenthsecond', + 'date_millisecond', 'shortdate_second', 'shortdate_tenthsecond', + 'shortdate_millisecond', 'formatdate_second', 'formatdate_tenthsecond', + 'formatdate_millisecond']), + trap_buff_enable=dict(type='str', default='no_use', choices=['no_use', 'true', 'false']), + trap_buff_size=dict(type='str'), + module_name=dict(type='str'), + channel_id=dict(type='str'), + trap_enable=dict(type='str', default='no_use', choices=['no_use', 'true', 'false']), + trap_level=dict(choices=['emergencies', 'alert', 'critical', 'error', 'warning', 'notification', + 'informational', 'debugging']) + ) + + argument_spec.update(ce_argument_spec) + module = InfoCenterTrap(argument_spec=argument_spec) + module.work() + + +if __name__ == '__main__': + main()