From 4f88b098cba2c5b41730ff5867f79fc6cc12fa52 Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Thu, 2 Jun 2022 21:46:08 +0200
Subject: [PATCH] update project

---
 agent_based/inv_juniper_hw_modules.py       | 150 ++++++++++++++++++++
 inv_juniper_hw_modules.mkp                  | Bin 0 -> 2921 bytes
 packages/inv_juniper_hw_modules             |  13 ++
 web/plugins/views/inv_juniper_hw_modules.py |  33 +++++
 web/plugins/wato/inv_juniper_hw_modules.py  |  63 ++++++++
 5 files changed, 259 insertions(+)
 create mode 100644 agent_based/inv_juniper_hw_modules.py
 create mode 100644 inv_juniper_hw_modules.mkp
 create mode 100644 packages/inv_juniper_hw_modules
 create mode 100644 web/plugins/views/inv_juniper_hw_modules.py
 create mode 100644 web/plugins/wato/inv_juniper_hw_modules.py

diff --git a/agent_based/inv_juniper_hw_modules.py b/agent_based/inv_juniper_hw_modules.py
new file mode 100644
index 0000000..8b6ad2e
--- /dev/null
+++ b/agent_based/inv_juniper_hw_modules.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2022-06-02
+#
+# inventory of juniper hardware modules
+#
+
+
+import time
+from typing import List, NamedTuple, Optional, Dict
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    StringTable,
+    InventoryResult,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    SNMPTree,
+    TableRow,
+    startswith,
+)
+
+
+def parse_inv_juniper_hw_modules(string_table: List[StringTable]) -> List[Dict]:
+    modules = []
+
+    jnx_contents_entry, jnx_box_anatomy, sys_uptime = string_table
+    sys_uptime = int(sys_uptime[0][0]) / 100  # change to seconds
+    # first entry in jnx_contents_entry is the chassis without data (?)
+    if jnx_contents_entry[0][5:9] == ['', '', '', '0']:
+        box_class, box_descr, box_serial_no, box_revision, box_installed = jnx_box_anatomy[0]
+        jnx_contents_entry[0][5] = box_descr
+        jnx_contents_entry[0][6] = box_serial_no
+        jnx_contents_entry[0][7] = box_revision
+        jnx_contents_entry[0][8] = box_installed
+
+    for container_index, l1_index, l2_index, l3_index, type_oid, descr, serial_no, revision, installed, part_no, \
+        chassis_id, chassis_descr, chassis_clei_code, model in jnx_contents_entry:
+
+        index = f'{container_index}.{l1_index}.{l2_index}.{l3_index}'
+        installed = time.ctime(time.time() - sys_uptime + (int(installed))) if installed != '0' else None
+
+        module = {}
+        for key, value in [
+            ('index', index),
+            ('description', descr),
+            ('type', type_oid),
+            ('serial_number', serial_no),
+            ('revision', revision),
+            # ('installed_at', installed),
+            ('part_no', part_no),
+            ('chassis_id', chassis_id),
+            ('chassis_descr', chassis_descr),
+            ('chassis_clei_code', chassis_clei_code),
+            ('model', model),
+        ]:
+            if value:
+                module.update({key: value})
+
+        modules.append(module)
+
+    return modules
+
+
+def inventory_hw_modules(params, section: List[Dict]) -> InventoryResult:
+    removecolumns = params.get('removecolumns', [])
+    allparts = params.get('allparts', False)
+
+    path = ['hardware', 'juniper-hw-modules']
+
+    for module in section:
+        # do not add parts without serial number
+        if allparts is False and module.get('serial_number', None) is None:
+            continue
+
+        key_columns = {'index': module['index']}
+        for key in key_columns.keys():
+            module.pop(key)
+
+        for entry in removecolumns:
+            try:
+                module.pop(entry)
+            except KeyError:
+                pass
+
+        yield TableRow(
+            path=path,
+            key_columns=key_columns,
+            inventory_columns=module
+        )
+
+
+register.snmp_section(
+    name='inv_juniper_hw_modules',
+    parse_function=parse_inv_juniper_hw_modules,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.2636.3.1.8.1',  # JUNIPER-MIB::jnxContentsEntry
+            oids=[
+                '1',  # jnxContentsContainerIndex
+                '2',  # jnxContentsL1Index
+                '3',  # jnxContentsL2Index
+                '4',  # jnxContentsL3Index
+                '5',  # jnxContentsType
+                '6',  # jnxContentsDescr
+                '7',  # jnxContentsSerialNo
+                '8',  # jnxContentsRevision
+                '9',  # jnxContentsInstalled
+                '10',  # jnxContentsPartNo
+                '11',  # jnxContentsChassisId
+                '12',  # jnxContentsChassisDescr
+                '13',  # jnxContentsChassisCleiCode
+                '14',  # jnxContentsModel
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.4.1.2636.3.1',  # UNIPER-MIB::jnxBoxAnatomy
+            oids=[
+                '1',  # jnxBoxClass
+                '2',  # jnxBoxDescr
+                '3',  # jnxBoxSerialNo
+                '4',  # jnxBoxRevision
+                '5',  # jnxBoxInstalled
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.2.1.1',  # SNMPv2-MIB::system
+            oids=[
+                '3',  # sysUpTime
+            ]
+        )
+    ],
+    detect=startswith('.1.3.6.1.2.1.1.2.0', '.1.3.6.1.4.1.2636.1.1.1'),
+)
+
+register.inventory_plugin(
+    name='inv_juniper_hw_modules',
+    inventory_function=inventory_hw_modules,
+    inventory_default_parameters={
+        'removecolumns': [],
+        'allparts': False,
+    },
+    inventory_ruleset_name='inv_juniper_hw_modules',
+)
diff --git a/inv_juniper_hw_modules.mkp b/inv_juniper_hw_modules.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..395b174af71436112eb6d6ff4ba5a7a6eb64816d
GIT binary patch
literal 2921
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
IfZw?BKR_<95&!@I

