����JFIF��������� Mr.X
  
  __  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

deexcl@216.73.217.71: ~ $
#
# 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 <http://www.gnu.org/licenses/>.
#

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

DOCUMENTATION = '''
---
module: ce_stp
short_description: Manages STP configuration on HUAWEI CloudEngine switches.
description:
    - Manages STP configurations on HUAWEI CloudEngine switches.
author:
    - wangdezhuang (@QijunPan)
notes:
    - Recommended connection is C(network_cli).
    - This module also works with C(local) connections for legacy playbooks.
options:
    state:
        description:
            - Specify desired state of the resource.
        default: present
        choices: ['present', 'absent']
    stp_mode:
        description:
            - Set an operation mode for the current MSTP process.
              The mode can be STP, RSTP, or MSTP.
        choices: ['stp', 'rstp', 'mstp']
    stp_enable:
        description:
            - Enable or disable STP on a switch.
        choices: ['enable', 'disable']
    stp_converge:
        description:
            - STP convergence mode.
              Fast means set STP aging mode to Fast.
              Normal means set STP aging mode to Normal.
        choices: ['fast', 'normal']
    bpdu_protection:
        description:
            - Configure BPDU protection on an edge port.
              This function prevents network flapping caused by attack packets.
        choices: ['enable', 'disable']
    tc_protection:
        description:
            - Configure the TC BPDU protection function for an MSTP process.
        choices: ['enable', 'disable']
    tc_protection_interval:
        description:
            - Set the time the MSTP device takes to handle the maximum number of TC BPDUs
              and immediately refresh forwarding entries.
              The value is an integer ranging from 1 to 600, in seconds.
    tc_protection_threshold:
        description:
            - Set the maximum number of TC BPDUs that the MSTP can handle.
              The value is an integer ranging from 1 to 255. The default value is 1 on the switch.
    interface:
        description:
            - Interface name.
              If the value is C(all), will apply configuration to all interfaces.
              if the value is a special name, only support input the full name.
    edged_port:
        description:
            - Set the current port as an edge port.
        choices: ['enable', 'disable']
    bpdu_filter:
        description:
            - Specify a port as a BPDU filter port.
        choices: ['enable', 'disable']
    cost:
        description:
            - Set the path cost of the current port.
              The default instance is 0.
    root_protection:
        description:
            - Enable root protection on the current port.
        choices: ['enable', 'disable']
    loop_protection:
        description:
            - Enable loop protection on the current port.
        choices: ['enable', 'disable']
'''

EXAMPLES = '''

- name: CloudEngine stp test
  hosts: cloudengine
  connection: local
  gather_facts: no

  tasks:

  - name: "Config stp mode"
    community.network.ce_stp:
      state: present
      stp_mode: stp

  - name: "Undo stp mode"
    community.network.ce_stp:
      state: absent
      stp_mode: stp

  - name: "Enable bpdu protection"
    community.network.ce_stp:
      state: present
      bpdu_protection: enable

  - name: "Disable bpdu protection"
    community.network.ce_stp:
      state: present
      bpdu_protection: disable
'''

RETURN = '''
changed:
    description: check to see if a change was made on the device
    returned: always
    type: bool
    sample: true
proposed:
    description: k/v pairs of parameters passed into module
    returned: always
    type: dict
    sample: {"bpdu_protection": "enable",
             "state": "present"}
existing:
    description: k/v pairs of existing aaa server
    returned: always
    type: dict
    sample: {"bpdu_protection": "disable"}
end_state:
    description: k/v pairs of aaa params after module execution
    returned: always
    type: dict
    sample: {"bpdu_protection": "enable"}
updates:
    description: command sent to the device
    returned: always
    type: list
    sample: ["stp bpdu-protection"]
'''

import re
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.network.plugins.module_utils.network.cloudengine.ce import exec_command, load_config, ce_argument_spec


def get_config(module, flags):

    """Retrieves the current config from the device or cache"""

    flags = [] if flags is None else flags

    cmd = 'display current-configuration '
    cmd += ' '.join(flags)
    cmd = cmd.strip()

    rc, out, err = exec_command(module, cmd)
    if rc != 0:
        module.fail_json(msg=err)
    config = str(out).strip()
    if config.startswith("display"):
        configs = config.split("\n")
        if len(configs) > 1:
            return "\n".join(configs[1:])
        else:
            return ""
    else:
        return config


