Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript
Tikhon Uskov, μηχανικός της ομάδας ολοκλήρωσης Zabbix

Το Zabbix είναι μια προσαρμόσιμη πλατφόρμα που χρησιμοποιείται για την παρακολούθηση κάθε είδους δεδομένων. Από τις πρώτες εκδόσεις του Zabbix, οι διαχειριστές παρακολούθησης είχαν τη δυνατότητα να εκτελούν διάφορα σενάρια μέσω Δράσεις για ελέγχους σε κόμβους δικτύου προορισμού. Ταυτόχρονα, η κυκλοφορία των σεναρίων οδήγησε σε μια σειρά από δυσκολίες, όπως η ανάγκη υποστήριξης σεναρίων, η παράδοσή τους σε κόμβους επικοινωνίας και proxies, καθώς και υποστήριξη για διαφορετικές εκδόσεις.

JavaScript για Zabbix

Τον Απρίλιο του 2019, παρουσιάστηκε το Zabbix 4.2 με προεπεξεργασία JavaScript. Πολλοί άνθρωποι ενθουσιάστηκαν με την ιδέα να εγκαταλείψουν τα σενάρια γραφής που μεταφέρουν δεδομένα κάπου, τα αφομοιώνουν και τα παρέχουν σε μια μορφή που κατανοεί το Zabbix και εκτελούν απλούς ελέγχους που θα λαμβάνουν δεδομένα που δεν είναι έτοιμα για αποθήκευση και επεξεργασία από το Zabbix, και στη συνέχεια επεξεργαστείτε αυτήν τη ροή δεδομένων χρησιμοποιώντας εργαλεία Zabbix και JavaScript. Σε συνδυασμό με την ανακάλυψη χαμηλού επιπέδου και τα εξαρτημένα στοιχεία που εμφανίστηκαν στο Zabbix 3.4, αποκτήσαμε μια αρκετά ευέλικτη ιδέα για την ταξινόμηση και τη διαχείριση των δεδομένων που λαμβάνονται.

Στο Zabbix 4.4, ως λογική συνέχεια της προεπεξεργασίας σε JavaScript, εμφανίστηκε μια νέα μέθοδος ειδοποίησης - το Webhook, η οποία μπορεί να χρησιμοποιηθεί για την εύκολη ενσωμάτωση των ειδοποιήσεων Zabbix με εφαρμογές τρίτων.

JavaScript και Duktapes

Γιατί επιλέχθηκαν τα JavaScript και Duktape; Εξετάστηκαν διάφορες επιλογές για γλώσσες και κινητήρες:

  • Λούα - Λούα 5.1
  • Lua - LuaJIT
  • Javascript - Duktape
  • Javascript - JerryScript
  • Ενσωματωμένη Python
  • Ενσωματωμένο Perl

Τα κύρια κριτήρια επιλογής ήταν η επικράτηση, η ευκολία ενσωμάτωσης του κινητήρα στο προϊόν, η χαμηλή κατανάλωση πόρων και η συνολική απόδοση του κινητήρα και η ασφάλεια εισαγωγής κώδικα σε αυτή τη γλώσσα στην παρακολούθηση. Με βάση τον συνδυασμό των δεικτών, η JavaScript κέρδισε στον κινητήρα Duktape.

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript

Κριτήρια επιλογής και δοκιμή απόδοσης

Χαρακτηριστικά του Duktape:

— Τυπικό ECMAScript E5/E5.1
— Ενότητες Zabbix για Duktape:

  • Zabbix.log() - σας επιτρέπει να γράφετε μηνύματα με διαφορετικά επίπεδα λεπτομέρειας απευθείας στο αρχείο καταγραφής διακομιστή Zabbix, γεγονός που καθιστά δυνατή τη συσχέτιση σφαλμάτων, για παράδειγμα, σε ένα Webhook, με την κατάσταση του διακομιστή.
  • CurlHttpRequest() - σας επιτρέπει να κάνετε αιτήματα HTTP στο δίκτυο, στο οποίο βασίζεται η χρήση του Webhook.
  • atob() και btoa() - σας επιτρέπει να κωδικοποιήσετε και να αποκωδικοποιήσετε συμβολοσειρές σε μορφή Base64.

Σημείωση. Το Duktape συμμορφώνεται με τα πρότυπα ACME. Το Zabbix χρησιμοποιεί την έκδοση του σεναρίου του 2015. Οι επόμενες αλλαγές είναι μικρές, επομένως μπορούν να αγνοηθούν..

