File: exercise_ledctl.py

package info (click to toggle)
ledmon 0.97-1.2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 712 kB
  • sloc: ansic: 7,691; python: 120; sh: 78; makefile: 50
file content (175 lines) | stat: -rwxr-xr-x 5,439 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/python3

# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (C) 2023 Red Hat Inc.

# Simple tests for ledctl.  This needs to be expanded.

import sys
import subprocess
import re

LEDCTL_BIN = "/usr/sbin/ledctl"
SLOT_LINE = re.compile(r"^slot: (.+)led state:(.+)device:(.+)$")

SLOT_FILTERS = []

# Note:
# RH SES lab hardware has some enclosures which don't work, which includes the ses tools from sg_utils
# and libStorageMgmt, so it's not something specific with ledmon project.
#
# To run this test do ./exercise_led_ctl ../src/ledctl sg3- sg2-
# to filter out enclosures that don't work
#
# exit code == 0 -> success


class Slot:
    def __init__(self, cntrl_type, slot_id, state, device_node):
        self.cntrl_type = cntrl_type
        self.slot = slot_id
        self.state = state.lower()
        self.device_node = None
        if device_node.startswith('/dev/'):
            self.device_node = device_node

    def __str__(self):
        return "slot: %s state: %s device: %s" % (self.slot, self.state, self.device_node)


def get_controllers_with_slot_functionality():
    rc = {}
    result = subprocess.run([LEDCTL_BIN, "--list-controllers"], capture_output=True)
    if result.returncode == 0:
        out = result.stdout.decode("utf-8")
        for raw_line in out.split("\n"):
            line = raw_line.strip()
            if "SCSI" in line:
                rc["SCSI"] = True
            elif "VMD" in line:
                rc["VMD"] = True
            elif "NPEM" in line:
                rc["NPEM"] = True
    return rc.keys()


def process_slot_line(controller, rawline):
    line = rawline.strip()
    match = SLOT_LINE.match(line)
    if match is not None:
        slot = Slot(controller, match.group(1).strip(), match.group(2).strip(), match.group(3).strip())
        for slot_filter in SLOT_FILTERS:
            if slot.slot.startswith(slot_filter):
                # Filter out this slot
                return None
        return slot
    return None


def get_slot(slot_o):
    result = subprocess.run([LEDCTL_BIN,
                             "--get-slot",
                             "--controller-type", slot_o.cntrl_type,
                             "--slot", slot_o.slot], capture_output=True)
    if result.returncode == 0:
        out = result.stdout.decode("utf-8")
        slot = process_slot_line(slot_o.cntrl_type, out)
        return slot
    else:
        print("Failed to set slot: {result}")
        return None


def get_slots(controller_type):
    rc = []
    result = subprocess.run([LEDCTL_BIN,
                             "--list-slots",
                             "--controller-type", controller_type], capture_output=True)
    if result.returncode == 0:
        out = result.stdout.decode("utf-8")
        for l in out.split("\n"):
            s = process_slot_line(controller_type, l)
            if s is not None:
                rc.append(s)
    return rc


def set_slot_state(slot_o, state):
    result = subprocess.run([LEDCTL_BIN,
                             "--set-slot",
                             "--controller-type", slot_o.cntrl_type,
                             "--slot", slot_o.slot,
                             "--state", state], capture_output=True)
    if result.returncode == 0:
        return True
    else:
        print("Failed to set slot: {result}")
        return False


def get_all_slots():
    all_slots = []
    for controller in get_controllers_with_slot_functionality():
        all_slots.extend(get_slots(controller))
    return all_slots


def set_state_by_dev_node(dev_node, state):
    option = "%s=%s" % (state, dev_node)
    result = subprocess.run([LEDCTL_BIN, option], capture_output=True)
    if result.returncode == 0:
        return True
    else:
        print(f"Error while using led non slot syntax {option} {result}")
        return False


def test_non_slot_set_path():
    """
    Test setting the led status by using non-slot syntax, eg. ledctl locate=/dev/sda
    :return:
    """
    slots_with_device_nodes = [s for s in get_all_slots() if s.device_node is not None]

    for slot in slots_with_device_nodes:
        for state in ["failure", "locate", "normal"]:
            set_state_by_dev_node(slot.device_node, state)
            cur = get_slot(slot)
            if cur.state != state:
                print(f"unable to set from {slot} to {state}, current = {cur} using non-slot syntax")
                sys.exit(1)


def test_slot_state_walk():
    """
    Test that we can set slots to different states and verify that they reported a change
    :return:
    """
    slots = get_all_slots()

    for slot in slots:
        for state in ["locate", "failure", "normal"]:
            result = set_slot_state(slot, state)
            if not result:
                print("failed to set slot state")
                sys.exit(1)
            cur = get_slot(slot)
            if cur.state != state:
                print(f"unable to set from {slot} to {state}, current = {cur}")
                sys.exit(1)


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"syntax: {sys.argv[0]} <ledctl binary>")
        sys.exit(1)
    elif len(sys.argv) > 2:
        # optional slots to skip as known to be not working
        SLOT_FILTERS = sys.argv[2:]
        print(f"slot filter = {SLOT_FILTERS}")

    LEDCTL_BIN = sys.argv[1]
    test_non_slot_set_path()
    test_slot_state_walk()
    sys.exit(0)