class Stp(object):
    """ Manages stp/rstp/mstp configuration """

    def __init__(self, **kwargs):
        """ Stp module init """

        # module
        argument_spec = kwargs["argument_spec"]
        self.spec = argument_spec
        self.module = AnsibleModule(argument_spec=self.spec, supports_check_mode=True)

        # config
        self.cur_cfg = dict()
        self.stp_cfg = None
        self.interface_stp_cfg = None

        # module args
        self.state = self.module.params['state'] or None
        self.stp_mode = self.module.params['stp_mode'] or None
        self.stp_enable = self.module.params['stp_enable'] or None
        self.stp_converge = self.module.params['stp_converge'] or None
        self.interface = self.module.params['interface'] or None
        self.edged_port = self.module.params['edged_port'] or None
        self.bpdu_filter = self.module.params['bpdu_filter'] or None
        self.cost = self.module.params['cost'] or None
        self.bpdu_protection = self.module.params['bpdu_protection'] or None
        self.tc_protection = self.module.params['tc_protection'] or None
        self.tc_protection_interval = self.module.params['tc_protection_interval'] or None
        self.tc_protection_threshold = self.module.params['tc_protection_threshold'] or None
        self.root_protection = self.module.params['root_protection'] or None
        self.loop_protection = self.module.params['loop_protection'] or None

        # state
        self.changed = False
        self.updates_cmd = list()
        self.results = dict()
        self.proposed = dict()
        self.existing = dict()
        self.end_state = dict()

    def cli_load_config(self, commands):
        """ Cli load configuration """

        if not self.module.check_mode:
            load_config(self.module, commands)

    def cli_get_stp_config(self):
        """ Cli get stp configuration """

        flags = [r"| section include #\s*\n\s*stp", r"| section exclude #\s*\n+\s*stp process \d+"]
        self.stp_cfg = get_config(self.module, flags)

    def cli_get_interface_stp_config(self):
        """ Cli get interface's stp configuration """

        if self.interface:
            regular = r"| ignore-case section include ^#\s+interface %s\s+" % self.interface.replace(" ", "")
            flags = list()
            flags.append(regular)
            tmp_cfg = get_config(self.module, flags)

            if not tmp_cfg:
                self.module.fail_json(
                    msg='Error: The interface %s is not exist.' % self.interface)

            if "undo portswitch" in tmp_cfg:
                self.module.fail_json(
                    msg='Error: The interface %s is not switch mode.' % self.interface)

            self.interface_stp_cfg = tmp_cfg

    def check_params(self):
        """ Check module params """

        if self.cost:
            if self.cost.isdigit():
                if int(self.cost) < 1 or int(self.cost) > 200000000:
                    self.module.fail_json(
                        msg='Error: The value of cost is out of [1 - 200000000].')
            else:
                self.module.fail_json(
                    msg='Error: The cost is not digit.')

        if self.tc_protection_interval:
            if self.tc_protection_interval.isdigit():
                if int(self.tc_protection_interval) < 1 or int(self.tc_protection_interval) > 600:
                    self.module.fail_json(
                        msg='Error: The value of tc_protection_interval is out of [1 - 600].')
            else:
                self.module.fail_json(
                    msg='Error: The tc_protection_interval is not digit.')

        if self.tc_protection_threshold:
            if self.tc_protection_threshold.isdigit():
                if int(self.tc_protection_threshold) < 1 or int(self.tc_protection_threshold) > 255:
                    self.module.fail_json(
                        msg='Error: The value of tc_protection_threshold is out of [1 - 255].')
            else:
                self.module.fail_json(
                    msg='Error: The tc_protection_threshold is not digit.')

        if self.root_protection or self.loop_protection or self.cost:
            if not self.interface:
                self.module.fail_json(
                    msg='Error: Please input interface.')
            elif self.interface == "all":
                self.module.fail_json(
                    msg='Error: Interface can not be all when config root_protection or loop_protection or cost.')

        if self.root_protection and self.root_protection == "enable":
            if self.loop_protection and self.loop_protection == "enable":
                self.module.fail_json(
                    msg='Error: Can not enable root_protection and loop_protection at the same interface.')

        if self.edged_port or self.bpdu_filter:
            if not self.interface:
                self.module.fail_json(
                    msg='Error: Please input interface.')

    def get_proposed(self):
        """ Get module proposed """

        self.proposed["state"] = self.state

        if self.stp_mode:
            self.proposed["stp_mode"] = self.stp_mode
        if self.stp_enable:
            self.proposed["stp_enable"] = self.stp_enable
        if self.stp_converge:
            self.proposed["stp_converge"] = self.stp_converge
        if self.interface:
            self.proposed["interface"] = self.interface
        if self.edged_port:
            self.proposed["edged_port"] = self.edged_port
        if self.bpdu_filter:
            self.proposed["bpdu_filter"] = self.bpdu_filter
        if self.cost:
            self.proposed["cost"] = self.cost
        if self.bpdu_protection:
            self.proposed["bpdu_protection"] = self.bpdu_protection
        if self.tc_protection:
            self.proposed["tc_protection"] = self.tc_protection
        if self.tc_protection_interval:
            self.proposed["tc_protection_interval"] = self.tc_protection_interval
        if self.tc_protection_threshold:
            self.proposed["tc_protection_threshold"] = self.tc_protection_threshold
        if self.root_protection:
            self.proposed["root_protection"] = self.root_protection
        if self.loop_protection:
            self.proposed["loop_protection"] = self.loop_protection

    def get_existing(self):
        """ Get existing configuration """

        self.cli_get_stp_config()
        if self.interface and self.interface != "all":
            self.cli_get_interface_stp_config()

        if self.stp_mode:
            if "stp mode stp" in self.stp_cfg:
                self.cur_cfg["stp_mode"] = "stp"
                self.existing["stp_mode"] = "stp"
            elif "stp mode rstp" in self.stp_cfg:
                self.cur_cfg["stp_mode"] = "rstp"
                self.existing["stp_mode"] = "rstp"
            else:
                self.cur_cfg["stp_mode"] = "mstp"
                self.existing["stp_mode"] = "mstp"

        if self.stp_enable:
            if "stp disable" in self.stp_cfg:
                self.cur_cfg["stp_enable"] = "disable"
                self.existing["stp_enable"] = "disable"
            else:
                self.cur_cfg["stp_enable"] = "enable"
                self.existing["stp_enable"] = "enable"

        if self.stp_converge:
            if "stp converge fast" in self.stp_cfg:
                self.cur_cfg["stp_converge"] = "fast"
                self.existing["stp_converge"] = "fast"
            else:
                self.cur_cfg["stp_converge"] = "normal"
                self.existing["stp_converge"] = "normal"

        if self.edged_port:
            if self.interface == "all":
                if "stp edged-port default" in self.stp_cfg:
                    self.cur_cfg["edged_port"] = "enable"
                    self.existing["edged_port"] = "enable"
                else:
                    self.cur_cfg["edged_port"] = "disable"
                    self.existing["edged_port"] = "disable"
            else:
                if "stp edged-port enable" in self.interface_stp_cfg:
                    self.cur_cfg["edged_port"] = "enable"
                    self.existing["edged_port"] = "enable"
                else:
                    self.cur_cfg["edged_port"] = "disable"
                    self.existing["edged_port"] = "disable"

        if self.bpdu_filter:
            if self.interface == "all":
                if "stp bpdu-filter default" in self.stp_cfg:
                    self.cur_cfg["bpdu_filter"] = "enable"
                    self.existing["bpdu_filter"] = "enable"
                else:
                    self.cur_cfg["bpdu_filter"] = "disable"
                    self.existing["bpdu_filter"] = "disable"
            else:
                if "stp bpdu-filter enable" in self.interface_stp_cfg:
                    self.cur_cfg["bpdu_filter"] = "enable"
                    self.existing["bpdu_filter"] = "enable"
                else:
                    self.cur_cfg["bpdu_filter"] = "disable"
                    self.existing["bpdu_filter"] = "disable"

        if self.bpdu_protection:
            if "stp bpdu-protection" in self.stp_cfg:
                self.cur_cfg["bpdu_protection"] = "enable"
                self.existing["bpdu_protection"] = "enable"
            else:
                self.cur_cfg["bpdu_protection"] = "disable"
                self.existing["bpdu_protection"] = "disable"

        if self.tc_protection:
            pre_cfg = self.stp_cfg.split("\n")
            if "stp tc-protection" in pre_cfg:
                self.cur_cfg["tc_protection"] = "enable"
                self.existing["tc_protection"] = "enable"
            else:
                self.cur_cfg["tc_protection"] = "disable"
                self.existing["tc_protection"] = "disable"

        if self.tc_protection_interval:
            if "stp tc-protection interval" in self.stp_cfg:
                tmp_value = re.findall(r'stp tc-protection interval (.*)', self.stp_cfg)
                if not tmp_value:
                    self.module.fail_json(
                        msg='Error: Can not find tc-protection interval on the device.')
                self.cur_cfg["tc_protection_interval"] = tmp_value[0]
                self.existing["tc_protection_interval"] = tmp_value[0]
            else:
                self.cur_cfg["tc_protection_interval"] = "null"
                self.existing["tc_protection_interval"] = "null"

        if self.tc_protection_threshold:
            if "stp tc-protection threshold" in self.stp_cfg:
                tmp_value = re.findall(r'stp tc-protection threshold (.*)', self.stp_cfg)
                if not tmp_value:
                    self.module.fail_json(
                        msg='Error: Can not find tc-protection threshold on the device.')
                self.cur_cfg["tc_protection_threshold"] = tmp_value[0]
                self.existing["tc_protection_threshold"] = tmp_value[0]
            else:
                self.cur_cfg["tc_protection_threshold"] = "1"
                self.existing["tc_protection_threshold"] = "1"

        if self.cost:
            tmp_value = re.findall(r'stp instance (.*) cost (.*)', self.interface_stp_cfg)
            if not tmp_value:
                self.cur_cfg["cost"] = "null"
                self.existing["cost"] = "null"
            else:
                self.cur_cfg["cost"] = tmp_value[0][1]
                self.existing["cost"] = tmp_value[0][1]

        # root_protection and loop_protection should get configuration at the same time
        if self.root_protection or self.loop_protection:
            if "stp root-protection" in self.interface_stp_cfg:
                self.cur_cfg["root_protection"] = "enable"
                self.existing["root_protection"] = "enable"
            else:
                self.cur_cfg["root_protection"] = "disable"
                self.existing["root_protection"] = "disable"

            if "stp loop-protection" in self.interface_stp_cfg:
                self.cur_cfg["loop_protection"] = "enable"
                self.existing["loop_protection"] = "enable"
            else:
                self.cur_cfg["loop_protection"] = "disable"
                self.existing["loop_protection"] = "disable"

    def get_end_state(self):
        """ Get end state """

        self.cli_get_stp_config()
        if self.interface and self.interface != "all":
            self.cli_get_interface_stp_config()

        if self.stp_mode:
            if "stp mode stp" in self.stp_cfg:
                self.end_state["stp_mode"] = "stp"
            elif "stp mode rstp" in self.stp_cfg:
                self.end_state["stp_mode"] = "rstp"
            else:
                self.end_state["stp_mode"] = "mstp"

        if self.stp_enable:
            if "stp disable" in self.stp_cfg:
                self.end_state["stp_enable"] = "disable"
            else:
                self.end_state["stp_enable"] = "enable"

        if self.stp_converge:
            if "stp converge fast" in self.stp_cfg:
                self.end_state["stp_converge"] = "fast"
            else:
                self.end_state["stp_converge"] = "normal"

        if self.edged_port:
            if self.interface == "all":
                if "stp edged-port default" in self.stp_cfg:
                    self.end_state["edged_port"] = "enable"
                else:
                    self.end_state["edged_port"] = "disable"
            else:
                if "stp edged-port enable" in self.interface_stp_cfg:
                    self.end_state["edged_port"] = "enable"
                else:
                    self.end_state["edged_port"] = "disable"

        if self.bpdu_filter:
            if self.interface == "all":
                if "stp bpdu-filter default" in self.stp_cfg:
                    self.end_state["bpdu_filter"] = "enable"
                else:
                    self.end_state["bpdu_filter"] = "disable"
            else:
                if "stp bpdu-filter enable" in self.interface_stp_cfg:
                    self.end_state["bpdu_filter"] = "enable"
                else:
                    self.end_state["bpdu_filter"] = "disable"

        if self.bpdu_protection:
            if "stp bpdu-protection" in self.stp_cfg:
                self.end_state["bpdu_protection"] = "enable"
            else:
                self.end_state["bpdu_protection"] = "disable"

        if self.tc_protection:
            pre_cfg = self.stp_cfg.split("\n")
            if "stp tc-protection" in pre_cfg:
                self.end_state["tc_protection"] = "enable"
            else:
                self.end_state["tc_protection"] = "disable"

        if self.tc_protection_interval:
            if "stp tc-protection interval" in self.stp_cfg:
                tmp_value = re.findall(r'stp tc-protection interval (.*)', self.stp_cfg)
                if not tmp_value:
                    self.module.fail_json(
                        msg='Error: Can not find tc-protection interval on the device.')
                self.end_state["tc_protection_interval"] = tmp_value[0]
            else:
                self.end_state["tc_protection_interval"] = "null"

        if self.tc_protection_threshold:
            if "stp tc-protection threshold" in self.stp_cfg:
                tmp_value = re.findall(r'stp tc-protection threshold (.*)', self.stp_cfg)
                if not tmp_value:
                    self.module.fail_json(
                        msg='Error: Can not find tc-protection threshold on the device.')
                self.end_state["tc_protection_threshold"] = tmp_value[0]
            else:
                self.end_state["tc_protection_threshold"] = "1"

        if self.cost:
            tmp_value = re.findall(r'stp instance (.*) cost (.*)', self.interface_stp_cfg)
            if not tmp_value:
                self.end_state["cost"] = "null"
            else:
                self.end_state["cost"] = tmp_value[0][1]

        if self.root_protection or self.loop_protection:
            if "stp root-protection" in self.interface_stp_cfg:
                self.end_state["root_protection"] = "enable"
            else:
                self.end_state["root_protection"] = "disable"

            if "stp loop-protection" in self.interface_stp_cfg:
                self.end_state["loop_protection"] = "enable"
            else:
                self.end_state["loop_protection"] = "disable"

        if self.existing == self.end_state:
            self.changed = False
            self.updates_cmd = list()

    def present_stp(self):
        """ Present stp configuration """

        cmds = list()

        # config stp global
        if self.stp_mode:
            if self.stp_mode != self.cur_cfg["stp_mode"]:
                cmd = "stp mode %s" % self.stp_mode
                cmds.append(cmd)
                self.updates_cmd.append(cmd)

        if self.stp_enable:
            if self.stp_enable != self.cur_cfg["stp_enable"]:
                cmd = "stp %s" % self.stp_enable
                cmds.append(cmd)
                self.updates_cmd.append(cmd)

        if self.stp_converge:
            if self.stp_converge != self.cur_cfg["stp_converge"]:
                cmd = "stp converge %s" % self.stp_converge
                cmds.append(cmd)
                self.updates_cmd.append(cmd)

        if self.edged_port:
            if self.interface == "all":
                if self.edged_port != self.cur_cfg["edged_port"]:
                    if self.edged_port == "enable":
                        cmd = "stp edged-port default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                    else:
                        cmd = "undo stp edged-port default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)

        if self.bpdu_filter:
            if self.interface == "all":
                if self.bpdu_filter != self.cur_cfg["bpdu_filter"]:
                    if self.bpdu_filter == "enable":
                        cmd = "stp bpdu-filter default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                    else:
                        cmd = "undo stp bpdu-filter default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)

        if self.bpdu_protection:
            if self.bpdu_protection != self.cur_cfg["bpdu_protection"]:
                if self.bpdu_protection == "enable":
                    cmd = "stp bpdu-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                else:
                    cmd = "undo stp bpdu-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)

        if self.tc_protection:
            if self.tc_protection != self.cur_cfg["tc_protection"]:
                if self.tc_protection == "enable":
                    cmd = "stp tc-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                else:
                    cmd = "undo stp tc-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)

        if self.tc_protection_interval:
            if self.tc_protection_interval != self.cur_cfg["tc_protection_interval"]:
                cmd = "stp tc-protection interval %s" % self.tc_protection_interval
                cmds.append(cmd)
                self.updates_cmd.append(cmd)

        if self.tc_protection_threshold:
            if self.tc_protection_threshold != self.cur_cfg["tc_protection_threshold"]:
                cmd = "stp tc-protection threshold %s" % self.tc_protection_threshold
                cmds.append(cmd)
                self.updates_cmd.append(cmd)

        # config interface stp
        if self.interface and self.interface != "all":
            tmp_changed = False

            cmd = "interface %s" % self.interface
            cmds.append(cmd)
            self.updates_cmd.append(cmd)

            if self.edged_port:
                if self.edged_port != self.cur_cfg["edged_port"]:
                    if self.edged_port == "enable":
                        cmd = "stp edged-port enable"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp edged-port"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.bpdu_filter:
                if self.bpdu_filter != self.cur_cfg["bpdu_filter"]:
                    if self.bpdu_filter == "enable":
                        cmd = "stp bpdu-filter enable"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp bpdu-filter"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.root_protection:
                if self.root_protection == "enable" and self.cur_cfg["loop_protection"] == "enable":
                    self.module.fail_json(
                        msg='Error: The interface has enable loop_protection, can not enable root_protection.')
                if self.root_protection != self.cur_cfg["root_protection"]:
                    if self.root_protection == "enable":
                        cmd = "stp root-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp root-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.loop_protection:
                if self.loop_protection == "enable" and self.cur_cfg["root_protection"] == "enable":
                    self.module.fail_json(
                        msg='Error: The interface has enable root_protection, can not enable loop_protection.')
                if self.loop_protection != self.cur_cfg["loop_protection"]:
                    if self.loop_protection == "enable":
                        cmd = "stp loop-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp loop-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.cost:
                if self.cost != self.cur_cfg["cost"]:
                    cmd = "stp cost %s" % self.cost
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                    tmp_changed = True

            if not tmp_changed:
                cmd = "interface %s" % self.interface
                self.updates_cmd.remove(cmd)
                cmds.remove(cmd)

        if cmds:
            self.cli_load_config(cmds)
            self.changed = True

    def absent_stp(self):
        """ Absent stp configuration """

        cmds = list()

        if self.stp_mode:
            if self.stp_mode == self.cur_cfg["stp_mode"]:
                if self.stp_mode != "mstp":
                    cmd = "undo stp mode"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                    self.changed = True

        if self.stp_enable:
            if self.stp_enable != self.cur_cfg["stp_enable"]:
                cmd = "stp %s" % self.stp_enable
                cmds.append(cmd)
                self.updates_cmd.append(cmd)

        if self.stp_converge:
            if self.stp_converge == self.cur_cfg["stp_converge"]:
                cmd = "undo stp converge"
                cmds.append(cmd)
                self.updates_cmd.append(cmd)
                self.changed = True

        if self.edged_port:
            if self.interface == "all":
                if self.edged_port != self.cur_cfg["edged_port"]:
                    if self.edged_port == "enable":
                        cmd = "stp edged-port default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                    else:
                        cmd = "undo stp edged-port default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)

        if self.bpdu_filter:
            if self.interface == "all":
                if self.bpdu_filter != self.cur_cfg["bpdu_filter"]:
                    if self.bpdu_filter == "enable":
                        cmd = "stp bpdu-filter default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                    else:
                        cmd = "undo stp bpdu-filter default"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)

        if self.bpdu_protection:
            if self.bpdu_protection != self.cur_cfg["bpdu_protection"]:
                if self.bpdu_protection == "enable":
                    cmd = "stp bpdu-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                else:
                    cmd = "undo stp bpdu-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)

        if self.tc_protection:
            if self.tc_protection != self.cur_cfg["tc_protection"]:
                if self.tc_protection == "enable":
                    cmd = "stp tc-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                else:
                    cmd = "undo stp tc-protection"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)

        if self.tc_protection_interval:
            if self.tc_protection_interval == self.cur_cfg["tc_protection_interval"]:
                cmd = "undo stp tc-protection interval"
                cmds.append(cmd)
                self.updates_cmd.append(cmd)
                self.changed = True

        if self.tc_protection_threshold:
            if self.tc_protection_threshold == self.cur_cfg["tc_protection_threshold"]:
                if self.tc_protection_threshold != "1":
                    cmd = "undo stp tc-protection threshold"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                    self.changed = True

        # undo interface stp
        if self.interface and self.interface != "all":
            tmp_changed = False

            cmd = "interface %s" % self.interface
            cmds.append(cmd)
            self.updates_cmd.append(cmd)

            if self.edged_port:
                if self.edged_port != self.cur_cfg["edged_port"]:
                    if self.edged_port == "enable":
                        cmd = "stp edged-port enable"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp edged-port"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.bpdu_filter:
                if self.bpdu_filter != self.cur_cfg["bpdu_filter"]:
                    if self.bpdu_filter == "enable":
                        cmd = "stp bpdu-filter enable"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp bpdu-filter"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.root_protection:
                if self.root_protection == "enable" and self.cur_cfg["loop_protection"] == "enable":
                    self.module.fail_json(
                        msg='Error: The interface has enable loop_protection, can not enable root_protection.')
                if self.root_protection != self.cur_cfg["root_protection"]:
                    if self.root_protection == "enable":
                        cmd = "stp root-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp root-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.loop_protection:
                if self.loop_protection == "enable" and self.cur_cfg["root_protection"] == "enable":
                    self.module.fail_json(
                        msg='Error: The interface has enable root_protection, can not enable loop_protection.')
                if self.loop_protection != self.cur_cfg["loop_protection"]:
                    if self.loop_protection == "enable":
                        cmd = "stp loop-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True
                    else:
                        cmd = "undo stp loop-protection"
                        cmds.append(cmd)
                        self.updates_cmd.append(cmd)
                        tmp_changed = True

            if self.cost:
                if self.cost == self.cur_cfg["cost"]:
                    cmd = "undo stp cost"
                    cmds.append(cmd)
                    self.updates_cmd.append(cmd)
                    tmp_changed = True

            if not tmp_changed:
                cmd = "interface %s" % self.interface
                self.updates_cmd.remove(cmd)
                cmds.remove(cmd)

        if cmds:
            self.cli_load_config(cmds)
            self.changed = True

    def work(self):
        """ Work function """

        self.check_params()
        self.get_proposed()
        self.get_existing()

        if self.state == "present":
            self.present_stp()
        else:
            self.absent_stp()

        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'),
        stp_mode=dict(choices=['stp', 'rstp', 'mstp']),
        stp_enable=dict(choices=['enable', 'disable']),
        stp_converge=dict(choices=['fast', 'normal']),
        bpdu_protection=dict(choices=['enable', 'disable']),
        tc_protection=dict(choices=['enable', 'disable']),
        tc_protection_interval=dict(type='str'),
        tc_protection_threshold=dict(type='str'),
        interface=dict(type='str'),
        edged_port=dict(choices=['enable', 'disable']),
        bpdu_filter=dict(choices=['enable', 'disable']),
        cost=dict(type='str'),
        root_protection=dict(choices=['enable', 'disable']),
        loop_protection=dict(choices=['enable', 'disable'])
    )

    argument_spec.update(ce_argument_spec)
    module = Stp(argument_spec=argument_spec)
    module.work()


