get_inventory.py 9.77 KB
Newer Older
bee26's avatar
bee26 committed
1
# -*- coding: utf-8 -*-
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
2
3
4
# ---------------------------------------------------------------------
# Eltex.MES.get_inventory
# ---------------------------------------------------------------------
5
# Copyright (C) 2007-2022 The NOC Project
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
6
7
8
9
10
# See LICENSE for details
# ---------------------------------------------------------------------

# Python modules
import re
Dmitry Volodin's avatar
Dmitry Volodin committed
11

Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
12
13
14
# NOC modules
from noc.core.script.base import BaseScript
from noc.sa.interfaces.igetinventory import IGetInventory
kk's avatar
kk committed
15
from noc.core.text import parse_table
kk's avatar
kk committed
16
from noc.core.validators import is_int
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
17
18
19
20
21
22
23


class Script(BaseScript):
    name = "Eltex.MES.get_inventory"
    interface = IGetInventory
    cache = True

Dmitry Volodin's avatar
Dmitry Volodin committed
24
25
26
    rx_hardware = re.compile(r"^HW version+\s+(?P<hardware>\S+)$", re.MULTILINE)
    rx_serial1 = re.compile(r"^Serial number :\s+(?P<serial>\S+)$", re.MULTILINE)
    rx_serial2 = re.compile(r"^\s+1\s+(?P<serial>\S+)\s*\n", re.MULTILINE)
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
27
    rx_serial3 = re.compile(
Dmitry Volodin's avatar
Dmitry Volodin committed
28
29
30
31
        r"^\s+1\s+(?P<mac>\S+)\s+(?P<hardware>\S+)\s+(?P<serial>\S+)\s*\n", re.MULTILINE
    )
    rx_platform = re.compile(r"^System Object ID:\s+(?P<platform>\S+)$", re.MULTILINE)
    rx_descr = re.compile(r"^System (?:Description|Type):\s+(?P<descr>.+)$", re.MULTILINE)
32
33
34
    rx_pwr = re.compile(
        r"^(?P<type>\S+) Power Supply Status \[(?P<pwr_type>\S+)\]:\s+", re.MULTILINE
    )
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
35
36
37
38
39
40
41
42
43
44
45
    rx_trans = re.compile(
        r"^\s*Transceiver information:\s*\n"
        r"^\s*Vendor name: (?P<vendor>.+?)\s*\n"
        r"^\s*Serial number: (?P<serial>.+?)\s*\n"
        r"(^\s*Part number: (?P<part_no>.+?)\s*\n)?"
        r"(^\s*Vendor revision: (?P<revision>.+?)\s*\n)?"
        r"^\s*Connector type: (?P<conn_type>.+?)\s*\n"
        r"^\s*Type: (?P<type>.+?)\s*\n"
        r"^\s*Compliance code: (?P<code>.+?)\s*\n"
        r"^\s*Laser wavelength: (?P<wavelength>.+?)\s*\n"
        r"^\s*Transfer distance: (?P<distance>.+?)\s*\n",
Dmitry Volodin's avatar
Dmitry Volodin committed
46
        re.MULTILINE,
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
47
    )
48
    has_detail = True
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
49
50
51
52
53
54
55
56

    def get_chassis(self, plat, ver, ser):
        match = self.rx_descr.search(plat)
        if match and match.group("descr").startswith("MES"):
            descr = match.group("descr")
        else:
            descr = None

57
        platform, revision = None, None
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
58
59
60
61
        match = self.rx_platform.search(plat)
        if match:
            platform = match.group("platform")
            platform = platform.split(".")[8]
62
            platform, revision = self.profile.get_platform(platform)
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        elif self.has_capability("Stack | Members"):
            # Try to obtain platform from description
            if descr and descr.startswith("MES"):
                platform = descr.split()[0]  # MES-3124F
                if not descr.startswith("MES-"):  # MES2208P
                    platform = "MES-%s" % platform[3:]

        hardware = self.rx_hardware.search(ver)

        match = self.rx_serial1.search(ser)
        match2 = self.rx_serial3.search(ser)
        if match:
            serial = self.rx_serial1.search(ser)
        elif match2:
            # Unit    MAC address    Hardware version Serial number
            # ---- ----------------- ---------------- -------------
            # 1   xx:xx:xx:xx:xx:xx     02.01.02      ESXXXXXXX
            serial = self.rx_serial3.search(ser)
        else:
            serial = self.rx_serial2.search(ser)

Dmitry Volodin's avatar
Dmitry Volodin committed
84
        r = {"type": "CHASSIS", "vendor": "ELTEX", "part_no": [platform]}
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
85
86
        if serial:
            r["serial"] = serial.group("serial")
87
88
89
        if revision:
            r["revision"] = revision.split(".")[-1]
        elif hardware:
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
90
91
92
93
94
            r["revision"] = hardware.group("hardware")
        if descr:
            r["description"] = descr
        return r

95
96
    def get_pwr(self, type, pwr_type, platform):
        if platform in [
97
98
            "MES-3108",
            "MES-3108F",
99
            "MES-3116",
bee26's avatar
bee26 committed
100
            "MES-3116F",
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
            "MES-3124",
            "MES-3124F",
            "MES-3308F",
            "MES-3316F",
            "MES-3324",
            "MES-3324F",
            "MES-3348",
            "MES-3348F",
            "MES-5312",
            "MES-5324",
            "MES-5332A",
        ]:
            if pwr_type == "AC":
                part_no = "PM160-220/12"
            elif pwr_type == "DC":
                part_no = "PM100-48/12"
            elif pwr_type == "N/A":
                part_no = "PM160-220/12"
            else:
                raise self.NotSupportedError("Unknown PS type: %s" % pwr_type)
        elif platform in ["MES-5148", "MES-5248", "MES-5448", "MES-7048"]:
            if pwr_type == "AC":
                part_no = "PM350-220/12"
            elif pwr_type == "DC":
                part_no = "PM350-48/12"
            elif pwr_type == "N/A":
                part_no = "PM350-220/12"
            else:
                raise self.NotSupportedError("Unknown PS type: %s" % pwr_type)
        elif platform in ["MES-2348P"]:
            part_no = "PM950"
