Commit 6c77d49f authored by Jan Koester's avatar Jan Koester
Browse files

test

parent 86c24cc0
Loading
Loading
Loading
Loading
+29 −6
Changes for modules/snmp/snmp.cpp: 29 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -33,11 +33,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *       settings: enabled, interval, events, report{raid, lvm,
 *           filesystems, disks, smart_attributes, services}, fsWarning,
 *           fsCritical, tempWarning, tempCritical,
 *           services[], targets[{host, port, version, community}],
 *           enterprise (read only)
 *           services[], targets[{host, port, version, community (1, 2c);
 *           user, level, auth, authPasswordSet, priv, privPasswordSet
 *           (3)}], enterprise, engineId (read only)
 *       status: lastReport, nextReport (unix time, 0: never/off), sent,
 *           status, problems[], targets[{target, sent, error}]
 *   save {settings}     replaces them all (as above, without enterprise)
 *           status, engineId, engineBoots, problems[],
 *           targets[{target, sent, error}]
 *   save {settings}     replaces them all (as above, without enterprise and
 *                       engineId; version 3: authPassword, privPassword --
 *                       empty keeps the target's current one)
 *   send                a report now -> {sent}
 */

@@ -90,13 +94,20 @@ json_object *settingsJson(const sysbus::Message &r) {
        else if (k.compare(0, 7, "report_") == 0)
            json_object_object_add(report, k.c_str() + 7, json_object_new_boolean(v == "yes"));
        else if (k == "enterprise") json_object_object_add(o, "enterprise", jstr(v));
        else if (k == "engine_id") json_object_object_add(o, "engineId", jstr(v));
        else if (k == "service") json_object_array_add(services, jstr(v));
        else if (k == "target") {
            target = json_object_new_object();
            json_object_array_add(targets, target);
            json_object_object_add(target, "host", jstr(v));
        } else if (target && k == "port") json_object_object_add(target, "port", json_object_new_int64(num(v)));
        else if (target && (k == "version" || k == "community")) json_object_object_add(target, k.c_str(), jstr(v));
        else if (target && (k == "version" || k == "community" || k == "user" || k == "level" || k == "auth" ||
                            k == "priv"))
            json_object_object_add(target, k.c_str(), jstr(v));
        else if (target && k == "auth_password_set")
            json_object_object_add(target, "authPasswordSet", json_object_new_boolean(v == "yes"));
        else if (target && k == "priv_password_set")
            json_object_object_add(target, "privPasswordSet", json_object_new_boolean(v == "yes"));
    }
    json_object_object_add(o, "report", report);
    json_object_object_add(o, "services", services);
@@ -120,6 +131,8 @@ json_object *statusJson(const sysbus::Message &r) {
        else if (k == "next_report") json_object_object_add(o, "nextReport", json_object_new_int64(num(v)));
        else if (k == "sent") json_object_object_add(o, "sent", json_object_new_int64(num(v)));
        else if (k == "status") json_object_object_add(o, "status", jstr(v));
        else if (k == "engine_id") json_object_object_add(o, "engineId", jstr(v));
        else if (k == "engine_boots") json_object_object_add(o, "engineBoots", json_object_new_int64(num(v)));
        else if (k == "problem") json_object_array_add(problems, jstr(v));
    }
    json_object_object_add(o, "problems", problems);
@@ -158,8 +171,18 @@ std::string settingsFields(json_object *s, Fields &out) {
            if (!t || !json_object_is_type(t, json_type_object)) return tr("invalid target", "ungültiges Ziel");
            out.emplace_back("target", webctl::str(t, "host"));
            out.emplace_back("port", std::to_string(webctl::integer(t, "port", 162)));
            out.emplace_back("version", webctl::str(t, "version", "2c"));
            std::string version = webctl::str(t, "version", "2c");
            out.emplace_back("version", version);
            if (version != "3") {
                out.emplace_back("community", webctl::str(t, "community"));
                continue;
            }
            out.emplace_back("user", webctl::str(t, "user"));
            out.emplace_back("level", webctl::str(t, "level", "authPriv"));
            out.emplace_back("auth", webctl::str(t, "auth", "SHA-256"));
            out.emplace_back("auth_password", webctl::str(t, "authPassword"));
            out.emplace_back("priv", webctl::str(t, "priv", "AES"));
            out.emplace_back("priv_password", webctl::str(t, "privPassword"));
        }
    }
    return "";
