get_version.py 9.13 KB
Newer Older
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
1
2
3
# ---------------------------------------------------------------------
# Cisco.IOS.get_version
# ---------------------------------------------------------------------
4
# Copyright (C) 2007-2019 The NOC Project
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
5
6
# See LICENSE for details
# ---------------------------------------------------------------------
7

Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
8
# Python modules
9
import re
Dmitry Volodin's avatar
Dmitry Volodin committed
10

Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
11
# NOC modules
Dmitry Volodin's avatar
Dmitry Volodin committed
12
13
from noc.core.script.base import BaseScript
from noc.sa.interfaces.igetversion import IGetVersion
14
from noc.core.mib import mib
Dmitry Volodin's avatar
Dmitry Volodin committed
15
16


Dmitry Volodin's avatar
Dmitry Volodin committed
17
class Script(BaseScript):
Dmitry Volodin's avatar
Dmitry Volodin committed
18
19
    name = "Cisco.IOS.get_version"
    cache = True
Dmitry Volodin's avatar
Dmitry Volodin committed
20
    interface = IGetVersion
21
    always_prefer = "S"
22

23
    rx_version = re.compile(
24
25
        r"^(?:Cisco IOS Software( \[(?:Gibraltar|Fuji|Everest|Denali|Amsterdam)\])?,.*?|IOS \(tm\)) (IOS[\-\s]XE "
        r"Software,\s)?(?P<platform>.+?) Software \((?P<image>[^)]+)\), (Experimental )?"
Dmitry Volodin's avatar
Dmitry Volodin committed
26
27
28
        r"Version (?P<version>[^\s,]+)",
        re.MULTILINE | re.DOTALL,
    )
29
    rx_snmp_ver = re.compile(
30
        r"^(?:Cisco IOS Software( \[(?:Gibraltar|Fuji|Everest|Denali|Amsterdam)\])?,.*?|IOS \(tm\)) (?P<platform>.+?) "
31
        r"Software \((?P<image>[^)]+)\), (Experimental )?Version (?P<version>[^\s,]+)",
Dmitry Volodin's avatar
Dmitry Volodin committed
32
33
        re.MULTILINE | re.DOTALL,
    )
34
    rx_platform = re.compile(
35
        r"^cisco (?P<platform>\S+) \(\S+\) processor( \(revision.+?\))? with",
Dmitry Volodin's avatar
Dmitry Volodin committed
36
37
        re.IGNORECASE | re.MULTILINE,
    )
38
    rx_old_platform = re.compile(r"^(?P<platform>\S+) chassis")
Dmitry Volodin's avatar
Dmitry Volodin committed
39
    rx_invalid_platforms = re.compile(r"IOS[\-\s]XE|EGR|Catalyst( \S+)? L3 Switch|s\d+\S+")
40
41
42
    rx_item = re.compile(
        r"^NAME: \"(?P<name>[^\"]+)\", DESCR: \"(?P<descr>[^\"]+)\"\n"
        r"PID:\s+(?P<pid>\S+)?\s*,\s+VID:\s+(?P<vid>\S+)?\s*, "
Dmitry Volodin's avatar
Dmitry Volodin committed
43
44
45
        r"SN:\s(?P<serial>\S+)?",
        re.MULTILINE | re.DOTALL,
    )
46
    rx_7100 = re.compile(
Dmitry Volodin's avatar
Dmitry Volodin committed
47
48
        r"^(?:uBR|CISCO)?71(?:20|40|11|14)(-\S+)? " r"(?:Universal Broadband Router|chassis)"
    )
49
    rx_c4900m = re.compile(r"^Cisco Systems, Inc. (?P<part_no>\S+) \d+ slot switch")
50
51
52
53
54
    rx_ver = re.compile(
        r"Model revision number\s+:\s+(?P<revision>\S+)\s*\n"
        r"Motherboard revision number\s+:\s+\S+\s*\n"
        r"Model number\s+:\s+(?P<part_no>\S+)\s*\n"
        r"System serial number\s+:\s+(?P<serial>\S+)\s*\n",
Dmitry Volodin's avatar
Dmitry Volodin committed
55
56
        re.IGNORECASE | re.MULTILINE | re.DOTALL,
    )
57
    rx_ver1 = re.compile(
Dmitry Volodin's avatar
Dmitry Volodin committed
58
59
60
61
62
        r"^cisco (?P<part_no>\S+) \(\S+\) processor( " r"\(revision(?P<revision>.+?)\))? with",
        re.IGNORECASE | re.MULTILINE,
    )
    IGNORED_SERIAL = {"H22L714"}
    IGNORED_NAMES = {"c7201"}
63

64
65
66
67
68
69
70
71
72
73
74
75
    def clear_platform(self, platform):
        """
        Clear platform string
        :param platform:
        :return:
        """
        # Clear K9 in platform
        if platform.endswith("/K9"):
            platform = platform[:-3]

        return platform

76
    def execute_snmp(self, **kwargs):
77
        v = self.snmp.get(mib["SNMPv2-MIB::sysDescr", 0], cached=True)
78
79
80
81
82
83
        if v:
            s = ""
            match = self.rx_snmp_ver.search(v)
            platform = match.group("platform")
            # inventory
            # p = self.snmp.get("1.3.6.1.2.1.47.1.1.1.1.2.1001")
84
            p = self.snmp.get(mib["ENTITY-MIB::entPhysicalDescr", 1001])
85
            if p and (p.startswith("WS-C") or p.startswith("ME-3")):
86
                platform = p
