alexa-monit – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #!/usr/bin/env nodejs
2 ///////////////////////////////////////////////////////////////////////////
3 // Copyright (C) Wizardry and Steamworks 2018 - License: GNU GPLv3 //
4 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
5 // rights of fair usage, the disclaimer and warranty conditions. //
6 ///////////////////////////////////////////////////////////////////////////
7  
8 const request = require('request');
9 const mqtt = require('mqtt')
10 const YAML = require('yamljs');
11 const winston = require('winston');
12 const urljoin = require('url-join');
13 const fs = require('fs');
14 const jsonDiff = require('json-diff')
15  
16 // Load configuration file.
17 const config = YAML.load('config.yml');
18  
19 // Set up logger.
20 const logger = winston.createLogger({
21 level: 'info',
22 format: winston.format.json(),
23 transports: [
24 new winston.transports.File({
25 filename: config.log
26 })
27 ]
28 });
29  
30 if (process.env.NODE_ENV !== 'production') {
31 logger.add(new winston.transports.Console({
32 format: winston.format.simple()
33 }));
34 }
35  
36 // Create cookie jar.
37 const cookieJar = request.jar();
38  
39 // Connect to MQTT
40 const mqttClient = mqtt.connect(config.mqtt.url);
41  
42 function main() {
43 return new Promise((resolve, reject) => {
44 request({
45 method: 'GET',
46 url: urljoin(config.mmonit.url, '/index.csp'),
47 jar: cookieJar
48 },
49 (error, response, body) => {
50 if (error) {
51 reject(error);
52 return;
53 }
54 resolve(error);
55 });
56 });
57 }
58  
59 function authenticate() {
60 return new Promise((resolve, reject) => {
61 request.post({
62 url: urljoin(config.mmonit.url, '/z_security_check'),
63 jar: cookieJar,
64 form: {
65 'z_username': config.mmonit.username,
66 'z_password': config.mmonit.password,
67 'z_csrf_protection': 'off'
68 }
69 },
70 (error, response, body) => {
71 if (error) {
72 reject(error);
73 return;
74 }
75 resolve(error);
76 });
77 });
78 }
79  
80 function getHostStatusList() {
81 return new Promise((resolve, reject) => {
82 request({
83 method: 'GET',
84 url: urljoin(config.mmonit.url, '/status/hosts/list'),
85 jar: cookieJar
86 },
87 (error, response, body) => {
88 if (error) {
89 reject(error);
90 return;
91 }
92 resolve(body);
93 });
94 });
95 }
96  
97 function writeState(state, file) {
98 // Store the state.
99 var data = JSON.stringify(state);
100  
101 return new Promise(function (resolve, reject) {
102 fs.writeFile(file, data, function (error) {
103 if (error) {
104 reject(error);
105 return;
106 }
107 resolve();
108 });
109 });
110 }
111  
112 function readState(file) {
113 // Store the state.
114 return new Promise(function (resolve, reject) {
115 fs.readFile(file, 'utf8', function (error, data) {
116 if (error) {
117 reject(error);
118 return;
119 }
120 resolve(JSON.parse(data));
121 })
122 });
123 }
124  
125 function retrieveData() {
126 main().then((error) => {
127 if (error) {
128 logger.error('Could not reach main page.');
129 return;
130 }
131  
132 logger.info('Got cookie.');
133  
134 authenticate().then((error) => {
135 if (error) {
136 logger.error('Could not authenticate.');
137 return;
138 }
139  
140 logger.info('Authentication successful.');
141  
142 getHostStatusList().then((data) => {
143 if (error) {
144 logger.error('Could not get status list.');
145 return;
146 }
147  
148 logger.info('Retrieved status list.');
149 var stateNew = JSON.parse(data);
150  
151 fs.access(config.stateFile, fs.constants.F_OK, function (error) {
152 // State file does not exist, so write the data file and terminate.
153 if (error) {
154 logger.warn('State file not found, writing state.');
155 writeState(stateNew, config.stateFile).then(function () {
156 logger.info("Data stored.");
157 }, function (error) {
158 logger.error("Unable to store data: " + error);
159 });
160 return;
161 }
162  
163 readState(config.stateFile).then(function (stateOld) {
164 logger.info("Comparing data.");
165  
166 // stateOld, stateNew
167 stateOld.records.forEach(function (oldRecord) {
168 var hostname = oldRecord.hostname;
169 var id = oldRecord.id;
170  
171 var newRecord = stateNew.records.find(function (record) {
172 return record.id === id;
173 });
174  
175 var diff = jsonDiff.diff(oldRecord, newRecord);
176 if (typeof diff === undefined || diff == null) {
177 // No difference found so continue.
178 return;
179 }
180  
181 // Filter out the "status" component.
182 if (typeof diff.status === undefined ||
183 diff.status == null) {
184 return;
185 }
186  
187 // Build message out of hostname and new status change.
188 var message = hostname + " " + diff.status.__new;
189 logger.info(message);
190  
191 mqttClient.publish(config.mqtt.topic, message, {}, function(error) {
192 if(error) {
193 logger.error("Unable to publish MQTT message: " + error);
194 return;
195 }
196  
197 logger.info("Status change pushed to MQTT.");
198 });
199 });
200  
201 // Save the retrieved data.
202 writeState(stateNew, config.stateFile).then(function () {
203 logger.info("Data stored.");
204 }, function (error) {
205 logger.error("Unable to store data: " + error);
206 });
207  
208 }, function(error) {
209 logger.error("Unable to read state: " + error);
210 });
211 });
212 })
213 })
214 });
215 }
216  
217 setInterval(retrieveData, config.interval);