Μαγεία JavaScript

Όλη η μαγεία της JavaScript έγκειται στη δυναμική πληκτρολόγηση και τη μετάδοση τύπων: συμβολοσειρά, αριθμητική και boolean.

Αυτό σημαίνει ότι δεν είναι απαραίτητο να δηλωθεί εκ των προτέρων ποιος τύπος θα πρέπει να επιστρέψει μια τιμή η μεταβλητή.

Στις μαθηματικές πράξεις, οι τιμές που επιστρέφονται από τους τελεστές συναρτήσεων μετατρέπονται σε αριθμούς. Η εξαίρεση σε τέτοιες πράξεις είναι η πρόσθεση, επειδή εάν τουλάχιστον ένας από τους όρους είναι συμβολοσειρά, η μετατροπή συμβολοσειράς εφαρμόζεται σε όλους τους όρους.

Σημείωση. Οι μέθοδοι που είναι υπεύθυνες για τέτοιους μετασχηματισμούς εφαρμόζονται συνήθως στα μητρικά πρωτότυπα του αντικειμένου, αξία του и toString. αξία του καλείται κατά την αριθμητική μετατροπή και πάντα πριν από τη μέθοδο toString. Μέθοδος αξία του πρέπει να επιστρέψει πρωτόγονες τιμές, διαφορετικά το αποτέλεσμά του αγνοείται.

Μια μέθοδος καλείται σε ένα αντικείμενο αξία του. Εάν δεν βρεθεί ή δεν επιστρέψει μια αρχική τιμή, καλείται η μέθοδος toString. Εάν η μέθοδος toString δεν βρέθηκε, ψάχνω αξία του στο πρωτότυπο του αντικειμένου και όλα επαναλαμβάνονται έως ότου ολοκληρωθεί η επεξεργασία της τιμής και όλες οι τιμές στην έκφραση μεταφέρονται στον ίδιο τύπο. Εάν το αντικείμενο υλοποιεί μια μέθοδο toString, που επιστρέφει μια πρωταρχική τιμή, τότε είναι αυτή που χρησιμοποιείται για τη μετατροπή συμβολοσειράς. Ωστόσο, το αποτέλεσμα της εφαρμογής αυτής της μεθόδου δεν είναι απαραίτητα μια συμβολοσειρά.

Για παράδειγμα, εάν για αντικείμενο "objορίζεται η μέθοδος toString,

`var obj = { toString() { return "200" }}` 

μέθοδος toString επιστρέφει ακριβώς μια συμβολοσειρά και όταν προσθέτουμε μια συμβολοσειρά με έναν αριθμό, παίρνουμε μια κολλημένη συμβολοσειρά:

`obj + 1 // '2001'` 

`obj + 'a' // ‘200a'`

Αν όμως ξαναγράψεις toString, ώστε η μέθοδος να επιστρέψει έναν αριθμό, όταν προστεθεί το αντικείμενο, θα εκτελεστεί μια μαθηματική πράξη με αριθμητική μετατροπή και θα προκύψει το αποτέλεσμα της μαθηματικής πρόσθεσης.

`var obj = { toString() { return 200 }}` 

`obj + 1 // '2001'`

Σε αυτή την περίπτωση, αν κάνουμε πρόσθεση με συμβολοσειρά, γίνεται μετατροπή συμβολοσειράς, και παίρνουμε μια κολλημένη χορδή.

`obj + 'a' // ‘200a'`

Αυτός είναι ο λόγος για έναν μεγάλο αριθμό λαθών από αρχάριους χρήστες JavaScript.

Η μέθοδος toString μπορείτε να γράψετε μια συνάρτηση που θα αυξήσει την τρέχουσα τιμή του αντικειμένου κατά 1.

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript
Εκτέλεση του σεναρίου, με την προϋπόθεση ότι η μεταβλητή είναι ίση με 3, και είναι επίσης ίση με 4.

Σε σύγκριση με ένα cast (==), η μέθοδος εκτελείται κάθε φορά toString με συνάρτηση αύξησης αξίας. Αντίστοιχα, με κάθε επόμενη σύγκριση, η τιμή αυξάνεται. Αυτό μπορεί να αποφευχθεί με τη χρήση σύγκρισης μη cast (===).

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript
Σύγκριση χωρίς χύτευση τύπου

Σημείωση. Μην χρησιμοποιείτε άσκοπα τη σύγκριση Cast.