87
                s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 1001])
88
89
            else:
                # Found in WS-C3650-48TD
90
                p = self.snmp.get(mib["ENTITY-MIB::entPhysicalDescr", 1000])
91
92
                if p and p.startswith("WS-C"):
                    platform = p
93
                    s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 1000])
94
95
                else:
                    # CISCO-ENTITY-MIB::entPhysicalModelName
96
                    p = self.snmp.get(mib["ENTITY-MIB::entPhysicalModelName", 1])
97
98
99
100
                    if not p:
                        # Found in WS-C650X-E
                        p = self.snmp.get(mib["ENTITY-MIB::entPhysicalModelName", 2])
                        s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 2])
101
                    # WS-C4500X-32 return '  ', WS-C4900M return 'MIDPLANE'
102
                    if p is None or p.strip() in ["", "MIDPLANE"]:
103
                        # Found in WS-C4500X-32 and WS-C4900M
104
105
                        p = self.snmp.get(mib["ENTITY-MIB::entPhysicalModelName", 1000])
                        s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 1000])
106
107
                        if p is None:
                            # Found on C2600 series
108
109
                            p = self.snmp.get(mib["ENTITY-MIB::entPhysicalDescr", 1])
                            s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 1])
110
                    elif not s:
111
                        s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 1])
112
113
114
115
                    if p in ["Catalyst 37xx Switch Stack", "Catalyst C29xx Switch Stack"]:
                        # Found on 37xx and C29xx
                        p = self.snmp.get(mib["ENTITY-MIB::entPhysicalDescr", 2001])
                        s = self.snmp.get(mib["ENTITY-MIB::entPhysicalSerialNum", 2001])
116
                    if p:
117
                        p = p.strip()  # Cisco 3845 return 'CISCO3845         '
118
119
120
121
                        if p.startswith("CISCO"):
                            p = p[5:]
                        if p.endswith("-CHASSIS"):
                            p = p[:-8]
122
123
124
125
                        # '2651XM chassis, Hw Serial#: 2297211811, Hw Revision: 0x301'
                        match1 = self.rx_old_platform.search(p)
                        if match1:
                            p = match1.group("platform")
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
                        platform = p
            version = match.group("version")
            # WS-C4500X-32 do not have ',' in version string
            n = version.find(" RELEASE SOFTWARE")
            if n > 0:
                version = version[:n]
            if not self.rx_invalid_platforms.search(platform):
                r = {
                    "vendor": "Cisco",
                    "platform": self.clear_platform(platform),
                    "version": version,
                    "image": match.group("image"),
                }
                if s:
                    r["attributes"] = {}
                    r["attributes"]["Serial Number"] = s
                return r

    def execute_cli(self, **kwargs):
145
146
147
148
        c = ""
        try:
            v = self.cli("show inventory raw")
            i = 0
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
149
            serial = None
150
151
152
153
154
155
156
157
158
            for match in self.rx_item.finditer(v):
                name = match.group("name")
                pid = match.group("pid")
                if pid is None:
                    pid = ""
                descr = match.group("descr")
                if name in self.IGNORED_NAMES:
                    continue
                if (
Dmitry Volodin's avatar
Dmitry Volodin committed
159
160
161
162
163
164
165
                    (i == 0 or pid.startswith("CISCO") or pid.startswith("WS-C"))
                    and not pid.startswith("WS-CAC-")
                    and not pid.endswith("-MB")
                    and "Clock" not in descr
                    and "VTT FRU" not in descr
                    and "C2801 Motherboard " not in descr
                    and "xx Switch Stack" not in descr
166
167
168
169
                ):
                    if pid in ("", "N/A"):
                        if self.rx_7100.search(descr):
                            pid = "CISCO7100"
170
171
172
173
                    if pid == "MIDPLANE" and name == "Switch System":
                        match1 = self.rx_c4900m.search(descr)
                        if match1:
                            pid = match1.group("part_no")
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
174
175
                    if pid.startswith("CISCO"):
                        pid = pid[5:]
176
177
178
179
                    platform = pid
                    serial = match.group("serial")
                    break
                i = 1
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
180
181
            if serial in self.IGNORED_SERIAL:
                serial = None
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
        except self.CLISyntaxError:
            c = self.cli("show version", cached=True)
            match = self.rx_ver.search(c)
            if match:
                platform = match.group("part_no")
                serial = match.group("serial")
            else:
                match = self.rx_ver1.search(c)
                if match:
                    platform = match.group("part_no")
                    serial = None
                else:
                    raise self.NotSupportedError()
        if c == "":
            c = self.cli("show version", cached=True)
        match = self.rx_version.search(c)
        if not platform:
            platform = match.group("platform")
200
        if self.rx_invalid_platforms.search(platform):
201
            # Process IOS XE platform
202
203
204
205
206
207
208
209
210
            match1 = self.rx_platform.search(c)
            if match1:
                platform = match1.group("platform")
        version = match.group("version")
        # WS-C4500X-32 do not have ',' in version string
        n = version.find(" RELEASE SOFTWARE")
        if n > 0:
            version = version[:n]
        r = {
Dmitry Lukhtionov's avatar
Dmitry Lukhtionov committed
211
            "vendor": "Cisco",
212
            "platform": self.clear_platform(platform),
213
            "version": version,
214
            "image": match.group("image"),
Dmitry Volodin's avatar
Dmitry Volodin committed
215
        }
216
217
218
219
        if bool(serial):
            r["attributes"] = {}
            r["attributes"]["Serial Number"] = serial
        return r