Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add SNMP Monitor #4717

Open
wants to merge 63 commits into
base: master
Choose a base branch
from
Open

feat: Add SNMP Monitor #4717

wants to merge 63 commits into from

Conversation

mattv8
Copy link

@mattv8 mattv8 commented Apr 27, 2024

Tick the checkbox if you understand [x]:

  • I have read and understand the pull request rules.

Description (Updated 06 June 2024 to reflect new scope)

This PR introduces a new SNMP monitor type and extends the functionality of JSON query monitoring with additional comparison operators. The following changes have been made:

Uptime Kuma Core

  • Broke out the JSON query evaluation logic into a new utility function for better reusability and clarity, called evaluateJsonQuery(data: any, jsonPath: string, jsonPathOperator: string, expectedValue: any), which returns { status: boolean, response: any } where status is the UP/DOWN evaluation and response is the result of the JSON query evaluation.

New SNMP Monitor Type:

  • Added new fields for SNMP configuration, including community string, OID (Object Identifier), and SNMP version.
  • Updated the database schema to include SNMP-related columns.
  • Utilizes new evaluateJsonQuery() to determine monitor status based on SNMP values and configured conditions.
  • Utilizes net-snmp library for SNMP queries.

JSON Query Monitoring:

  • Utilizes new evaluateJsonQuery() to determine monitor status based on JSON query evaluation and configured conditions.
  • Extended the UI to allow users to select the desired comparison operator (==, !=, <, <=, >, >=).
  • Introduced a new property in the monitoring configuration to hold the comparison operator.
  • Ensured backward compatibility by defaulting to == if the operator is not specified in existing configurations.

Resolves #1675
Resolves #4715
Resolves #4614
Resolves #4617

Type of change

Please delete any options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Checklist

  • My code follows the style guidelines of this project
  • I ran ESLint and other linters for modified files
  • I have performed a self-review of my own code and tested it
  • I have commented my code, particularly in hard-to-understand areas (including JSDoc for methods)
  • My changes generates no new warnings
  • My code needed automated testing. I have added them (this is optional task)

Screenshots

image

This commit introduces a new SNMP monitor feature to the application, allowing users to monitor devices using SNMP (Simple Network Management Protocol).
@mattv8 mattv8 mentioned this pull request Apr 27, 2024
1 task
@mattv8 mattv8 changed the title feat: Add SNMP Monitor feat: Add SNMP Monitor (WIP) Apr 27, 2024
net-snmp over snmp-native is:
-more robust
-more popular
-better documented
-supports v3
Further testing of SNMP feat, however I'm running into the issue `Error in SNMP check: RequestTimedOutError: Request timed out` when the check function is called. I am unsure as to why since my local SNMP script works great with very similar code.
@mattv8

This comment has been minimized.

@CommanderStorm

This comment has been minimized.

Thanks for pointing it out @CommanderStorm!
@mattv8

This comment was marked as resolved.

@CommanderStorm

This comment was marked as resolved.

@mattv8

This comment was marked as resolved.

@CommanderStorm

This comment was marked as resolved.

DB must allow nulls otherwise this will break other monitors.
knex requires down function
Updates appropriate values async when editing the SNMP monitor
@mattv8 mattv8 changed the title feat: Add SNMP Monitor (WIP) feat: Add SNMP Monitor Apr 30, 2024
@mattv8 mattv8 marked this pull request as ready for review April 30, 2024 21:46
@mattv8
Copy link
Author

mattv8 commented Apr 30, 2024

@CommanderStorm I'm ready for review. It is not passing ES Lint, although when I run npm run lint:prod --fix there are some changes to server/model/monitor.js that are unrelated to this PR. I'm unsure as how to proceed on the linting side of things.

CommanderStorm

This comment was marked as resolved.