Για πολύπλοκα σενάρια, όπως Webhooks με σύνθετη λογική, που απαιτούν σύγκριση με casting τύπου, συνιστάται η προεγγραφή ελέγχων για τις τιμές που επιστρέφουν μεταβλητές και χειρίζονται ασυνέπειες και σφάλματα.

Webhook Media

Στα τέλη του 2019 και στις αρχές του 2020, η ομάδα ενσωμάτωσης του Zabbix ανέπτυξε ενεργά Webhooks και ενσωματώσεις out-of-the-box που συνοδεύουν τη διανομή Zabbix.

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript
Σύνδεση με τεκμηρίωση

Προεπεξεργασία

  • Η έλευση της προεπεξεργασίας σε JavaScript κατέστησε δυνατή την εγκατάλειψη των περισσότερων εξωτερικών σεναρίων και αυτή τη στιγμή στο Zabbix μπορείτε να λάβετε οποιαδήποτε τιμή και να τη μετατρέψετε σε μια εντελώς διαφορετική τιμή.
  • Η προεπεξεργασία στο Zabbix υλοποιείται από κώδικα JavaScript, ο οποίος, όταν μεταγλωττίζεται σε bytecode, μετατρέπεται σε μια συνάρτηση που παίρνει μια μόνο τιμή ως παράμετρο αξία ως συμβολοσειρά (μια συμβολοσειρά μπορεί να περιέχει και ψηφίο και αριθμό).
  • Δεδομένου ότι η έξοδος είναι μια συνάρτηση, στο τέλος του σεναρίου απαιτείται απόδοση.
  • Είναι δυνατή η χρήση προσαρμοσμένων μακροεντολών στον κώδικα.
  • Οι πόροι μπορούν να περιοριστούν όχι μόνο σε επίπεδο λειτουργικού συστήματος, αλλά και μέσω προγραμματισμού. Το βήμα προεπεξεργασίας εκχωρείται το πολύ 10 megabyte μνήμης RAM και όριο χρόνου εκτέλεσης 10 δευτερολέπτων.

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript

Σημείωση. Η τιμή χρονικού ορίου των 10 δευτερολέπτων είναι αρκετά μεγάλη, επειδή η συλλογή υπό όρους χιλιάδων στοιχείων δεδομένων σε 1 δευτερόλεπτο σύμφωνα με ένα μάλλον «βαρύ» σενάριο προεπεξεργασίας μπορεί να επιβραδύνει το Zabbix. Επομένως, δεν συνιστάται η χρήση προεπεξεργασίας για την εκτέλεση πλήρους δέσμης ενεργειών JavaScript μέσω των λεγόμενων στοιχείων σκιωδών δεδομένων (εικονικά στοιχεία), τα οποία εκτελούνται μόνο για την εκτέλεση προεπεξεργασίας.

Μπορείτε να ελέγξετε τον κωδικό σας μέσω της δοκιμής προεπεξεργασίας ή χρησιμοποιώντας το βοηθητικό πρόγραμμα zabbix_js:

`zabbix_js -s *script-file -p *input-param* [-l log-level] [-t timeout]`

`zabbix_js -s script-file -i input-file [-l log-level] [-t timeout]`

`zabbix_js -h`

`zabbix_js -V`

Πρακτικές εργασίες

Έργο 1

Αντικαταστήστε το υπολογιζόμενο στοιχείο με προεπεξεργασία.

Κατάσταση: Λάβετε τη θερμοκρασία σε Φαρενάιτ από τον αισθητήρα για αποθήκευση σε βαθμούς Κελσίου.

Προηγουμένως, θα δημιουργούσαμε ένα αντικείμενο που συλλέγει τη θερμοκρασία σε βαθμούς Φαρενάιτ. Μετά από αυτό, ένα άλλο στοιχείο δεδομένων (υπολογισμένο) που θα μετατρέψει το Fahrenheit σε Κελσίου χρησιμοποιώντας έναν τύπο.

Προβλήματα:

  • Είναι απαραίτητο να αντιγράψετε στοιχεία δεδομένων και να αποθηκεύσετε όλες τις τιμές στη βάση δεδομένων.
  • Πρέπει να συμφωνήσετε για τα διαστήματα για το "γονικό" στοιχείο δεδομένων που υπολογίζεται και χρησιμοποιείται στον τύπο, καθώς και για το υπολογιζόμενο στοιχείο δεδομένων. Διαφορετικά, το υπολογιζόμενο στοιχείο μπορεί να μεταβεί σε κατάσταση που δεν υποστηρίζεται ή να υπολογίσει μια προηγούμενη τιμή, η οποία θα επηρεάσει την αξιοπιστία των αποτελεσμάτων παρακολούθησης.

