diff --git a/lib/ansible/modules/network/cloudengine/ce_info_center_log.py b/lib/ansible/modules/network/cloudengine/ce_info_center_log.py
new file mode 100644
index 0000000000..3c2de25bd5
--- /dev/null
+++ b/lib/ansible/modules/network/cloudengine/ce_info_center_log.py
@@ -0,0 +1,555 @@
+#!/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_log
+version_added: "2.4"
+short_description: Manages information center log configuration on HUAWEI CloudEngine switches.
+description:
+ - Setting the Timestamp Format of Logs.
+ Configuring the Device to Output Logs to the Log Buffer.
+author: QijunPan (@CloudEngine-Ansible)
+options:
+ log_time_stamp:
+ description:
+ - Sets the timestamp format of logs.
+ 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']
+ log_buff_enable:
+ description:
+ - Enables the Switch to send logs to the log buffer.
+ required: false
+ default: no_use
+ choices: ['no_use','true', 'false']
+ log_buff_size:
+ description:
+ - Specifies the maximum number of logs in the log buffer.
+ The value is an integer that ranges from 0 to 10240. If logbuffer-size is 0, logs are not displayed.
+ required: false
+ default: null
+ module_name:
+ description:
+ - Specifies the name of a module.
+ The value is a module name in registration logs.
+ required: false
+ default: null
+ channel_id:
+ description:
+ - Specifies a channel ID.
+ The value is an integer ranging from 0 to 9.
+ required: false
+ default: null
+ log_enable:
+ description:
+ - Indicates whether log filtering is enabled.
+ required: false
+ default: no_use
+ choices: ['no_use','true', 'false']
+ log_level:
+ description:
+ - Specifies a log severity.
+ required: false
+ default: null
+ choices: ['emergencies', 'alert', 'critical', 'error',
+ 'warning', 'notification', 'informational', 'debugging']
+ state:
+ description:
+ - Determines whether the config should be present or not
+ on the device.
+ required: false
+ default: present
+ choices: ['present', 'absent']
+"""
+
+EXAMPLES = '''
+
+- name: CloudEngine info center log 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: "Setting the timestamp format of logs"
+ ce_info_center_log:
+ log_time_stamp: date_tenthsecond
+ provider: "{{ cli }}"
+
+ - name: "Enabled to output information to the log buffer"
+ ce_info_center_log:
+ log_buff_enable: true
+ provider: "{{ cli }}"
+
+ - name: "Set the maximum number of logs in the log buffer"
+ ce_info_center_log:
+ log_buff_size: 100
+ provider: "{{ cli }}"
+
+ - name: "Set a rule for outputting logs to a channel"
+ ce_info_center_log:
+ module_name: aaa
+ channel_id: 1
+ log_enable: true
+ log_level: critical
+ provider: "{{ cli }}"
+'''
+
+RETURN = '''
+proposed:
+ description: k/v pairs of parameters passed into module
+ returned: verbose mode
+ type: dict
+ sample: {"log_time_stamp": "date_tenthsecond", "state": "present"}
+existing:
+ description: k/v pairs of existing configuration
+ returned: verbose mode
+ type: dict
+ sample: {"log_time_stamp": "date_second"}
+end_state:
+ description: k/v pairs of configuration after module execution
+ returned: verbose mode
+ type: dict
+ sample: {"log_time_stamp": "date_tenthsecond"}
+updates:
+ description: commands sent to the device
+ returned: always
+ type: list
+ sample: ["info-center timestamp log date precision-time tenth-second"]
+changed:
+ description: check to see if a change was made on the device
+ returned: always
+ type: boolean
+ sample: true
+'''
+
+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
+
+
+CE_NC_GET_LOG = """
+
+
+
+
+
+
+
+
+
+ %s
+ %s
+
+
+
+
+
+
+
+"""
+
+CE_NC_GET_LOG_GLOBAL = """
+
+
+
+
+
+
+
+
+
+"""
+
+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_LOG_STATE = {"0": "true",
+ "1": "true",
+ "2": "true",
+ "3": "false",
+ "4": "true",
+ "5": "false",
+ "6": "true",
+ "7": "true",
+ "8": "true",
+ "9": "true"}
+
+CHANNEL_DEFAULT_LOG_LEVEL = {"0": "warning",
+ "1": "warning",
+ "2": "informational",
+ "3": "informational",
+ "4": "warning",
+ "5": "debugging",
+ "6": "debugging",
+ "7": "warning",
+ "8": "debugging",
+ "9": "debugging"}
+
+
+class InfoCenterLog(object):
+ """
+ Manages information center log configuration
+ """
+
+ def __init__(self, argument_spec):
+ self.spec = argument_spec
+ self.module = None
+ self.init_module()
+
+ # module input info
+ self.log_time_stamp = self.module.params['log_time_stamp']
+ self.log_buff_enable = self.module.params['log_buff_enable']
+ self.log_buff_size = self.module.params['log_buff_size']
+ self.module_name = self.module.params['module_name']
+ self.channel_id = self.module.params['channel_id']
+ self.log_enable = self.module.params['log_enable']
+ self.log_level = self.module.params['log_level']
+ self.state = self.module.params['state']
+
+ # state
+ self.log_dict = dict()
+ self.changed = False
+ self.updates_cmd = list()
+ self.commands = list()
+ self.results = dict()
+ self.proposed = dict()
+ self.existing = dict()
+ self.end_state = dict()
+
+ def init_module(self):
+ """init module"""
+
+ self.module = AnsibleModule(argument_spec=self.spec, supports_check_mode=True)
+
+ def check_response(self, xml_str, xml_name):
+ """Check if response message is already succeed"""
+
+ if "" not in xml_str:
+ self.module.fail_json(msg='Error: %s failed.' % xml_name)
+
+ def get_log_dict(self):
+ """ log config dict"""
+
+ log_dict = dict()
+ if self.module_name:
+ if self.module_name.lower() == "default":
+ conf_str = CE_NC_GET_LOG % (self.module_name.lower(), self.channel_id)
+ else:
+ conf_str = CE_NC_GET_LOG % (self.module_name.upper(), self.channel_id)
+ else:
+ conf_str = CE_NC_GET_LOG_GLOBAL
+
+ xml_str = get_nc_config(self.module, conf_str)
+ if "" in xml_str:
+ return log_dict
+
+ xml_str = xml_str.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)
+
+ # get global param info
+ glb = root.find("data/syslog/globalParam")
+ if glb:
+ for attr in glb:
+ if attr.tag in ["bufferSize", "logTimeStamp", "icLogBuffEn"]:
+ log_dict[attr.tag] = attr.text
+
+ # get info-center source info
+ log_dict["source"] = dict()
+ src = root.find("data/syslog/icSources/icSource")
+ if src:
+ for attr in src:
+ if attr.tag in ["moduleName", "icChannelId", "icChannelName", "logEnFlg", "logEnLevel"]:
+ log_dict["source"][attr.tag] = attr.text
+
+ return log_dict
+
+ def config_log_global(self):
+ """config log global param"""
+
+ xml_str = ''
+ if self.log_time_stamp:
+ if self.state == "present" and self.log_time_stamp.upper() != self.log_dict.get("logTimeStamp"):
+ xml_str += '%s' % self.log_time_stamp.upper()
+ self.updates_cmd.append(
+ "info-center timestamp log %s" % TIME_STAMP_DICT.get(self.log_time_stamp))
+ elif self.state == "absent" and self.log_time_stamp.upper() == self.log_dict.get("logTimeStamp"):
+ xml_str += 'DATE_SECOND' # set default
+ self.updates_cmd.append("undo info-center timestamp log")
+ else:
+ pass
+
+ if self.log_buff_enable != 'no_use':
+ if self.log_dict.get("icLogBuffEn") != self.log_buff_enable:
+ xml_str += '%s' % self.log_buff_enable
+ if self.log_buff_enable == "true":
+ self.updates_cmd.append("info-center logbuffer")
+ else:
+ self.updates_cmd.append("undo info-center logbuffer")
+
+ if self.log_buff_size:
+ if self.state == "present" and self.log_dict.get("bufferSize") != self.log_buff_size:
+ xml_str += '%s' % self.log_buff_size
+ self.updates_cmd.append(
+ "info-center logbuffer size %s" % self.log_buff_size)
+ elif self.state == "absent" and self.log_dict.get("bufferSize") == self.log_buff_size:
+ xml_str += '512'
+ self.updates_cmd.append("undo info-center logbuffer size")
+
+ if xml_str == '':
+ return ""
+ else:
+ xml_str += ''
+ return xml_str
+
+ def config_log_soruce(self):
+ """config info-center sources"""
+
+ xml_str = ''
+ if not self.module_name or not self.channel_id:
+ return xml_str
+
+ source = self.log_dict["source"]
+ if self.state == "present":
+ xml_str = ''
+ cmd = 'info-center source %s channel %s log' % (
+ self.module_name, self.channel_id)
+ else:
+ if not source or self.module_name != source.get("moduleName").lower() or \
+ self.channel_id != source.get("icChannelId"):
+ return ''
+
+ if self.log_enable == 'no_use' and not self.log_level:
+ xml_str = ''
+ else:
+ xml_str = ''
+ cmd = 'undo info-center source %s channel %s log' % (
+ self.module_name, self.channel_id)
+
+ xml_str += '%s%s' % (
+ self.module_name, self.channel_id)
+
+ # log_enable
+ if self.log_enable != 'no_use':
+ if self.state == "present" and (not source or self.log_enable != source.get("logEnFlg")):
+ xml_str += '%s' % self.log_enable
+ if self.log_enable == "true":
+ cmd += ' state on'
+ else:
+ cmd += ' state off'
+ elif self.state == "absent" and source and self.log_level == source.get("logEnLevel"):
+ xml_str += '%s' % CHANNEL_DEFAULT_LOG_STATE.get(self.channel_id)
+ cmd += ' state'
+
+ # log_level
+ if self.log_level:
+ if self.state == "present" and (not source or self.log_level != source.get("logEnLevel")):
+ xml_str += '%s' % self.log_level
+ cmd += ' level %s' % self.log_level
+ elif self.state == "absent" and source and self.log_level == source.get("logEnLevel"):
+ xml_str += '%s' % CHANNEL_DEFAULT_LOG_LEVEL.get(self.channel_id)
+ cmd += ' level'
+
+ if xml_str.endswith(""):
+ if self.log_enable == 'no_use' and not self.log_level and self.state == "absent":
+ xml_str += ''
+ self.updates_cmd.append(cmd)
+ return xml_str
+ else:
+ return ''
+ else:
+ xml_str += ''
+ self.updates_cmd.append(cmd)
+ return xml_str
+
+ def netconf_load_config(self, xml_str):
+ """load log config by netconf"""
+
+ if not xml_str:
+ return
+
+ xml_cfg = """
+
+
+ %s
+
+ """ % xml_str
+
+ recv_xml = set_nc_config(self.module, xml_cfg)
+ self.check_response(recv_xml, "SET_LOG")
+ self.changed = True
+
+ def check_params(self):
+ """Check all input params"""
+
+ # check log_buff_size ranges from 0 to 10240
+ if self.log_buff_size:
+ if not self.log_buff_size.isdigit():
+ self.module.fail_json(
+ msg="Error: log_buff_size is not digit.")
+ if int(self.log_buff_size) < 0 or int(self.log_buff_size) > 10240:
+ self.module.fail_json(
+ msg="Error: log_buff_size is not ranges from 0 to 10240.")
+
+ # check channel_id ranging from 0 to 9
+ if self.channel_id:
+ if not self.channel_id.isdigit():
+ self.module.fail_json(msg="Error: channel_id is not digit.")
+ if int(self.channel_id) < 0 or int(self.channel_id) > 9:
+ self.module.fail_json(
+ msg="Error: channel_id is not ranges from 0 to 9.")
+
+ # module_name and channel_id must be set at the same time
+ if bool(self.module_name) != bool(self.channel_id):
+ self.module.fail_json(
+ msg="Error: module_name and channel_id must be set at the same time.")
+
+ def get_proposed(self):
+ """get proposed info"""
+
+ if self.log_time_stamp:
+ self.proposed["log_time_stamp"] = self.log_time_stamp
+ if self.log_buff_enable != 'no_use':
+ self.proposed["log_buff_enable"] = self.log_buff_enable
+ if self.log_buff_size:
+ self.proposed["log_buff_size"] = self.log_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.log_enable != 'no_use':
+ self.proposed["log_enable"] = self.log_enable
+ if self.log_level:
+ self.proposed["log_level"] = self.log_level
+ self.proposed["state"] = self.state
+
+ def get_existing(self):
+ """get existing info"""
+
+ if not self.log_dict:
+ return
+
+ if self.log_time_stamp:
+ self.existing["log_time_stamp"] = self.log_dict.get("logTimeStamp").lower()
+ if self.log_buff_enable != 'no_use':
+ self.existing["log_buff_enable"] = self.log_dict.get("icLogBuffEn")
+ if self.log_buff_size:
+ self.existing["log_buff_size"] = self.log_dict.get("bufferSize")
+ if self.module_name:
+ self.existing["source"] = self.log_dict.get("source")
+
+ def get_end_state(self):
+ """get end state info"""
+
+ log_dict = self.get_log_dict()
+ if not log_dict:
+ return
+
+ if self.log_time_stamp:
+ self.end_state["log_time_stamp"] = log_dict.get("logTimeStamp").lower()
+ if self.log_buff_enable != 'no_use':
+ self.end_state["log_buff_enable"] = log_dict.get("icLogBuffEn")
+ if self.log_buff_size:
+ self.end_state["log_buff_size"] = log_dict.get("bufferSize")
+ if self.module_name:
+ self.end_state["source"] = log_dict.get("source")
+
+ def work(self):
+ """worker"""
+
+ self.check_params()
+ self.log_dict = self.get_log_dict()
+ self.get_existing()
+ self.get_proposed()
+
+ # deal present or absent
+ xml_str = ''
+ if self.log_time_stamp or self.log_buff_enable != 'no_use' or self.log_buff_size:
+ xml_str += self.config_log_global()
+
+ if self.module_name:
+ xml_str += self.config_log_soruce()
+
+ if xml_str:
+ self.netconf_load_config(xml_str)
+ self.changed = True
+
+ 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
+ if self.changed:
+ self.results['updates'] = self.updates_cmd
+ else:
+ self.results['updates'] = list()
+
+ self.module.exit_json(**self.results)
+
+
+def main():
+ """Module main"""
+
+ argument_spec = dict(
+ log_time_stamp=dict(required=False, type='str',
+ choices=['date_boot', 'date_second', 'date_tenthsecond', 'date_millisecond',
+ 'shortdate_second', 'shortdate_tenthsecond', 'shortdate_millisecond',
+ 'formatdate_second', 'formatdate_tenthsecond', 'formatdate_millisecond']),
+ log_buff_enable=dict(type='str', default='no_use', choices=['no_use', 'true', 'false']),
+ log_buff_size=dict(required=False, type='str'),
+ module_name=dict(required=False, type='str'),
+ channel_id=dict(required=False, type='str'),
+ log_enable=dict(type='str', default='no_use', choices=['no_use', 'true', 'false']),
+ log_level=dict(required=False, type='str',
+ choices=['emergencies', 'alert', 'critical', 'error',
+ 'warning', 'notification', 'informational', 'debugging']),
+ state=dict(required=False, default='present',
+ choices=['present', 'absent'])
+ )
+
+ argument_spec.update(ce_argument_spec)
+ module = InfoCenterLog(argument_spec)
+ module.work()
+
+
+if __name__ == '__main__':
+ main()