@github-actions github-actions bot added needs:resolve-merge-conflict A merge-conflict needs to be addressed before reviewing makes sense again and removed needs:resolve-merge-conflict A merge-conflict needs to be addressed before reviewing makes sense again labels May 23, 2024
@chakflying
Copy link
Collaborator

  • The idea behind my suggestion of using json-query for value comparisons, is that it can provide the maximum freedom for users to process and transform the input data before comparison.
  • If all we are using the library for is running a few preset queries, we are not providing that freedom to the user. Then we may as well have not used the library.
  • However, I also see that there is benefit in being able to set a custom condition/comparison operator other than ==, since it can simplify the expression in complicated cases. (Basically the idea in feat: extend monitor JSON data evaluation operators #4617)

My ideal implementation would be like this:

  • We reuse existing database columns json_path and expected_value, instead of creating new one snmpControlValue
  • We name the new column for the comparison operator json_path_operator instead of the current snmp_condition (as it was in feat: extend monitor JSON data evaluation operators #4617)
  • Optionally, we can default json_path to $.value for people who do not require any transformation.
  • When the monitor runs its check,
    • we obtain the value from SNMP as it's currently done: const value = varbinds[0].value;
    • we evaluate this value according to user's inputted json_path:
         let expression = jsonata(this.jsonPath);
         let result = await expression.evaluate(value);
      
    • We compare result with expected_value using the user's chosen operator (==, >=, etc)
    • This comparison produces a true/false result which will determine the monitor status

This implementation would be maximally compatible with the existing json-query monitor, and have the benefit that the user has much more freedom, e.g. can quickly check if the SNMP value is odd by doing $.value % 2 != 0 (I think).

I really appreciate the work that you have put into this feature, it looks great already. I don't want this to be like "great, but here's more work for you". It's difficult to reach an ideal solution when we all have different ideas of how it would look like. I'm also not in a good position to comment since I don't have an SNMP device to test. Feel free to discuss if needed.

@chakflying
Copy link
Collaborator

BTW, if we are reusing radiusPassword for the storing the community string, then I guess a new database column for that is also not needed anymore?

@mattv8
Copy link
Author

mattv8 commented May 28, 2024

Hey @chakflying I appreciate your thoughts on all this! Currently on mobile and on vacation, so forgive this for being brief. I'll jump back into this in a week or so when I'm back in town and solid internet.

Yes, what you're describing I feel is absolutely workable. I think we need to walk the line between absolute freedom of an open text input for json-queries and the simplicity of the comparison drop down. Let me work through this and see what I can come up with!

@mattv8

This comment was marked as outdated.

-Reuse expected_value for snmpControlValue
-Create jsonPathOperator for snmpCondition
Utilizes the JSON Query library to handle comparison logic.
@mattv8
Copy link
Author

mattv8 commented Jun 5, 2024

I realize I've now pushed a lot of change all at once and @CommanderStorm might not like it (understandably 😉), but I've retooled the SNMP monitor to use json-query based logic, and I've also created a new utility function that includes conditionals, and re-worked the HTTP(s) - JSON Query monitor, effectively implementing the desired outcome of #4617. Lemme know what you two think once you've had the chance to take a look. I've tested SNMP with it, I'll create a server with a JSON response and test that as well.

@qu4cks4lb3r I'd be curious to see if this meets your expectations for the conditionals in the json-query monitor, and perhaps you could help test.

-This is less abstract
-Maximum compatibility with @chakflying's existing json-query monitor code.
-Maximum compatibility with @chakflying's existing json-query monitor code.
There are a lot of changes here:
-Fixed a lot of issues encountered during my testing
-JSON path is evaluated BEFORE making comparisons (this was the true intended behavior by @chakflying)
-Variable name changes (cosmetic)
-Added != operator
-Changed jsonQueryDescription (again)
@mattv8
Copy link
Author

mattv8 commented Jun 7, 2024

Had some more time today to dive into this and more thoroughly test my feat against an HTTP(s) Json response. I made a few more commits (with lots of changes) to address the issues I encountered. I'm going to let the code settle for a bit now and hopefully folks will get a chance to review.

Admittedly I went a little overboard and there's a bit of scope change now from the original SNMP monitor. I hope this is acceptable. I'll remain open-minded and if we want to dial it back, let me know. If we need to break this into two PR's; one addressing #4617 and one adding the SNMP monitor I'm fine with that. As it stands, this PR now combines the two feats.

@github-actions github-actions bot removed the needs:resolve-merge-conflict A merge-conflict needs to be addressed before reviewing makes sense again label Jun 12, 2024
Copy link
Collaborator

@CommanderStorm CommanderStorm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

@chakflying would like a review from your side as well ^^

src/pages/EditMonitor.vue Outdated Show resolved Hide resolved
<label for="hostname" class="form-label">{{ $t("Hostname") }}</label>
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping / SNMP only -->
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping' || monitor.type === 'snmp'" class="my-3">
<label for="hostname" class="form-label">{{ $t("Hostname or IP Address") }}</label>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I don't think this translation does make sense for every monitor here.
F.ex. we currently don't support IP-adresses for the dns monitor.

Likely does not matter in the real world.

Copy link
Author

@mattv8 mattv8 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably best for me to put it back to simply "Hostname" to limit number of potentially disruptive frontend changes from this PR. My intention was to avoid potential confusion from people not realizing it is also an "IP address" field. Very rarely would one use a hostname for SNMP (IMHO).

server/model/monitor.js Outdated Show resolved Hide resolved
server/monitor-types/snmp.js Outdated Show resolved Hide resolved
server/monitor-types/snmp.js Outdated Show resolved Hide resolved
server/monitor-types/snmp.js Outdated Show resolved Hide resolved
response // The response from the server or result from initial json-query evaluation
};
} catch (err: any) {
throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

response in this context may quite large.
If we just print it to the console, this could DOS the server => please at most print a truncated version.

Alternatively, just returning the error is likely fine too.

Copy link
Author

@mattv8 mattv8 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the potential for this issue in my own testing and wrote truncation code that was a bit clunky so I didn't commit it yet. Let me adjust and see what I can come up with.

@@ -588,7 +588,7 @@
"notificationDescription": "Notifications must be assigned to a monitor to function.",
"keywordDescription": "Search keyword in plain HTML or JSON response. The search is case-sensitive.",
"invertKeywordDescription": "Look for the keyword to be absent rather than present.",
"jsonQueryDescription": "Do a json Query against the response and check for expected value (Return value will get converted into string for comparison). Check out {0} for the documentation about the query language. A playground can be found {1}.",
"jsonQueryDescription": "Parse and extract specific data from the server's JSON response using JSON query or use \"$\" for the raw response, if not expecting JSON. The result is then compared to the expected value, as strings. See {0} for documentation and use {1} to experiment with queries.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to remove the other translations.
This is a significantly different (read: better) message and needs to be re-translated anyway.

Copy link
Author

@mattv8 mattv8 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll remove the other translations for this PR, and commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:monitor Everything related to monitors needs:review this PR needs a review by maintainers or other community members
Projects
None yet
3 participants