root/src/modules-lua/noit/module/http.lua

Revision 4a67d452816c39b086e4f2ba5be9d12cf51aa81b, 8.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

allow method specification, refs #187

  • Property mode set to 100644
Line 
1 -- Copyright (c) 2008, OmniTI Computer Consulting, Inc.
2 -- All rights reserved.
3 --
4 -- Redistribution and use in source and binary forms, with or without
5 -- modification, are permitted provided that the following conditions are
6 -- met:
7 --
8 --     * Redistributions of source code must retain the above copyright
9 --       notice, this list of conditions and the following disclaimer.
10 --     * Redistributions in binary form must reproduce the above
11 --       copyright notice, this list of conditions and the following
12 --       disclaimer in the documentation and/or other materials provided
13 --       with the distribution.
14 --     * Neither the name OmniTI Computer Consulting, Inc. nor the names
15 --       of its contributors may be used to endorse or promote products
16 --       derived from this software without specific prior written
17 --       permission.
18 --
19 -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 -- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 -- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 -- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 -- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 -- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 -- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 module(..., package.seeall)
32
33 function onload(image)
34   image.xml_description([=[
35 <module>
36   <name>http</name>
37   <description><para>The http module performs GET requests over either HTTP or HTTPS and checks the return code and optionally the body.</para>
38   </description>
39   <loader>lua</loader>
40   <object>noit.module.http</object>
41   <checkconfig>
42     <parameter name="url"
43                required="required"
44                allowed=".+">The URL including schema and hostname (as you would type into a browser's location bar).</parameter>
45     <parameter name="method"
46                required="optional"
47                allowed="\S+"
48                default="GET">The HTTP method to use.</parameter>
49     <parameter name="ca_chain"
50                required="optional"
51                allowed=".+">A path to a file containing all the certificate authorities that should be loaded to validate the remote certificate (for SSL checks).</parameter>
52     <parameter name="certificate_file"
53                required="optional"
54                allowed=".+">A path to a file containing the client certificate that will be presented to the remote server (for SSL checks).</parameter>
55     <parameter name="key_file"
56                required="optional"
57                allowed=".+">A path to a file containing key to be used in conjunction with the cilent certificate (for SSL checks).</parameter>
58     <parameter name="ciphers"
59                required="optional"
60                allowed=".+">A list of ciphers to be used in the SSL protocol (for SSL checks).</parameter>
61     <parameter name="code"
62                required="optional"
63                default="^200$"
64                allowed=".+">The HTTP code that is expected.  If the code received does not match this regular expression, the check is marked as "bad."</parameter>
65     <parameter name="body"
66                required="optional"
67                allowed=".+">This regular expression is matched against the body of the response.  If a match is not found, the check will be marked as "bad."</parameter>
68   </checkconfig>
69   <examples>
70     <example>
71       <title>Checking an HTTP and HTTPS URL.</title>
72       <para>This example checks the OmniTI Labs website over both HTTP and HTTPS.</para>
73       <programlisting><![CDATA[
74       <noit>
75         <modules>
76           <loader image="lua" name="lua">
77             <config><directory>/opt/reconnoiter/libexec/modules-lua/?.lua</directory></config>
78           </loader>
79           <module loader="lua" name="http" object="noit.module.http" />
80         </modules>
81         <checks>
82           <labs target="8.8.38.5" module="http">
83             <check uuid="fe3e984c-7895-11dd-90c1-c74c31b431f0" name="http">
84               <config><url>http://labs.omniti.com/</url></config>
85             </check>
86             <check uuid="1ecd887a-7896-11dd-b28d-0b4216877f83" name="https">
87               <config><url>https://labs.omniti.com/</url></config>
88             </check>
89           </labs>
90         </checks>
91       </noit>
92     ]]></programlisting>
93     </example>
94   </examples>
95 </module>
96 ]=]);
97   return 0
98 end
99
100 function init(module)
101   return 0
102 end
103
104 function config(module, options)
105   return 0
106 end
107
108 local HttpClient = require 'noit.HttpClient'
109
110 function elapsed(check, name, starttime, endtime)
111     local elapsedtime = endtime - starttime
112     local seconds = string.format('%.3f', noit.timeval.seconds(elapsedtime))
113     check.metric_uint32(name, math.floor(seconds * 1000 + 0.5))
114     return seconds
115 end
116
117 function initiate(module, check)
118     local url = check.config.url or 'http:///'
119     local schema, host, uri = string.match(url, "^(https?)://([^/]*)(.+)$");
120     local port
121     local use_ssl = false
122     local codere = noit.pcre(check.config.code or '^200$')
123     local good = false
124     local starttime = noit.timeval.now()
125     local method = check.config.method or "GET"
126
127     if host == nil then host = check.target end
128     if schema == nil then
129         schema = 'http'
130         uri = '/'
131     end
132     if schema == 'http' then
133         port = check.config.port or 80
134     elseif schema == 'https' then
135         port = check.config.port or 443
136         use_ssl = true
137     else
138         error(schema .. " not supported")
139     end
140
141     local output = ''
142     local connecttime, firstbytetime
143
144     -- callbacks from the HttpClient
145     local callbacks = { }
146     callbacks.consume = function (str)
147         if firstbytetime == nil then firstbytetime = noit.timeval.now() end
148         output = output .. str
149     end
150     callbacks.connected = function () connecttime = noit.timeval.now() end
151
152     -- setup SSL info
153     local default_ca_chain =
154         noit.conf_get_string("/noit/eventer/config/default_ca_chain")
155     callbacks.certfile = function () return check.config.certificate_file end
156     callbacks.keyfile = function () return check.config.key_file end
157     callbacks.cachain = function ()
158         return check.config.ca_chain and check.config.ca_chain
159                                       or default_ca_chain
160     end
161     callbacks.ciphers = function () return check.config.ciphers end
162     local client = HttpClient:new(callbacks)
163     local rv, err = client:connect(check.target, port, use_ssl)
164    
165     if rv ~= 0 then
166         check.bad()
167         check.unavailable()
168         check.status(str or "unknown error")
169         return
170     end
171
172     -- perform the request
173     local headers = {}
174     headers.Host = host
175     client:do_request(method, uri, headers)
176     client:get_response()
177     local endtime = noit.timeval.now()
178     check.available()
179
180     local status = ''
181     -- setup the code
182     check.metric_string("code", client.code)
183     status = status .. 'code=' .. client.code
184     if codere ~= nil and codere(client.code) then
185       good = true
186     end
187
188     -- turnaround time
189     local seconds = elapsed(check, "duration", starttime, endtime)
190     status = status .. ',rt=' .. seconds .. 's'
191     elapsed(check, "tt_connect", starttime, connecttime)
192     elapsed(check, "tt_firstbyte", starttime, firstbytetime)
193
194     -- size
195     status = status .. ',bytes=' .. client.content_bytes
196     check.metric_int32("bytes", client.content_bytes)
197
198     -- check body
199     if check.config.body ~= nil then
200       local bodyre = noit.pcre(check.config.body)
201       if bodyre ~= nil and bodyre(output) then
202         status = status .. ',body=matched'
203       else
204         status = status .. ',body=failed'
205         good = false
206       end
207     end
208
209     -- ssl ctx
210     local ssl_ctx = client:ssl_ctx()
211     if ssl_ctx ~= nil then
212       if ssl_ctx.error ~= nil then status = status .. ',sslerror' end
213       check.metric_string("cert_error", ssl_ctx.error)
214       check.metric_string("cert_issuer", ssl_ctx.issuer)
215       check.metric_string("cert_subject", ssl_ctx.subject)
216       check.metric_uint32("cert_start", ssl_ctx.start_time)
217       check.metric_uint32("cert_end", ssl_ctx.end_time)
218       if noit.timeval.seconds(starttime) > ssl_ctx.end_time then
219         good = false
220         status = status .. ',ssl=expired'
221       end
222     end
223
224     if good then check.good() else check.bad() end
225     check.status(status)
226 end
227
Note: See TracBrowser for help on using the browser.