if __name__ == '__main__':
    main()

Filemanager

Name Type Size Permission Actions
__pycache__ Folder 0755
__init__.py File 0 B 0644
a10_server.py File 10.45 KB 0644
a10_server_axapi3.py File 8.67 KB 0644
a10_service_group.py File 12.91 KB 0644
a10_virtual_server.py File 10.92 KB 0644
aireos_command.py File 6.93 KB 0644
aireos_config.py File 13.73 KB 0644
apconos_command.py File 5.96 KB 0644
aruba_command.py File 6.7 KB 0644
aruba_config.py File 16.41 KB 0644
avi_actiongroupconfig.py File 5.3 KB 0644
avi_alertconfig.py File 12.43 KB 0644
avi_alertemailconfig.py File 3.73 KB 0644
avi_alertscriptconfig.py File 3.53 KB 0644
avi_alertsyslogconfig.py File 3.69 KB 0644
avi_analyticsprofile.py File 31.36 KB 0644
avi_api_session.py File 8.86 KB 0644
avi_api_version.py File 2.65 KB 0644
avi_applicationpersistenceprofile.py File 6.47 KB 0644
avi_applicationprofile.py File 7.58 KB 0644
avi_authprofile.py File 5.06 KB 0644
avi_autoscalelaunchconfig.py File 4.38 KB 0644
avi_backup.py File 3.95 KB 0644
avi_backupconfiguration.py File 5.35 KB 0644
avi_certificatemanagementprofile.py File 3.64 KB 0644
avi_cloud.py File 11.09 KB 0644
avi_cloudconnectoruser.py File 4.57 KB 0644
avi_cloudproperties.py File 3.66 KB 0644
avi_cluster.py File 3.79 KB 0644
avi_clusterclouddetails.py File 3.47 KB 0644
avi_controllerproperties.py File 19.1 KB 0644
avi_customipamdnsprofile.py File 3.76 KB 0644
avi_dnspolicy.py File 3.69 KB 0644
avi_errorpagebody.py File 3.78 KB 0644
avi_errorpageprofile.py File 4.44 KB 0644
avi_gslb.py File 14.35 KB 0644
avi_gslbgeodbprofile.py File 4.07 KB 0644
avi_gslbservice.py File 9.43 KB 0644
avi_gslbservice_patch_member.py File 10.19 KB 0644
avi_hardwaresecuritymodulegroup.py File 3.5 KB 0644
avi_healthmonitor.py File 7.44 KB 0644
avi_httppolicyset.py File 5.22 KB 0644
avi_ipaddrgroup.py File 4.8 KB 0644
avi_ipamdnsproviderprofile.py File 6.04 KB 0644
avi_l4policyset.py File 4.03 KB 0644
avi_microservicegroup.py File 3.78 KB 0644
avi_network.py File 5.13 KB 0644
avi_networkprofile.py File 4.14 KB 0644
avi_networksecuritypolicy.py File 4.15 KB 0644
avi_pkiprofile.py File 5.32 KB 0644
avi_pool.py File 22.34 KB 0644
avi_poolgroup.py File 5.87 KB 0644
avi_poolgroupdeploymentpolicy.py File 5.49 KB 0644
avi_prioritylabels.py File 3.62 KB 0644
avi_role.py File 3.25 KB 0644
avi_scheduler.py File 5.08 KB 0644
avi_seproperties.py File 3.51 KB 0644
avi_serverautoscalepolicy.py File 7.22 KB 0644
avi_serviceengine.py File 5.74 KB 0644
avi_serviceenginegroup.py File 53.38 KB 0644
avi_snmptrapprofile.py File 3.4 KB 0644
avi_sslkeyandcertificate.py File 6.75 KB 0644
avi_sslprofile.py File 8.21 KB 0644
avi_stringgroup.py File 4.08 KB 0644
avi_systemconfiguration.py File 6.76 KB 0644
avi_tenant.py File 3.87 KB 0644
avi_trafficcloneprofile.py File 4.01 KB 0644
avi_user.py File 6.12 KB 0644
avi_useraccount.py File 5.02 KB 0644
avi_useraccountprofile.py File 4.65 KB 0644
avi_virtualservice.py File 29.62 KB 0644
avi_vrfcontext.py File 4.51 KB 0644
avi_vsdatascriptset.py File 4.86 KB 0644
avi_vsvip.py File 5.21 KB 0644
avi_webhook.py File 3.77 KB 0644
bcf_switch.py File 4.86 KB 0644
bigmon_chain.py File 3.99 KB 0644
bigmon_policy.py File 6.23 KB 0644
ce_aaa_server.py File 69.09 KB 0644
ce_aaa_server_host.py File 101.81 KB 0644
ce_acl.py File 35.95 KB 0644
ce_acl_advance.py File 73.4 KB 0644
ce_acl_interface.py File 10.36 KB 0644
ce_bfd_global.py File 21.02 KB 0644
ce_bfd_session.py File 21.99 KB 0644
ce_bfd_view.py File 19.71 KB 0644
ce_bgp.py File 79.52 KB 0644
ce_bgp_af.py File 133.02 KB 0644
ce_bgp_neighbor.py File 72.12 KB 0644
ce_bgp_neighbor_af.py File 110.55 KB 0644
ce_command.py File 7.79 KB 0644
ce_config.py File 17.88 KB 0644
ce_dldp.py File 18.62 KB 0644
ce_dldp_interface.py File 22.41 KB 0644
ce_eth_trunk.py File 22.44 KB 0644
ce_evpn_bd_vni.py File 39.01 KB 0644
ce_evpn_bgp.py File 26.71 KB 0644
ce_evpn_bgp_rr.py File 18 KB 0644
ce_evpn_global.py File 6.93 KB 0644
ce_facts.py File 11.4 KB 0644
ce_file_copy.py File 13.18 KB 0644
ce_info_center_debug.py File 21.33 KB 0644
ce_info_center_global.py File 67.85 KB 0644
ce_info_center_log.py File 20.09 KB 0644
ce_info_center_trap.py File 24.65 KB 0644
ce_interface.py File 31 KB 0644
ce_interface_ospf.py File 30.25 KB 0644
ce_ip_interface.py File 23.63 KB 0644
ce_is_is_instance.py File 8.95 KB 0644
ce_is_is_interface.py File 27.75 KB 0644
ce_is_is_view.py File 76.21 KB 0644
ce_lacp.py File 17.68 KB 0644
ce_link_status.py File 21.76 KB 0644
ce_lldp.py File 31.85 KB 0644
ce_lldp_interface.py File 68.35 KB 0644
ce_mdn_interface.py File 12.96 KB 0644
ce_mlag_config.py File 34.52 KB 0644
ce_mlag_interface.py File 36.1 KB 0644
ce_mtu.py File 18.87 KB 0644
ce_multicast_global.py File 8.98 KB 0644
ce_multicast_igmp_enable.py File 17.36 KB 0644
ce_netconf.py File 5.81 KB 0644
ce_netstream_aging.py File 18.14 KB 0644
ce_netstream_export.py File 18.9 KB 0644
ce_netstream_global.py File 36.93 KB 0644
ce_netstream_template.py File 16.57 KB 0644
ce_ntp.py File 20.32 KB 0644
ce_ntp_auth.py File 16.36 KB 0644
ce_ospf.py File 33.93 KB 0644
ce_ospf_vrf.py File 67.18 KB 0644
ce_reboot.py File 4.28 KB 0644
ce_rollback.py File 15.86 KB 0644
ce_sflow.py File 44.08 KB 0644
ce_snmp_community.py File 34.64 KB 0644
ce_snmp_contact.py File 7.23 KB 0644
ce_snmp_location.py File 6.96 KB 0644
ce_snmp_target_host.py File 32.84 KB 0644
ce_snmp_traps.py File 19.59 KB 0644
ce_snmp_user.py File 36.66 KB 0644
ce_startup.py File 15.45 KB 0644
ce_static_route.py File 29 KB 0644
ce_static_route_bfd.py File 60.9 KB 0644
ce_stp.py File 36.76 KB 0644
ce_switchport.py File 38.54 KB 0644
ce_vlan.py File 20.88 KB 0644
ce_vrf.py File 10.73 KB 0644
ce_vrf_af.py File 30.04 KB 0644
ce_vrf_interface.py File 15.17 KB 0644
ce_vrrp.py File 52.15 KB 0644
ce_vxlan_arp.py File 24.02 KB 0644
ce_vxlan_gateway.py File 33.38 KB 0644
ce_vxlan_global.py File 18.3 KB 0644
ce_vxlan_tunnel.py File 30.95 KB 0644
ce_vxlan_vap.py File 33.03 KB 0644
cnos_backup.py File 9.69 KB 0644
cnos_banner.py File 5.64 KB 0644
cnos_bgp.py File 43.15 KB 0644
cnos_command.py File 5.84 KB 0644
cnos_conditional_command.py File 5.62 KB 0644
cnos_conditional_template.py File 6.68 KB 0644
cnos_config.py File 10.86 KB 0644
cnos_factory.py File 3.36 KB 0644
cnos_facts.py File 17.45 KB 0644
cnos_image.py File 8.65 KB 0644
cnos_interface.py File 15.57 KB 0644
cnos_l2_interface.py File 17.75 KB 0644
cnos_l3_interface.py File 12.54 KB 0644
cnos_linkagg.py File 9.84 KB 0644
cnos_lldp.py File 4.13 KB 0644
cnos_logging.py File 12.73 KB 0644
cnos_reload.py File 3.25 KB 0644
cnos_rollback.py File 10.32 KB 0644
cnos_save.py File 3.42 KB 0644
cnos_showrun.py File 3.34 KB 0644
cnos_static_route.py File 9.47 KB 0644
cnos_system.py File 12.93 KB 0644
cnos_template.py File 5.25 KB 0644
cnos_user.py File 12.28 KB 0644
cnos_vlag.py File 15.19 KB 0644
cnos_vlan.py File 10.69 KB 0644
cnos_vrf.py File 11.64 KB 0644
cv_server_provision.py File 23.67 KB 0644
dladm_etherstub.py File 3.93 KB 0644
dladm_iptun.py File 7.49 KB 0644
dladm_linkprop.py File 7.53 KB 0644
dladm_vlan.py File 5.15 KB 0644
dladm_vnic.py File 6.43 KB 0644
edgeos_command.py File 5.57 KB 0644
edgeos_config.py File 10.65 KB 0644
edgeos_facts.py File 8.06 KB 0644
edgeswitch_facts.py File 7.56 KB 0644
edgeswitch_vlan.py File 15.03 KB 0644
enos_command.py File 6.07 KB 0644
enos_config.py File 10.95 KB 0644
enos_facts.py File 15.23 KB 0644
eric_eccli_command.py File 6.89 KB 0644
exos_command.py File 7.23 KB 0644
exos_config.py File 16.96 KB 0644
exos_facts.py File 5.72 KB 0644
exos_l2_interfaces.py File 26.19 KB 0644
exos_lldp_global.py File 10.39 KB 0644
exos_lldp_interfaces.py File 13.68 KB 0644
exos_vlans.py File 16.07 KB 0644
flowadm.py File 14.32 KB 0644
ftd_configuration.py File 4.93 KB 0644
ftd_file_download.py File 4.26 KB 0644
ftd_file_upload.py File 3.54 KB 0644
ftd_install.py File 11.54 KB 0644
iap_start_workflow.py File 5.21 KB 0644
iap_token.py File 3.83 KB 0644
icx_banner.py File 6.54 KB 0644
icx_command.py File 7.22 KB 0644
icx_config.py File 18.28 KB 0644
icx_copy.py File 15.16 KB 0644
icx_facts.py File 17 KB 0644
icx_interface.py File 23.05 KB 0644
icx_l3_interface.py File 14.56 KB 0644
icx_linkagg.py File 10.03 KB 0644
icx_lldp.py File 5.13 KB 0644
icx_logging.py File 18.1 KB 0644
icx_ping.py File 7.84 KB 0644
icx_static_route.py File 9.38 KB 0644
icx_system.py File 16.14 KB 0644
icx_user.py File 13.05 KB 0644
icx_vlan.py File 26.24 KB 0644
ig_config.py File 16 KB 0644
ig_unit_information.py File 3.9 KB 0644
ipadm_addr.py File 11.31 KB 0644
ipadm_addrprop.py File 6.86 KB 0644
ipadm_if.py File 5.47 KB 0644
ipadm_ifprop.py File 7.94 KB 0644
ipadm_prop.py File 6.79 KB 0644
ironware_command.py File 5.07 KB 0644
ironware_config.py File 11.11 KB 0644
ironware_facts.py File 19.45 KB 0644
nclu.py File 8.02 KB 0644
netact_cm_command.py File 11.77 KB 0644
netscaler_cs_action.py File 8.71 KB 0644
netscaler_cs_policy.py File 9.28 KB 0644
netscaler_cs_vserver.py File 42.83 KB 0644
netscaler_gslb_service.py File 23.35 KB 0644
netscaler_gslb_site.py File 13.73 KB 0644
netscaler_gslb_vserver.py File 32.98 KB 0644
netscaler_lb_monitor.py File 46.23 KB 0644
netscaler_lb_vserver.py File 70.58 KB 0644
netscaler_nitro_request.py File 27.82 KB 0644
netscaler_save_config.py File 4.67 KB 0644
netscaler_server.py File 12.88 KB 0644
netscaler_service.py File 30.9 KB 0644
netscaler_servicegroup.py File 34.33 KB 0644
netscaler_ssl_certkey.py File 11.6 KB 0644
nos_command.py File 7.15 KB 0644
nos_config.py File 14.61 KB 0644
nos_facts.py File 13.44 KB 0644
nuage_vspk.py File 41.3 KB 0644
opx_cps.py File 12.18 KB 0644
ordnance_config.py File 12.03 KB 0644
ordnance_facts.py File 8.26 KB 0644
pn_access_list.py File 4.29 KB 0644
pn_access_list_ip.py File 4.42 KB 0644
pn_admin_service.py File 5.62 KB 0644
pn_admin_session_timeout.py File 2.96 KB 0644
pn_admin_syslog.py File 6.4 KB 0644
pn_connection_stats_settings.py File 10.3 KB 0644
pn_cpu_class.py File 5.65 KB 0644
pn_cpu_mgmt_class.py File 3.75 KB 0644
pn_dhcp_filter.py File 4.66 KB 0644
pn_dscp_map.py File 4.03 KB 0644
pn_dscp_map_pri_map.py File 3.99 KB 0644
pn_fabric_local.py File 4.71 KB 0644
pn_igmp_snooping.py File 6.22 KB 0644
pn_ipv6security_raguard.py File 6.64 KB 0644
pn_ipv6security_raguard_port.py File 3.73 KB 0644
pn_ipv6security_raguard_vlan.py File 4.77 KB 0644
pn_log_audit_exception.py File 5.65 KB 0644
pn_port_config.py File 11.93 KB 0644
pn_port_cos_bw.py File 3.96 KB 0644
pn_port_cos_rate_setting.py File 5.67 KB 0644
pn_prefix_list.py File 4.12 KB 0644
pn_prefix_list_network.py File 5.06 KB 0644
pn_role.py File 6.14 KB 0644
pn_snmp_community.py File 4.99 KB 0644
pn_snmp_trap_sink.py File 6 KB 0644
pn_snmp_vacm.py File 6.09 KB 0644
pn_stp.py File 5.91 KB 0644
pn_stp_port.py File 5.02 KB 0644
pn_switch_setup.py File 12.88 KB 0644
pn_user.py File 5.11 KB 0644
pn_vflow_table_profile.py File 3.62 KB 0644
pn_vrouter_bgp.py File 16.33 KB 0644
pn_vrouter_bgp_network.py File 5.06 KB 0644
pn_vrouter_interface_ip.py File 7.05 KB 0644
pn_vrouter_loopback_interface.py File 6.4 KB 0644
pn_vrouter_ospf.py File 5.57 KB 0644
pn_vrouter_ospf6.py File 5.49 KB 0644
pn_vrouter_packet_relay.py File 5.49 KB 0644
pn_vrouter_pim_config.py File 4.77 KB 0644
pn_vtep.py File 5.1 KB 0644
slxos_command.py File 7.19 KB 0644
slxos_config.py File 17.87 KB 0644
slxos_facts.py File 13.43 KB 0644
slxos_interface.py File 14.25 KB 0644
slxos_l2_interface.py File 16.58 KB 0644
slxos_l3_interface.py File 9.41 KB 0644
slxos_linkagg.py File 9.57 KB 0644
slxos_lldp.py File 3.33 KB 0644
slxos_vlan.py File 9.39 KB 0644
sros_command.py File 6.66 KB 0644
sros_config.py File 10.97 KB 0644
sros_rollback.py File 6.26 KB 0644
vdirect_commit.py File 12.58 KB 0644
vdirect_file.py File 8.99 KB 0644
vdirect_runnable.py File 13.38 KB 0644
voss_command.py File 7.75 KB 0644
voss_config.py File 18.33 KB 0644
voss_facts.py File 15.67 KB 0644