+80 −10
Changes for www/modules/snmp.js: 80 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -12,6 +12,19 @@
    'ok': 'ok', 'warning': 'Warnung', 'critical': 'kritisch', 'unknown': 'unbekannt',
    'Targets (NMS)': 'Ziele (NMS)', 'Add target': 'Ziel hinzufügen', 'Host': 'Host', 'Port': 'Port',
    'Version': 'Version', 'Community': 'Community', 'Sent': 'Gesendet', 'Error': 'Fehler',
    'Security': 'Sicherheit', 'clear text': 'Klartext', 'unchanged': 'unverändert',
    'at least 8 characters': 'mindestens 8 Zeichen', 'User': 'Benutzer', 'Security level': 'Sicherheitsstufe',
    'Authentication and encryption': 'Authentifizierung und Verschlüsselung',
    'Authentication only': 'Nur Authentifizierung', 'Neither (not recommended)': 'Keine (nicht empfohlen)',
    'Authentication': 'Authentifizierung', 'Authentication password': 'Authentifizierungs-Passwort',
    'Encryption': 'Verschlüsselung', 'Encryption password': 'Verschlüsselungs-Passwort',
    'AES-256 needs SHA-256 or SHA-384.': 'AES-256 braucht SHA-256 oder SHA-384.',
    'SNMPv1 and v2c send the community and everything else in clear text.':
      'SNMPv1 und v2c senden die Community und alles andere im Klartext.',
    'SNMPv3 engine ID': 'SNMPv3-Engine-ID', '(boots {0})': '(Starts {0})',
    'SNMPv3: the NMS knows each user under the engine ID of snmpdd, e.g. in snmptrapd.conf:':
      'SNMPv3: Das NMS kennt jeden Benutzer unter der Engine-ID von snmpdd, z. B. in snmptrapd.conf:',
    'user': 'Benutzer', 'password': 'Passwort',
    'Edit': 'Bearbeiten', 'Remove': 'Entfernen', 'No targets yet.': 'Noch keine Ziele.',
    'Target {0}': 'Ziel {0}', 'New target': 'Neues Ziel', 'Add': 'Hinzufügen',
    'Host name or IP address of the network management station.': 'Hostname oder IP-Adresse der Network-Management-Station.',