Μια λύση ήταν να απομακρυνθούμε από τα ευέλικτα διαστήματα ελέγχου προς όφελος των σταθερών διαστημάτων για να διασφαλιστεί ότι το υπολογισμένο στοιχείο αξιολογείται μετά το στοιχείο που λαμβάνει τα δεδομένα (στην περίπτωσή μας, η θερμοκρασία σε βαθμούς Φαρενάιτ).

Αλλά αν, για παράδειγμα, χρησιμοποιήσουμε το πρότυπο για να ελέγξουμε έναν μεγάλο αριθμό συσκευών και ο έλεγχος πραγματοποιείται μία φορά κάθε 30 δευτερόλεπτα, το Zabbix «χάκαρει» για 29 δευτερόλεπτα και στο τελευταίο δευτερόλεπτο αρχίζει να ελέγχει και να υπολογίζει. Αυτό δημιουργεί μια ουρά και επηρεάζει την απόδοση. Επομένως, συνιστάται η χρήση σταθερών διαστημάτων μόνο εάν είναι πραγματικά απαραίτητο.

Σε αυτό το πρόβλημα, η βέλτιστη λύση είναι μια προεπεξεργασία JavaScript μίας γραμμής που μετατρέπει βαθμούς Φαρενάιτ σε βαθμούς Κελσίου:

`return (value - 32) * 5 / 9;`

Είναι γρήγορο και εύκολο, δεν χρειάζεται να δημιουργείτε περιττά στοιχεία δεδομένων και να διατηρείτε ιστορικό σε αυτά, ενώ μπορείτε επίσης να χρησιμοποιείτε ευέλικτα διαστήματα για ελέγχους.

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript

`return (parseInt(value) + parseInt("{$EXAMPLE.MACRO}"));`

Αλλά, εάν σε μια υποθετική κατάσταση είναι απαραίτητο να προστεθεί το ληφθέν στοιχείο δεδομένων, για παράδειγμα, με οποιαδήποτε σταθερά που ορίζεται στη μακροεντολή, πρέπει να ληφθεί υπόψη ότι η παράμετρος αξία επεκτείνεται σε μια χορδή. Σε μια λειτουργία προσθήκης συμβολοσειράς, δύο συμβολοσειρές απλώς συνδυάζονται σε μία.

Επιλύουμε πρακτικά προβλήματα στο Zabbix χρησιμοποιώντας JavaScript

`return (value + "{$EXAMPLE.MACRO}");`

Για να λάβετε το αποτέλεσμα μιας μαθηματικής πράξης, είναι απαραίτητο να μετατρέψετε τους τύπους των λαμβανόμενων τιμών σε αριθμητική μορφή. Για αυτό μπορείτε να χρησιμοποιήσετε τη λειτουργία parseInt(), που παράγει έναν ακέραιο, μια συνάρτηση parseFloat(), που παράγει ένα δεκαδικό ή μια συνάρτηση αριθμός, το οποίο επιστρέφει έναν ακέραιο ή δεκαδικό.

Εργασία 2

Λάβετε το χρόνο σε δευτερόλεπτα μέχρι το τέλος του πιστοποιητικού.

Κατάσταση: μια υπηρεσία εκδίδει μια ημερομηνία λήξης πιστοποιητικού με τη μορφή "12 Φεβρουαρίου 12:33:56 2022 GMT".

Στο ECMAScript5 date.parse() αποδέχεται μια ημερομηνία σε μορφή ISO 8601 (ΕΕΕΕ-ΜΜ-ΗΗΗΩΗ:λλ:δδ.δδσΖ). Είναι απαραίτητο να ρίξετε μια συμβολοσειρά με τη μορφή ΜΜΜ ΗΗ ΕΕΕΕ ΩΩ:λλ:δδ ZZ

πρόβλημα: Η τιμή του μήνα εκφράζεται ως κείμενο και όχι ως αριθμός. Δεδομένα σε αυτήν τη μορφή δεν γίνονται δεκτά από την Duktape.