132
        else:
133
            raise self.NotSupportedError("PS on unknown platform: %s" % platform)
134
135
136
137
        if type not in ["Main", "Redundant"]:
            raise self.NotSupportedError("Unknown PS type: %s" % type)
        return {"type": "PWR", "vendor": "ELTEX", "part_no": part_no, "number": type}

Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
138
    def get_trans(self, ifname):
139
140
141
142
143
144
145
        if self.has_detail:
            try:
                v = self.cli("show fiber-ports optical-transceiver detailed interface %s" % ifname)
            except self.CLISyntaxError:
                self.has_detail = False
        if not self.has_detail:
            v = self.cli("show fiber-ports optical-transceiver interface %s" % ifname)
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
146
        match = self.rx_trans.search(v)
Dmitry Volodin's avatar
Dmitry Volodin committed
147
        r = {"type": "XCVR", "vendor": match.group("vendor")}
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
        if match.group("serial"):
            r["serial"] = match.group("serial")
        if match.group("revision"):
            r["revision"] = match.group("revision")
        if ifname.startswith("gi"):
            r["number"] = "gi%s" % ifname.split("/")[-1]
        if ifname.startswith("te"):
            r["number"] = "te%s" % ifname.split("/")[-1]
        if match.group("part_no"):
            part_no = match.group("part_no")
        else:
            r["vendor"] = "OEM"
            code = match.group("code")
            if code == "1000BASE-LX":
                part_no = "NoName | Transceiver | 1G | SFP LX"
            elif code == "BaseBX10":
                wavelength = match.group("wavelength")
                if wavelength == "1310 nm":
                    part_no = "NoName | Transceiver | 1G | SFP BX10D"
                elif wavelength == "1490 nm":
                    part_no = "NoName | Transceiver | 1G | SFP BX10U"
                else:
                    # raise self.NotSupportedError()
                    part_no = "NoName | Transceiver | 1G | SFP"
172
173
            elif code == "1000BASE-T":
                part_no = "NoName | Transceiver | 1G | SFP T"
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
174
175
            elif code == "10GBASE-LR":
                part_no = "NoName | Transceiver | 10G | SFP+ LR"
176
177
            elif code == "10GBASE-ER":
                part_no = "NoName | Transceiver | 10G | SFP+ ER"
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
178
179
180
            elif code == "unknown":
                part_no = "NoName | Transceiver | 1G | SFP"
            else:
181
                raise self.NotSupportedError("Unknown Compliance code: %s" % code)
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
182
183
184
        r["part_no"] = part_no
        return r

185
186
    def get_optical_ports(self):
        opt_ports = []
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
187
188
        try:
            v = self.cli("show fiber-ports optical-transceiver")
189
190
            for i in parse_table(v, footer=r"Temp\s+- Internally measured transceiver temperature"):
                if i[1] in ["OK", "N/S"] or is_int(i[1]):
191
                    opt_ports += [i[0]]
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
192
193
        except self.CLISyntaxError:
            pass
194
195
196
197
198
199
        return opt_ports

    def execute_cli(self, **kwargs):
        res = []

        ports = self.get_optical_ports()
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
200
201

        if self.has_capability("Stack | Members"):
202
            has_unit_command = True
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
203
            for unit in self.capabilities["Stack | Member Ids"].split(" | "):
204
205
206
207
208
209
210
211
212
213
                try:
                    plat = self.cli("show system unit %s" % unit, cached=True)
                except self.CLISyntaxError:
                    # Found on MES1124M SW version 1.1.46
                    # Left for compatibility with other models
                    if unit == "1":
                        plat = self.cli("show system", cached=True)
                        has_unit_command = False
                    else:
                        raise self.NotSupportedError()
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
214
                if not self.is_has_image:
215
216
217
218
                    if has_unit_command:
                        ver = self.cli("show version unit %s" % unit, cached=True)
                    else:
                        ver = self.cli("show version", cached=True)
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
219
220
                else:
                    ver = ""
221
222
223
224
                if has_unit_command:
                    ser = self.cli("show system id unit %s" % unit, cached=True)
                else:
                    ser = self.cli("show system", cached=True)
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
225
                r = self.get_chassis(plat, ver, ser)
226
                platform = r["part_no"][0]
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
227
                res += [r]
228
                for match in self.rx_pwr.finditer(plat):
229
                    res += [self.get_pwr(match.group("type"), match.group("pwr_type"), platform)]
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
230
231
232
233
234
235
236
237
238
                for p in ports:
                    if p.startswith("gi") or p.startswith("te"):
                        if unit == p[2]:
                            res += [self.get_trans(p)]
        else:
            plat = self.cli("show system", cached=True)
            ver = self.cli("show version", cached=True)
            ser = self.cli("show system id", cached=True)
            r = self.get_chassis(plat, ver, ser)
239
            platform = r["part_no"][0]
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
240
            res = [r]
241
            for match in self.rx_pwr.finditer(plat):
242
                res += [self.get_pwr(match.group("type"), match.group("pwr_type"), platform)]
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
243
244
245
246
            for p in ports:
                res += [self.get_trans(p)]

        return res