@@ -55,6 +68,7 @@
  async function save(changes, success) {
    const s = {...data.settings, ...changes};
    delete s.enterprise;
    delete s.engineId;
    await call('snmp', 'save', {settings: s});
    toast(success);
    load();
@@ -110,22 +124,62 @@

  function targetDialog(index) {
    const old = index >= 0 ? data.settings.targets[index] : null;
    const tg = old || {host: '', port: 162, version: '2c', community: 'public'};
    const tg = {host: '', port: 162, version: '3', community: 'public', user: '', level: 'authPriv',
                auth: 'SHA-256', priv: 'AES', ...(old || {})};
    const select = (name, values, value, labels) => h('select', {name},
      values.map((v, i) => h('option', {value: v, selected: v === value}, labels ? labels[i] : v)));
    // a password that is set stays unless something is typed in
    const password = (name, isSet) => h('input', {name, type: 'password', autocomplete: 'new-password', maxlength: 255,
      placeholder: isSet ? t('unchanged') : t('at least 8 characters')});
    dialog({
      title: old ? t('Target {0}', old.host) : t('New target'), submit: old ? undefined : t('Add'),
      fields: () => [
      fields: () => {
        const community = h('div', {},
          h('label', {}, t('Community'), h('input', {name: 'community', value: tg.community, maxlength: 255})),
          h('p', {class: 'hint'}, t('SNMPv1 and v2c send the community and everything else in clear text.')));
        const authBox = h('div', {class: 'row'},
          h('label', {}, t('Authentication'), select('auth', ['SHA', 'SHA-256', 'SHA-384'], tg.auth,
                                                    ['SHA-1', 'SHA-256', 'SHA-384'])),
          h('label', {}, t('Authentication password'), password('authPassword', old && old.authPasswordSet)));
        const privBox = h('div', {class: 'row'},
          h('label', {}, t('Encryption'), select('priv', ['AES', 'AES-256'], tg.priv, ['AES-128', 'AES-256'])),
          h('label', {}, t('Encryption password'), password('privPassword', old && old.privPasswordSet)));
        const level = select('level', ['authPriv', 'authNoPriv', 'noAuthNoPriv'], tg.level,
          [t('Authentication and encryption'), t('Authentication only'), t('Neither (not recommended)')]);
        const v3 = h('div', {},
          h('div', {class: 'row'},
            h('label', {}, t('User'), h('input', {name: 'user', value: tg.user, maxlength: 32})),
            h('label', {}, t('Security level'), level)),
          authBox, privBox,
          h('p', {class: 'hint'}, t('AES-256 needs SHA-256 or SHA-384.')));
        const version = select('version', ['3', '2c', '1'], tg.version, ['SNMPv3', 'SNMPv2c', 'SNMPv1']);
        const update = () => {
          const is3 = version.value === '3';
          community.hidden = is3;
          v3.hidden = !is3;
          authBox.hidden = level.value === 'noAuthNoPriv';
          privBox.hidden = level.value !== 'authPriv';
        };
        version.addEventListener('change', update);
        level.addEventListener('change', update);
        update();
        return [
          h('div', {class: 'row'},
            h('label', {}, t('Host'), h('input', {name: 'host', value: tg.host, required: true})),
            h('label', {}, t('Port'), h('input', {name: 'port', type: 'number', min: 1, max: 65535, value: tg.port, required: true}))),
          h('p', {class: 'hint'}, t('Host name or IP address of the network management station.')),
        h('div', {class: 'row'},
          h('label', {}, t('Version'), h('select', {name: 'version'},
            ['2c', '1'].map(v => h('option', {value: v, selected: v === tg.version}, 'SNMPv' + v)))),
          h('label', {}, t('Community'), h('input', {name: 'community', value: tg.community, required: true, maxlength: 255}))),
      ],
          h('label', {}, t('Version'), version),
          community, v3,
        ];
      },
      onSubmit: d => {
        const targets = [...data.settings.targets];
        const n = {host: d.host.trim(), port: Number(d.port), version: d.version, community: d.community};
        const n = {host: d.host.trim(), port: Number(d.port), version: d.version};
        if (d.version === '3')
          Object.assign(n, {user: d.user.trim(), level: d.level, auth: d.auth, priv: d.priv,
                            authPassword: d.authPassword, privPassword: d.privPassword});
        else
          n.community = d.community;
        if (old) targets[index] = n;
        else targets.push(n);
        return save({targets}, t('Target saved.'));
@@ -149,6 +203,17 @@
    load();
  }

  const levelText = {authPriv: 'authPriv', authNoPriv: 'authNoPriv', noAuthNoPriv: 'noAuthNoPriv'};

  function security(tg) {
    if (tg.version !== '3')
      return [h('span', {class: 'badge warn'}, t('clear text')), ' ', h('span', {class: 'mono'}, tg.community)];
    const strong = tg.level === 'authPriv';
    return [h('span', {class: 'badge ' + (strong ? 'ok' : 'warn')}, levelText[tg.level] || tg.level), ' ',
            h('span', {class: 'mono'}, tg.user),
            tg.level !== 'noAuthNoPriv' ? h('span', {class: 'muted'}, ' ' + [tg.auth, strong ? tg.priv : null].filter(Boolean).join(' / ')) : null];
  }

  function draw() {
    const s = data.settings, st = data.status;
    const row = (label, value) => h('tr', {}, h('th', {}, label), h('td', {}, value));
@@ -170,7 +235,9 @@
          row(t('Status'), st.lastReport ? badge(st.status) : '–'),
          st.problems.length ? row(t('Not collected'), st.problems.join('; ')) : null,
          row(t('Notifications sent'), String(st.sent || 0)),
          row(t('Enterprise OID'), h('span', {class: 'mono'}, s.enterprise || '')))))),
          row(t('Enterprise OID'), h('span', {class: 'mono'}, s.enterprise || '')),
          row(t('SNMPv3 engine ID'), [h('span', {class: 'mono'}, '0x' + (s.engineId || '')),
                                      st.engineBoots ? h('span', {class: 'muted'}, ' ' + t('(boots {0})', st.engineBoots)) : null]))))),
      h('section', {class: 'panel'},
        h('div', {class: 'toolbar'},
          h('h2', {}, t('Targets (NMS)')),
@@ -179,7 +246,7 @@
          {title: t('Host'), render: tg => h('strong', {}, tg.host)},
          {title: t('Port'), render: tg => tg.port, class: 'mono'},
          {title: t('Version'), render: tg => 'SNMPv' + tg.version},
          {title: t('Community'), render: tg => h('span', {class: 'mono'}, tg.community)},
          {title: t('Security'), render: security},
          {title: t('Sent'), render: tg => String((st.targets.find(x => x.target === key(tg)) || {}).sent || 0)},
          {title: t('Error'), render: tg => {
            const e = (st.targets.find(x => x.target === key(tg)) || {}).error;
@@ -191,6 +258,9 @@
                    h('button', {class: 'small danger', onclick: () => removeTarget(i)}, t('Remove'))];
          }},
        ], s.targets, t('No targets yet.')),
        h('p', {class: 'hint'}, t('SNMPv3: the NMS knows each user under the engine ID of snmpdd, e.g. in snmptrapd.conf:')),
        h('pre', {class: 'log'}, 'createUser -e 0x' + (s.engineId || '…') + ' <' + t('user') + '> SHA-256 <' +
                                  t('password') + '> AES <' + t('password') + '>'),
        h('p', {class: 'hint'}, t('SNMPDD-MIB describes the notifications (/usr/share/snmp/mibs/SNMPDD-MIB.txt); load it into the NMS.'))));
  }