Παράδειγμα Λύσης:

  • Πρώτα απ 'όλα, δηλώνεται μια μεταβλητή που παίρνει μια τιμή (όλο το σενάριο είναι μια δήλωση μεταβλητών που παρατίθενται διαχωρισμένες με κόμμα).

  • Στην πρώτη γραμμή παίρνουμε την ημερομηνία στην παράμετρο αξία και διαχωρίστε το με κενά χρησιμοποιώντας τη μέθοδο διαίρεση. Έτσι, παίρνουμε έναν πίνακα, όπου κάθε στοιχείο του πίνακα, ξεκινώντας από το δείκτη 0, αντιστοιχεί σε ένα στοιχείο ημερομηνίας πριν και μετά από ένα διάστημα. split (0) - μήνας, split (1) - αριθμός, split (2) - μια συμβολοσειρά με χρόνο, κ.λπ. Μετά από αυτό, κάθε στοιχείο της ημερομηνίας μπορεί να προσπελαστεί με ευρετήριο στον πίνακα.

`var split = value.split(' '),`

  • Κάθε μήνας (με χρονολογική σειρά) αντιστοιχεί στον δείκτη της θέσης του στον πίνακα (από 0 έως 11). Για να μετατρέψετε μια τιμή κειμένου σε αριθμητική τιμή, προστίθεται μία στο ευρετήριο μήνα (επειδή οι μήνες αριθμούνται από το 1). Σε αυτή την περίπτωση, η έκφραση με την προσθήκη ενός λαμβάνεται σε αγκύλες, γιατί διαφορετικά θα ληφθεί συμβολοσειρά και όχι αριθμός. Στο τέλος το κάνουμε φέτα() - κόψτε τον πίνακα από το τέλος για να αφήσετε μόνο δύο χαρακτήρες (κάτι που είναι σημαντικό για μήνες με διψήφιο αριθμό).

`MONTHS_LIST = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],`

`month_index = ('0' + (MONTHS_LIST.indexOf(split[0]) + 1)).slice(-2),`

  • Σχηματίζουμε μια συμβολοσειρά σε μορφή ISO από τις λαμβανόμενες τιμές με τη συνήθη προσθήκη συμβολοσειρών με την κατάλληλη σειρά.

`ISOdate = split[3] + '-' + month_index + '-' + split[1] + 'T' + split[2],`

Τα δεδομένα στη μορφή που προκύπτει είναι ο αριθμός των δευτερολέπτων από το 1970 έως κάποιο σημείο στο μέλλον. Είναι σχεδόν αδύνατο να χρησιμοποιήσετε δεδομένα στη ληφθείσα μορφή σε εναύσματα, επειδή το Zabbix σας επιτρέπει να λειτουργείτε μόνο με μακροεντολές {Ημερομηνία} и {Χρόνος}, τα οποία επιστρέφουν την ημερομηνία και την ώρα σε μορφή φιλική προς το χρήστη.

  • Στη συνέχεια, μπορούμε να πάρουμε την τρέχουσα ημερομηνία σε JavaScript σε μορφή Unix Timestamp και να την αφαιρέσουμε από την ημερομηνία λήξης του πιστοποιητικού που προκύπτει για να λάβουμε τον αριθμό των χιλιοστών του δευτερολέπτου από τώρα μέχρι τη λήξη του πιστοποιητικού.

`now = Date.now();`

  • Διαιρούμε τη λαμβανόμενη τιμή με χίλια για να λάβουμε δευτερόλεπτα στο Zabbix.

`return parseInt((Date.parse(ISOdate) - now) / 1000);`

Στο έναυσμα, μπορείτε να καθορίσετε την έκφραση "τελευταίος' ακολουθούμενο από ένα σύνολο ψηφίων που αντιστοιχεί στον αριθμό των δευτερολέπτων στην περίοδο στην οποία θέλετε να απαντήσετε, για παράδειγμα, σε εβδομάδες. Έτσι, το έναυσμα θα ειδοποιήσει ότι το πιστοποιητικό λήγει σε μια εβδομάδα.

Σημείωση. Δώστε προσοχή στη χρήση parseInt() σε λειτουργία απόδοσηγια να μετατρέψετε τον κλασματικό αριθμό που προκύπτει από τη διαίρεση των χιλιοστών του δευτερολέπτου σε έναν ακέραιο. Μπορείτε επίσης να χρησιμοποιήσετε parseFloat() και αποθήκευση κλασματικών δεδομένων.

Δείτε το ρεπορτάζ

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο