Browse Source

Add support for script's exit status in ping URLs

Fixes: #429
pull/456/head
Pēteris Caune 4 years ago
parent
commit
81e59ac553
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
12 changed files with 140 additions and 67 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +20
    -0
      hc/api/tests/test_ping.py
  3. +1
    -0
      hc/api/urls.py
  4. +4
    -1
      hc/api/views.py
  5. +4
    -15
      templates/docs/attaching_logs.html
  6. +4
    -16
      templates/docs/attaching_logs.md
  7. +6
    -8
      templates/docs/bash.html
  8. +6
    -6
      templates/docs/bash.md
  9. +26
    -0
      templates/docs/http_api.html
  10. +29
    -0
      templates/docs/http_api.md
  11. +18
    -11
      templates/docs/signalling_failures.html
  12. +21
    -10
      templates/docs/signalling_failures.md

+ 1
- 0
CHANGELOG.md View File

@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
- When saving a phone number, remove any invisible unicode characers - When saving a phone number, remove any invisible unicode characers
- Update the read-only dashboard's CSS for better mobile support (#442) - Update the read-only dashboard's CSS for better mobile support (#442)
- Reduce the number of SQL queries used in the "Get Checks" API call - Reduce the number of SQL queries used in the "Get Checks" API call
- Add support for script's exit status in ping URLs (#429)
## v1.17.0 - 2020-10-14 ## v1.17.0 - 2020-10-14


+ 20
- 0
hc/api/tests/test_ping.py View File

@ -224,3 +224,23 @@ class PingTestCase(BaseTestCase):
ping = Ping.objects.latest("id") ping = Ping.objects.latest("id")
self.assertEqual(ping.scheme, "http") self.assertEqual(ping.scheme, "http")
self.assertEqual(ping.kind, "ign") self.assertEqual(ping.kind, "ign")
def test_zero_exit_status_works(self):
r = self.client.get("/ping/%s/0" % self.check.code)
self.assertEqual(r.status_code, 200)
self.check.refresh_from_db()
self.assertEqual(self.check.status, "up")
ping = Ping.objects.latest("id")
self.assertEqual(ping.kind, None)
def test_nonzero_exit_status_works(self):
r = self.client.get("/ping/%s/123" % self.check.code)
self.assertEqual(r.status_code, 200)
self.check.refresh_from_db()
self.assertEqual(self.check.status, "down")
ping = Ping.objects.latest("id")
self.assertEqual(ping.kind, "fail")

+ 1
- 0
hc/api/urls.py View File

@ -32,6 +32,7 @@ urlpatterns = [
path("ping/<uuid:code>", views.ping, name="hc-ping"), path("ping/<uuid:code>", views.ping, name="hc-ping"),
path("ping/<uuid:code>/fail", views.ping, {"action": "fail"}, name="hc-fail"), path("ping/<uuid:code>/fail", views.ping, {"action": "fail"}, name="hc-fail"),
path("ping/<uuid:code>/start", views.ping, {"action": "start"}, name="hc-start"), path("ping/<uuid:code>/start", views.ping, {"action": "start"}, name="hc-start"),
path("ping/<uuid:code>/<int:exitstatus>", views.ping),
path("api/v1/checks/", views.checks), path("api/v1/checks/", views.checks),
path("api/v1/checks/<uuid:code>", views.single, name="hc-api-single"), path("api/v1/checks/<uuid:code>", views.single, name="hc-api-single"),
path("api/v1/checks/<sha1:unique_key>", views.get_check_by_unique_key), path("api/v1/checks/<sha1:unique_key>", views.get_check_by_unique_key),


+ 4
- 1
hc/api/views.py View File

@ -30,7 +30,7 @@ class BadChannelException(Exception):
@csrf_exempt @csrf_exempt
@never_cache @never_cache
def ping(request, code, action="success"):
def ping(request, code, action="success", exitstatus=0):
check = get_object_or_404(Check, code=code) check = get_object_or_404(Check, code=code)
headers = request.META headers = request.META
@ -41,6 +41,9 @@ def ping(request, code, action="success"):
ua = headers.get("HTTP_USER_AGENT", "") ua = headers.get("HTTP_USER_AGENT", "")
body = request.body.decode() body = request.body.decode()
if exitstatus > 0:
action = "fail"
if check.methods == "POST" and method != "POST": if check.methods == "POST" and method != "POST":
action = "ign" action = "ign"


+ 4
- 15
templates/docs/attaching_logs.html View File

@ -4,8 +4,8 @@
If the request body looks like a UTF-8 string, SITE_NAME will log the If the request body looks like a UTF-8 string, SITE_NAME will log the
first 10 kilobytes (10 000 bytes) of the request body, so you can inspect it later.</p> first 10 kilobytes (10 000 bytes) of the request body, so you can inspect it later.</p>
<h2>Logging Command Output</h2> <h2>Logging Command Output</h2>
<p>In this example, we run <code>certbot renew</code>, capture its output, and submit
the captured output to SITE_NAME:</p>
<p>In this example, we run <code>certbot renew</code>, capture its output (both the stdout
and stderr streams), and submit the captured output to SITE_NAME:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span> <div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span> <span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span>
@ -13,24 +13,13 @@ curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-r
</code></pre></div> </code></pre></div>
<h2>In Combination with the <code>/fail</code> Endpoint</h2>
<h2>In Combination with the <code>/fail</code> and <code>/{exit-status}</code> Endpoints</h2>
<p>We can extend the previous example and signal either success or failure <p>We can extend the previous example and signal either success or failure
depending on the exit code:</p> depending on the exit code:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span> <div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">url</span><span class="o">=</span>PING_URL
<span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span> <span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> -ne <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">url</span><span class="o">=</span><span class="nv">$url</span>/fail<span class="p">;</span> <span class="k">fi</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> <span class="nv">$url</span>
</code></pre></div>
<p>The above script can be packaged in a single line. The one-line
version sacrifices some readability, but it can be used directly in crontab,
without using a wrapper script:</p>
<div class="bash highlight"><pre><span></span><code><span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span><span class="p">;</span> curl -fsS --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> <span class="s2">&quot;PING_URL</span><span class="k">$(</span><span class="o">[</span> <span class="nv">$?</span> -ne <span class="m">0</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> -n /fail<span class="k">)</span><span class="s2">&quot;</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> PING_URL/<span class="nv">$?</span>
</code></pre></div> </code></pre></div>


+ 4
- 16
templates/docs/attaching_logs.md View File

@ -8,8 +8,8 @@ first 10 kilobytes (10 000 bytes) of the request body, so you can inspect it lat
## Logging Command Output ## Logging Command Output
In this example, we run `certbot renew`, capture its output, and submit
the captured output to SITE_NAME:
In this example, we run `certbot renew`, capture its output (both the stdout
and stderr streams), and submit the captured output to SITE_NAME:
```bash ```bash
#!/bin/sh #!/bin/sh
@ -18,7 +18,7 @@ m=$(/usr/bin/certbot renew 2>&1)
curl -fsS -m 10 --retry 5 --data-raw "$m" PING_URL curl -fsS -m 10 --retry 5 --data-raw "$m" PING_URL
``` ```
## In Combination with the `/fail` Endpoint
## In Combination with the `/fail` and `/{exit-status}` Endpoints
We can extend the previous example and signal either success or failure We can extend the previous example and signal either success or failure
depending on the exit code: depending on the exit code:
@ -26,20 +26,8 @@ depending on the exit code:
```bash ```bash
#!/bin/sh #!/bin/sh
url=PING_URL
m=$(/usr/bin/certbot renew 2>&1) m=$(/usr/bin/certbot renew 2>&1)
if [ $? -ne 0 ]; then url=$url/fail; fi
curl -fsS -m 10 --retry 5 --data-raw "$m" $url
```
The above script can be packaged in a single line. The one-line
version sacrifices some readability, but it can be used directly in crontab,
without using a wrapper script:
```bash
m=$(/usr/bin/certbot renew 2>&1); curl -fsS --data-raw "$m" "PING_URL$([ $? -ne 0 ] && echo -n /fail)"
curl -fsS -m 10 --retry 5 --data-raw "$m" PING_URL/$?
``` ```
## Using Runitor ## Using Runitor


+ 6
- 8
templates/docs/bash.html View File

@ -31,19 +31,17 @@ hides error messages.</dd>
<dd>Redirect curl's stdout to /dev/null (error messages still go to stderr).</dd> <dd>Redirect curl's stdout to /dev/null (error messages still go to stderr).</dd>
</dl> </dl>
<h2>Signalling Failure from Shell Scripts</h2> <h2>Signalling Failure from Shell Scripts</h2>
<p>You can append <code>/fail</code> to any ping URL and use the resulting URL to actively
signal a failure. The following example:</p>
<ul>
<li>runs <code>/usr/bin/certbot renew</code></li>
<li>if the certbot command is successful (exit code 0), sends HTTP GET to <code>PING_URL</code></li>
<li>otherwise, sends HTTP GET to <code>PING_URL/fail</code></li>
</ul>
<p>You can append <code>/fail</code> or <code>/{exit-status}</code> to any ping URL and use the resulting URL
to actively signal a failure. The exit status should be a 0-255 integer.
SITE_NAME will interpret exit status 0 as success, and all non-zero values as failures.</p>
<p>The following example runs <code>/usr/bin/certbot renew</code>, and uses the <code>$?</code> variable to
look up its exit status:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span> <div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="c1"># Payload here:</span> <span class="c1"># Payload here:</span>
/usr/bin/certbot renew /usr/bin/certbot renew
<span class="c1"># Ping SITE_NAME</span> <span class="c1"># Ping SITE_NAME</span>
curl -m <span class="m">10</span> --retry <span class="m">5</span> <span class="s2">&quot;PING_URL</span><span class="k">$(</span><span class="o">[</span> <span class="nv">$?</span> -ne <span class="m">0</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> -n /fail<span class="k">)</span><span class="s2">&quot;</span>
curl -m <span class="m">10</span> --retry <span class="m">5</span> PING_URL/<span class="nv">$?</span>
</code></pre></div> </code></pre></div>


+ 6
- 6
templates/docs/bash.md View File

@ -40,12 +40,12 @@ Here's what each curl parameter does:
## Signalling Failure from Shell Scripts ## Signalling Failure from Shell Scripts
You can append `/fail` to any ping URL and use the resulting URL to actively
signal a failure. The following example:
You can append `/fail` or `/{exit-status}` to any ping URL and use the resulting URL
to actively signal a failure. The exit status should be a 0-255 integer.
SITE_NAME will interpret exit status 0 as success, and all non-zero values as failures.
* runs `/usr/bin/certbot renew`
* if the certbot command is successful (exit code 0), sends HTTP GET to `PING_URL`
* otherwise, sends HTTP GET to `PING_URL/fail`
The following example runs `/usr/bin/certbot renew`, and uses the `$?` variable to
look up its exit status:
```bash ```bash
#!/bin/sh #!/bin/sh
@ -53,7 +53,7 @@ signal a failure. The following example:
# Payload here: # Payload here:
/usr/bin/certbot renew /usr/bin/certbot renew
# Ping SITE_NAME # Ping SITE_NAME
curl -m 10 --retry 5 "PING_URL$([ $? -ne 0 ] && echo -n /fail)"
curl -m 10 --retry 5 PING_URL/$?
``` ```
## Logging Command Output ## Logging Command Output


+ 26
- 0
templates/docs/http_api.html View File

@ -82,6 +82,32 @@ optional but enables a few extra features:</p>
</code></pre></div> </code></pre></div>
<div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/plain; charset=utf-8</span>
<span class="na">Content-Length</span><span class="o">:</span> <span class="l">2</span>
<span class="na">Connection</span><span class="o">:</span> <span class="l">close</span>
<span class="na">Access-Control-Allow-Origin</span><span class="o">:</span> <span class="l">*</span>
OK
</code></pre></div>
<h2>Report Script's Exit Status</h2>
<div class="text highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/{exit-status}
</code></pre></div>
<p>Sends a success or failure signal depending on the exit status
included in the URL. The exit status is a 0-255 integer. SITE_NAME
interprets 0 as success, and all other values as failure.</p>
<p><strong>Example</strong></p>
<div class="http highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/1</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">hc-ping.com</span>
</code></pre></div>
<div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span> <div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span> <span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span> <span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span>


+ 29
- 0
templates/docs/http_api.md View File

@ -105,3 +105,32 @@ Access-Control-Allow-Origin: *
OK OK
``` ```
## Report Script's Exit Status
```text
HEAD|GET|POST PING_ENDPOINT{uuid}/{exit-status}
```
Sends a success or failure signal depending on the exit status
included in the URL. The exit status is a 0-255 integer. SITE_NAME
interprets 0 as success, and all other values as failure.
**Example**
```http
GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/1 HTTP/1.0
Host: hc-ping.com
```
```http
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 29 Jan 2020 09:58:23 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 2
Connection: close
Access-Control-Allow-Origin: *
OK
```

+ 18
- 11
templates/docs/signalling_failures.html View File

@ -1,19 +1,26 @@
<h1>Signalling failures</h1> <h1>Signalling failures</h1>
<p>Append <code>/fail</code> to a ping URL and use it to actively signal a failure.
Requesting the <code>/fail</code> URL will immediately mark the check as "down".
You can use this feature to minimize the delay from your monitored service failing
to you getting a notification.</p>
<p>You can actively signal a failure to SITE_NAME by slightly changing the
ping URL: append either <code>/fail</code> or <code>/{exit-status}</code> to your normal ping URL.
The exit status should be a 0-255 integer. SITE_NAME will interpret
exit status 0 as success, and all non-zero values as failures.</p>
<p>Examples:</p>
<div class="bash highlight"><pre><span></span><code><span class="c1"># Reports failure by appending the /fail suffix:</span>
curl --retry <span class="m">3</span> PING_URL/fail
<span class="c1"># Reports failure by appending a non-zero exit status:</span>
curl --retry <span class="m">3</span> PING_URL/1
</code></pre></div>
<p>By actively signalling failures to SITE_NAME, you can minimize the delay from your
monitored service encountering a problem to you getting notified about it.</p>
<h2>Shell Scripts</h2> <h2>Shell Scripts</h2>
<p>The below shell script sends either a "success" or "failure" ping depending on
command's (certbot in this example) exit code:</p>
<p>The below shell script appends <code>$?</code> (a special variable which contains the
exit status of the last executed command) to the ping URL:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span> <div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">url</span><span class="o">=</span>PING_URL
/usr/bin/certbot renew /usr/bin/certbot renew
<span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> -ne <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">url</span><span class="o">=</span><span class="nv">$url</span>/fail<span class="p">;</span> <span class="k">fi</span>
curl --retry <span class="m">3</span> <span class="nv">$url</span>
curl --retry <span class="m">3</span> PING_URL/<span class="nv">$?</span>
</code></pre></div> </code></pre></div>


+ 21
- 10
templates/docs/signalling_failures.md View File

@ -1,24 +1,35 @@
# Signalling failures # Signalling failures
Append `/fail` to a ping URL and use it to actively signal a failure.
Requesting the `/fail` URL will immediately mark the check as "down".
You can use this feature to minimize the delay from your monitored service failing
to you getting a notification.
You can actively signal a failure to SITE_NAME by slightly changing the
ping URL: append either `/fail` or `/{exit-status}` to your normal ping URL.
The exit status should be a 0-255 integer. SITE_NAME will interpret
exit status 0 as success, and all non-zero values as failures.
Examples:
```bash
# Reports failure by appending the /fail suffix:
curl --retry 3 PING_URL/fail
# Reports failure by appending a non-zero exit status:
curl --retry 3 PING_URL/1
```
By actively signalling failures to SITE_NAME, you can minimize the delay from your
monitored service encountering a problem to you getting notified about it.
## Shell Scripts ## Shell Scripts
The below shell script sends either a "success" or "failure" ping depending on
command's (certbot in this example) exit code:
The below shell script appends `$?` (a special variable which contains the
exit status of the last executed command) to the ping URL:
```bash ```bash
#!/bin/sh #!/bin/sh
url=PING_URL
/usr/bin/certbot renew /usr/bin/certbot renew
curl --retry 3 PING_URL/$?
if [ $? -ne 0 ]; then url=$url/fail; fi
curl --retry 3 $url
``` ```
## Python ## Python


Loading…
Cancel
Save