literal 0
HcmV?d00001

diff --git a/packages/inv_juniper_hw_modules b/packages/inv_juniper_hw_modules
new file mode 100644
index 0000000..7f722a6
--- /dev/null
+++ b/packages/inv_juniper_hw_modules
@@ -0,0 +1,13 @@
+{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)',
+ 'description': 'Inventory of Juniper networks hardware modules\n',
+ 'download_url': 'https://thl-cmk.hopto.org',
+ 'files': {'agent_based': ['inv_juniper_hw_modules.py'],
+           'web': ['plugins/views/inv_juniper_hw_modules.py',
+                   'plugins/wato/inv_juniper_hw_modules.py']},
+ 'name': 'inv_juniper_hw_modules',
+ 'num_files': 3,
+ 'title': 'Juniper networks hardware inventory',
+ 'version': '20220602.v.0.01',
+ 'version.min_required': '2.0.0',
+ 'version.packaged': '2021.09.20',
+ 'version.usable_until': None}
\ No newline at end of file
diff --git a/web/plugins/views/inv_juniper_hw_modules.py b/web/plugins/views/inv_juniper_hw_modules.py
new file mode 100644
index 0000000..9a7daa9
--- /dev/null
+++ b/web/plugins/views/inv_juniper_hw_modules.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# import cmk.gui.utils
+from cmk.gui.plugins.views import (
+    inventory_displayhints, )
+from cmk.gui.i18n import _
+from cmk.gui.plugins.views.inventory import declare_invtable_view
+
+inventory_displayhints.update({
+    '.hardware.juniper-hw-modules:': {'title': _('Modules'),
+                                      'keyorder': ['index', 'description', 'serial_number', 'revision', 'part_no', ],
+                                      'view': 'invmodules_of_host',
+                                      },
+    '.hardware.juniper-hw-modules:*.index': {'title': _('Index'), },
+    '.hardware.juniper-hw-modules:*.serial_number': {'title': _('Serial number')},
+    '.hardware.juniper-hw-modules:*.description': {'title': _('Description')},
+    '.hardware.juniper-hw-modules:*.revision': {'title': _('Revision'), },
+    '.hardware.juniper-hw-modules:*.installed_at': {'title': _('Installed at'), },
+    '.hardware.juniper-hw-modules:*.part_no': {'title': _('Part No'), },
+    '.hardware.juniper-hw-modules:*.chassis_id': {'title': _('Chassis ID'), },
+    '.hardware.juniper-hw-modules:*.chassis_descr': {'title': _('Chassis description')},
+    '.hardware.juniper-hw-modules:*.chassis_clei_code': {'title': _('Chassis CLEI code'), },
+    '.hardware.juniper-hw-modules:*.model': {'title': _('Model'), },
+    '.hardware.juniper-hw-modules:*.type': {'title': _('Type (OID)'), },
+})
+
+declare_invtable_view(
+    'invmodules',
+    '.hardware.juniper-hw-modules:',
+    _('Juniper Hardware Modules'),
+    _('Juniper Hardware Modules')
+)
diff --git a/web/plugins/wato/inv_juniper_hw_modules.py b/web/plugins/wato/inv_juniper_hw_modules.py
new file mode 100644
index 0000000..1dd1865
--- /dev/null
+++ b/web/plugins/wato/inv_juniper_hw_modules.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+#
+
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato import (
+    HostRulespec,
+    rulespec_registry,
+    RulespecGroup,
+)
+from cmk.gui.valuespec import (
+    Dictionary,
+    FixedValue,
+    TextAscii,
+    ListChoice,
+)
+
+from cmk.gui.plugins.wato.inventory import (
+    RulespecGroupInventory,
+)
+
+_removecolumns = [
+    ('chassis_clei_code', 'Chassis CLEI code'),
+    ('chassis_descr', 'Chassis description'),
+    ('chassis_id', 'Chassis ID'),
+    # ('installed_at', 'Installed at'),
+    ('model', 'Model'),
+    ('type', 'Type (OID)'),
+]
+
+
+def _valuespec_inv_juniper_hw_modules():
+    return Dictionary(
+        title=_('Juniper hardware inventory'),
+        elements=[
+            ('allparts',
+             FixedValue(
+                 True,
+                 title=_('Inventory parts without serial number'),
+                 totext=_(''),
+                 default_value=False,
+             )),
+            ('removecolumns',
+             ListChoice(
+                 title=_('List of columns to remove'),
+                 help=_('information to remove from inventory'),
+                 choices=_removecolumns,
+                 default_value=[
+                 ],
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupInventory,
+        match_type="dict",
+        name="inv_parameters:inv_juniper_hw_modules",
+        valuespec=_valuespec_inv_juniper_hw_modules,
+    ))
-- 
GitLab