Compare commits

...

No commits in common. 'master' and 'gh-pages' have entirely different histories.

  1. 12
      .gitignore
  2. 9
      .gitmodules
  3. 492
      Adding/index.html
  4. 580
      Canary/index.html
  5. 19
      LICENSE
  6. 40
      README.md
  7. 513
      Running/index.html
  8. 568
      Services/index.html
  9. 4
      assets/fonts/font-awesome.css
  10. 13
      assets/fonts/material-icons.css
  11. BIN
      assets/fonts/specimen/FontAwesome.ttf
  12. BIN
      assets/fonts/specimen/FontAwesome.woff
  13. BIN
      assets/fonts/specimen/FontAwesome.woff2
  14. BIN
      assets/fonts/specimen/MaterialIcons-Regular.ttf
  15. BIN
      assets/fonts/specimen/MaterialIcons-Regular.woff
  16. BIN
      assets/fonts/specimen/MaterialIcons-Regular.woff2
  17. BIN
      assets/images/favicon.png
  18. 20
      assets/images/icons/bitbucket.1b09e088.svg
  19. 18
      assets/images/icons/github.f0b8504a.svg
  20. 38
      assets/images/icons/gitlab.6dd19c00.svg
  21. 1
      assets/javascripts/application.e72fd936.js
  22. 1
      assets/javascripts/lunr/lunr.da.js
  23. 1
      assets/javascripts/lunr/lunr.de.js
  24. 1
      assets/javascripts/lunr/lunr.du.js
  25. 1
      assets/javascripts/lunr/lunr.es.js
  26. 1
      assets/javascripts/lunr/lunr.fi.js
  27. 1
      assets/javascripts/lunr/lunr.fr.js
  28. 1
      assets/javascripts/lunr/lunr.hu.js
  29. 1
      assets/javascripts/lunr/lunr.it.js
  30. 1
      assets/javascripts/lunr/lunr.jp.js
  31. 1
      assets/javascripts/lunr/lunr.multi.js
  32. 1
      assets/javascripts/lunr/lunr.no.js
  33. 1
      assets/javascripts/lunr/lunr.pt.js
  34. 1
      assets/javascripts/lunr/lunr.ro.js
  35. 1
      assets/javascripts/lunr/lunr.ru.js
  36. 1
      assets/javascripts/lunr/lunr.stemmer.support.js
  37. 1
      assets/javascripts/lunr/lunr.sv.js
  38. 1
      assets/javascripts/lunr/lunr.tr.js
  39. 1
      assets/javascripts/lunr/tinyseg.js
  40. 1
      assets/javascripts/modernizr.1aa3b519.js
  41. 1176
      assets/stylesheets/application-palette.22915126.css
  42. 2552
      assets/stylesheets/application.451f80e5.css
  43. 1
      b-captain-hook
  44. 0
      css/custom.css
  45. 1
      d-nginx-subdomains
  46. 42
      docker-compose.yml
  47. 42
      docker-compose.yml.j2
  48. 44
      docs/adding.md
  49. 148
      docs/canary.md
  50. 176
      docs/index.md
  51. 64
      docs/running.md
  52. 93
      docs/services.md
  53. 696
      index.html
  54. 1
      mkdocs-material
  55. 38
      mkdocs.yml
  56. 24
      scripts/Readme.md
  57. 89
      scripts/apply_templates_captainhook.py
  58. 84
      scripts/apply_templates_pod.py
  59. 90
      scripts/apply_templates_subdomains.py
  60. 12
      scripts/captain-hook-canary.service.j2
  61. 47
      scripts/captain_hook_canary.sh.j2
  62. 110
      scripts/captain_hook_pull_host.py.j2
  63. 21
      scripts/executioner.py
  64. 125
      scripts/pages_init_setup.py.j2
  65. 129
      scripts/pages_pull.py.j2
  66. 14
      scripts/pod-webhooks.service.j2
  67. 89
      scripts/subdomains_init_setup.py.j2
  68. 95
      scripts/subdomains_pull.py.j2
  69. 2986
      search/lunr.js
  70. 96
      search/main.js
  71. 1
      search/search_index.json
  72. 128
      search/worker.js
  73. 28
      sitemap.xml
  74. BIN
      sitemap.xml.gz
  75. 6
      utils-www/README.md
  76. 21
      utils-www/clone_into_volume.sh
  77. 22
      utils-www/pull_inside_volume.sh
  78. 32
      utils-www/static_clone.py
  79. 6
      utils-www/static_domains.py
  80. 36
      utils-www/static_pull.py

12
.gitignore vendored

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
#mkdocs
site/
docker-compose.yml
# ignore scripts generated from templates
scripts/pages_init_setup.py
scripts/subdomains_init_setup.py
scripts/captain-hook-canary.service
scripts/captain_hook_canary.sh
scripts/captain_hook_pull_host.py
scripts/pod-webhooks.service
scripts/output/

9
.gitmodules vendored

@ -1,9 +0,0 @@ @@ -1,9 +0,0 @@
[submodule "b-captain-hook"]
path = b-captain-hook
url = https://git.charlesreid1.com/bots/b-captain-hook.git
[submodule "d-nginx-subdomains"]
path = d-nginx-subdomains
url = https://git.charlesreid1.com/docker/d-nginx-subdomains.git
[submodule "mkdocs-material"]
path = mkdocs-material
url = https://git.charlesreid1.com/charlesreid1/mkdocs-material

492
Adding/index.html

@ -0,0 +1,492 @@ @@ -0,0 +1,492 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/pod-webhooks/adding/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="..">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.0.3">
<title>Adding Webhooks - pod-webhooks</title>
<link rel="stylesheet" href="../assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.22915126.css">
<meta name="theme-color" content="#2196f3">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="../assets/fonts/material-icons.css">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="blue" data-md-color-accent="blue">
<svg class="md-svg">
<defs>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="../#adding-new-hooks" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-header-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
pod-webhooks
</span>
<span class="md-header-nav__topic">
Adding Webhooks
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
pod-webhooks
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Home" class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Adding Webhooks
</label>
<a href="./" title="Adding Webhooks" class="md-nav__link md-nav__link--active">
Adding Webhooks
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#adding-new-hooks" title="Adding New Hooks" class="md-nav__link">
Adding New Hooks
</a>
</li>
<li class="md-nav__item">
<a href="#debugging-failed-hooks" title="Debugging Failed Hooks" class="md-nav__link">
Debugging Failed Hooks
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../running/" title="Running Captain Hook" class="md-nav__link">
Running Captain Hook
</a>
</li>
<li class="md-nav__item">
<a href="../services/" title="Captain Hook Startup Services" class="md-nav__link">
Captain Hook Startup Services
</a>
</li>
<li class="md-nav__item">
<a href="../canary/" title="Captain Hook's Canary" class="md-nav__link">
Captain Hook's Canary
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#adding-new-hooks" title="Adding New Hooks" class="md-nav__link">
Adding New Hooks
</a>
</li>
<li class="md-nav__item">
<a href="#debugging-failed-hooks" title="Debugging Failed Hooks" class="md-nav__link">
Debugging Failed Hooks
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1>Adding Webhooks</h1>
<h2 id="adding-new-hooks">Adding New Hooks<a class="headerlink" href="#adding-new-hooks" title="Permanent link">&para;</a></h2>
<p>To add a hook to Captain Hook:</p>
<ol>
<li>
<p>Create an executable script in <a href="https://git.charlesreid1.com/bots/b-captain-hook">bots/b-captain-hook</a>
on git.charlesreid1.com with the name of the action, the name of the repo (not the owner),
and the name of the branch in the filename. For example, <code>push-my-dotfiles-master</code> would be
matched every time I <code>push</code> changes to the <code>master</code> branch of any repository named <code>my-dotfiles</code>.</p>
</li>
<li>
<p>Add, commit, and push your hook to the master branch of Captain Hook</p>
</li>
<li>
<p>Wait about 15 seconds for the canary script to run (it has to update
the Captain Hook git repo running on the remote server to the latest version
and restart the webhooks-subdomains docker pod.)</p>
</li>
<li>
<p>Open the <code>my-dotfiles</code> repository on git.charlesreid1.com, go to the
Settings &gt; Webhooks page, and add a Gitea webhook.</p>
</li>
<li>
<p>Enter info:</p>
<p>a. Payload URL is the Captain Hook server, which is <code>https://hooks.charlesreid1.com/webhook</code>.
b. Content type is <code>application/json</code>
c. Secret is (that's my little secret)
d. Pick what events you would like to trigger webhooks, usually "just the push event"</p>
</li>
<li>
<p>Save the webhook, then click on the webhook again to open it back up.
Scroll down to the bottom right and click "Test Delivery". </p>
</li>
</ol>
<p>You should see a green success sign. </p>
<h2 id="debugging-failed-hooks">Debugging Failed Hooks<a class="headerlink" href="#debugging-failed-hooks" title="Permanent link">&para;</a></h2>
<p>If you see a red warning sign:</p>
<ul>
<li>Ensure the webhooks docker pod is actually running okay (<code>docker ps</code> on the host machine)</li>
<li>Ensure port 5000 is open in the Captain Hook container, and on the host machine</li>
<li>Ensure you can see port 5000 of the <code>pod-webhooks</code> host machine from the <code>pod-charlesreid1</code> host machine</li>
<li>Ensure there is actually a hook in the <code>hooks/</code> directory of the Captain Hook repo</li>
</ul>
<p>Captain Hook repo: <a href="https://git.charlesreid1.com/bots/b-captain-hook">https://git.charlesreid1.com/bots/b-captain-hook</a></p>
<p>Captain Hook repo (Github mirror): <a href="https://github.com/charlesreid1-docker/b-captain-hook">https://github.com/charlesreid1-docker/b-captain-hook</a></p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href=".." title="Home" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Home
</span>
</div>
</a>
<a href="../running/" title="Running Captain Hook" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Running Captain Hook
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 <a href="https://charlesreid1.com">Charles Reid</a>, released under the <a href="https://opensource.org/licenses/MIT">MIT license</a>
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.e72fd936.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
<script src="../search/main.js"></script>
</body>
</html>

580
Canary/index.html

@ -0,0 +1,580 @@ @@ -0,0 +1,580 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/pod-webhooks/canary/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="..">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.0.3">
<title>Captain Hook's Canary - pod-webhooks</title>
<link rel="stylesheet" href="../assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.22915126.css">
<meta name="theme-color" content="#2196f3">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="../assets/fonts/material-icons.css">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="blue" data-md-color-accent="blue">
<svg class="md-svg">
<defs>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="../#captain-hooks-canary" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-header-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
pod-webhooks
</span>
<span class="md-header-nav__topic">
Captain Hook's Canary
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
pod-webhooks
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Home" class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item">
<a href="../adding/" title="Adding Webhooks" class="md-nav__link">
Adding Webhooks
</a>
</li>
<li class="md-nav__item">
<a href="../running/" title="Running Captain Hook" class="md-nav__link">
Running Captain Hook
</a>
</li>
<li class="md-nav__item">
<a href="../services/" title="Captain Hook Startup Services" class="md-nav__link">
Captain Hook Startup Services
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Captain Hook's Canary
</label>
<a href="./" title="Captain Hook's Canary" class="md-nav__link md-nav__link--active">
Captain Hook's Canary
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-canary-bash-script" title="The Canary Bash Script" class="md-nav__link">
The Canary Bash Script
</a>
</li>
<li class="md-nav__item">
<a href="#the-pull-host-captain-hook-script" title="The Pull Host Captain Hook Script" class="md-nav__link">
The Pull Host Captain Hook Script
</a>
</li>
<li class="md-nav__item">
<a href="#the-canary-startup-script" title="The Canary Startup Script" class="md-nav__link">
The Canary Startup Script
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-canary-bash-script" title="The Canary Bash Script" class="md-nav__link">
The Canary Bash Script
</a>
</li>
<li class="md-nav__item">
<a href="#the-pull-host-captain-hook-script" title="The Pull Host Captain Hook Script" class="md-nav__link">
The Pull Host Captain Hook Script
</a>
</li>
<li class="md-nav__item">
<a href="#the-canary-startup-script" title="The Canary Startup Script" class="md-nav__link">
The Canary Startup Script
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="captain-hooks-canary">Captain Hook's Canary<a class="headerlink" href="#captain-hooks-canary" title="Permanent link">&para;</a></h1>
<p>First things first: Captain Hook is the webhook server that
is part of the webhooks docker pod. It receives webhooks
from Github and Gitea and uses them to trigger scrips.
Links to <a href="https://pages.charlesreid1.com/b-captain-hook">documentation</a>
and <a href="https://git.charlesreid1.com/bots/b-captain-hook">code</a>
for Captain Hook.</p>
<p>Captain Hook's Canary is a mechanism by which the Captain Hook
webhooks server (running in a docker container) can trigger an action
on the host machine (running the pod). In this case the action is to
update Captain Hook and restart the docker pod anytime a webhook is
received indicating the Captain Hook repo has changed.</p>
<p>This is done by bind-mounting a host directory at <code>/tmp/triggers/</code>
inside the Captain Hook docker container. When Captain Hook receives
a webhook from Github or Gitea that indicates the Captain Hook
repo (<a href="https://git.charlesreid1.com/bots/b-captain-hook">https://git.charlesreid1.com/bots/b-captain-hook</a> or
<a href="https://github.com/charlesreid1/captain-hook">https://github.com/charlesreid1/captain-hook</a>), it creates a
trigger file.</p>
<p>Meanwhile, on the host that is running the docker pod, a service
script is running continuously to check for that trigger file
every 10 seconds. If the trigger file is seen, it updates the
Captain Hook git repository on the host machine and then restarts
the docker pod.</p>
<p>Sections below cover the following scripts, all run on the host:</p>
<ul>
<li>The canary bash script</li>
<li>The docker host pull script</li>
<li>The canary statup service</li>
</ul>
<h2 id="the-canary-bash-script">The Canary Bash Script<a class="headerlink" href="#the-canary-bash-script" title="Permanent link">&para;</a></h2>
<p>Note: this needs an associated systemd service.
See the services directory of the dotfiles repo.</p>
<p>This is a canary script for connecting
the Captain Hook container to the host
machine, and triggering tasks on the
host machine with webhooks.</p>
<p>The Captain Hook container mounts the
following host directory inside the
container (same location for host/container):</p>
<div class="codehilite"><pre><span></span>/tmp/triggers/
</pre></div>
<p>When a webhook in Captain Hook wants to
trigger an event on the host (blackbeard),
it puts a file in <code>/tmp/triggers/</code>.</p>
<p>Meanwhile, on the host, this script checks
every 10 seconds for trigger files.</p>
<p>Each webhook can create its own trigger file,
and this script processes each trigger differently.</p>
<div class="codehilite"><pre><span></span><span class="ch">#!/bin/bash</span>
<span class="nv">TRIGGER</span><span class="o">=</span><span class="s2">&quot;/tmp/triggers/push-b-captain-hook-master&quot;</span>
<span class="nv">UPDATE_SCRIPT</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">${</span><span class="nv">HOME</span><span class="si">}</span><span class="s2">/pod-webhooks/scripts/captain_hook_pull_host.py&quot;</span>
<span class="k">while</span> <span class="nb">true</span>
<span class="k">do</span>
<span class="c1"># bootstrap-pull captain hook</span>
<span class="k">if</span> <span class="o">[</span> -f <span class="s2">&quot;</span><span class="nv">$TRIGGER</span><span class="s2">&quot;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nb">echo</span> <span class="s2">&quot;CAPTAIN HOOK&#39;S CANARY:&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;Running trigger to update Captain Hook on the host machine (user charles)&quot;</span>
sudo -H -u charles python <span class="nv">$UPDATE_SCRIPT</span>
<span class="nb">echo</span> <span class="s2">&quot;All done.&quot;</span>
rm -f <span class="si">${</span><span class="nv">TRIGGER</span><span class="si">}</span>
<span class="k">fi</span>
sleep <span class="m">10</span><span class="p">;</span>
<span class="k">done</span>
</pre></div>
<h2 id="the-pull-host-captain-hook-script">The Pull Host Captain Hook Script<a class="headerlink" href="#the-pull-host-captain-hook-script" title="Permanent link">&para;</a></h2>
<p>Next we have a python script that actually updates the host's
version of Captain Hook:</p>
<div class="codehilite"><pre><span></span><span class="ch">#!/usr/bin/env python3</span>
<span class="kn">import</span> <span class="nn">subprocess</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Captain Hook: Pull Captain Hook on the Host </span>
<span class="sd">This script is called by the host machine </span>
<span class="sd">(blackbeard) running the Captain Hook container.</span>
<span class="sd">This is triggered by push actions to the </span>
<span class="sd">master branch of b-captain-hook.</span>
<span class="sd">The action is to update (git pull) the copy </span>
<span class="sd">of Captain Hook running on the host, and</span>
<span class="sd">restart the container pod.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="n">work_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s1">&#39;/home&#39;</span><span class="p">,</span><span class="s1">&#39;charles&#39;</span><span class="p">,</span><span class="s1">&#39;pod-webhooks&#39;</span><span class="p">,</span><span class="s1">&#39;b-captain-hook&#39;</span><span class="p">)</span>
<span class="c1"># Step 1:</span>
<span class="c1"># Update Captain Hook</span>
<span class="n">pull_cmd</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;git&#39;</span><span class="p">,</span><span class="s1">&#39;pull&#39;</span><span class="p">,</span><span class="s1">&#39;origin&#39;</span><span class="p">,</span><span class="s1">&#39;master&#39;</span><span class="p">]</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">pull_cmd</span><span class="p">,</span> <span class="n">cwd</span><span class="o">=</span><span class="n">work_dir</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="c1"># Step 2:</span>
<span class="c1"># Restart Captain Hook pod</span>
<span class="n">pod_restart</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;docker-compose&#39;</span><span class="p">,</span><span class="s1">&#39;restart&#39;</span><span class="p">]</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">pod_restart</span><span class="p">,</span> <span class="n">cwd</span><span class="o">=</span><span class="n">work_dir</span><span class="p">)</span>
</pre></div>
<h2 id="the-canary-startup-script">The Canary Startup Script<a class="headerlink" href="#the-canary-startup-script" title="Permanent link">&para;</a></h2>
<p>Here is the startup file that runs the Captain Hook's Canary bash script.</p>
<p>The stop directive uses pgrep to find the process id and stops any PIDs returned.</p>
<div class="codehilite"><pre><span></span>[Unit]
Description=captain hook canary script
Requires=pod-webhooks.service
After=pod-webhooks.service
[Service]
Restart=always
ExecStart=/home/charles/pod-webhooks/scripts/captain_hook_canary.sh
ExecStop=/usr/bin/pgrep -f captain_hook_canary | /usr/bin/xargs /bin/kill
[Install]
WantedBy=default.target
</pre></div>
<p>See <a href="../services/">Services</a> for more info on what to do with this file.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../services/" title="Captain Hook Startup Services" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Captain Hook Startup Services
</span>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 <a href="https://charlesreid1.com">Charles Reid</a>, released under the <a href="https://opensource.org/licenses/MIT">MIT license</a>
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.e72fd936.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
<script src="../search/main.js"></script>
</body>
</html>

19
LICENSE

@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
Copyright (c) 2018 Charles Reid
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
README.md

@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
# pod-webhooks
This docker pod runs two services:
* Captain Hook webhook server (python + flask)
* [b-captain-hook](https://git.charlesreid1.com/bots/b-captain-hook)
* Static content server for subdomain pages (nginx)
* [d-nginx-subdomains](https://git.charlesreid1.com/docker/d-nginx-subdomains)
These two services are in this repo as submodules.
## Links
See documentation page here: <https://pages.charlesreid1.com/pod-webhooks>
Or visit [docs/index.md](/docs/index.md)
Source code on git.charlesreid1.com: <https://git.charlesreid1.com/docker/pod-webhooks>
Source code on github.com: <https://github.com/charlesreid1-docker/pod-webhooks>
## If you get a 403
If you visit the IP of the page running things and you get a 403,
it's probably because you haven't created the `/www/` directory
structure yet.
To do this, you need a folder for each subdomain at `/www/`, along
with subdirectories for `htdocs` and for the `.git` directory
(see `scripts/` directory for scripts to do this automatically):
```
/www/pages.charlesreid1.com/
/www/bots.charlesreid1.com/
/www/hooks.charlesreid1.com/
```

513
Running/index.html

@ -0,0 +1,513 @@ @@ -0,0 +1,513 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/pod-webhooks/running/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="..">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.0.3">
<title>Running Captain Hook - pod-webhooks</title>
<link rel="stylesheet" href="../assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.22915126.css">
<meta name="theme-color" content="#2196f3">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="../assets/fonts/material-icons.css">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="blue" data-md-color-accent="blue">
<svg class="md-svg">
<defs>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="../#the-docker-compose-file" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-header-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
pod-webhooks
</span>
<span class="md-header-nav__topic">
Running Captain Hook
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
pod-webhooks
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Home" class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item">
<a href="../adding/" title="Adding Webhooks" class="md-nav__link">
Adding Webhooks
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Running Captain Hook
</label>
<a href="./" title="Running Captain Hook" class="md-nav__link md-nav__link--active">
Running Captain Hook
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-docker-compose-file" title="The Docker Compose File" class="md-nav__link">
The Docker Compose File
</a>
</li>
<li class="md-nav__item">
<a href="#running-webhooks-docker-pod-from-command-line" title="Running Webhooks Docker Pod from Command Line" class="md-nav__link">
Running Webhooks Docker Pod from Command Line
</a>
</li>
<li class="md-nav__item">
<a href="#workflow-for-docker-pod-updates" title="Workflow for Docker Pod Updates" class="md-nav__link">
Workflow for Docker Pod Updates
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../services/" title="Captain Hook Startup Services" class="md-nav__link">
Captain Hook Startup Services
</a>
</li>
<li class="md-nav__item">
<a href="../canary/" title="Captain Hook's Canary" class="md-nav__link">
Captain Hook's Canary
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-docker-compose-file" title="The Docker Compose File" class="md-nav__link">
The Docker Compose File
</a>
</li>
<li class="md-nav__item">
<a href="#running-webhooks-docker-pod-from-command-line" title="Running Webhooks Docker Pod from Command Line" class="md-nav__link">
Running Webhooks Docker Pod from Command Line
</a>
</li>
<li class="md-nav__item">
<a href="#workflow-for-docker-pod-updates" title="Workflow for Docker Pod Updates" class="md-nav__link">
Workflow for Docker Pod Updates
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1>Running Captain Hook</h1>
<h2 id="the-docker-compose-file">The Docker Compose File<a class="headerlink" href="#the-docker-compose-file" title="Permanent link">&para;</a></h2>
<p>The <code>docker-compose.yml</code> file contains everything needed to
run the webhooks docker pod: a Captain Hook webhook server, and
an nginx server to serve up static pages for each subdomain.</p>
<p>Why use docker-compose instead of docker?
docker-compose is the preferred way to run multiple containers.</p>
<h2 id="running-webhooks-docker-pod-from-command-line">Running Webhooks Docker Pod from Command Line<a class="headerlink" href="#running-webhooks-docker-pod-from-command-line" title="Permanent link">&para;</a></h2>
<p>Run the pod in the foreground or background by running these
commands from the directory containing <code>docker-compose.yml</code>:</p>
<div class="codehilite"><pre><span></span>docker-compose up # interactive
docker-compose up -d # detached
</pre></div>
<p>If you want to rebuild all the containers before bringing
the pod up, add the <code>--build</code> flag:</p>
<div class="codehilite"><pre><span></span>docker-compose up --build
</pre></div>
<p>If you just want to rebuild the containers without bringing
them up,</p>
<div class="codehilite"><pre><span></span>docker-compose build
</pre></div>
<p>To rebuild absolutely everything from scratch,</p>
<div class="codehilite"><pre><span></span>docker-compose build --no-cache
</pre></div>
<p><strong><em>WARNING:</em></strong> this will re-download all aptitude packages,
which can be extremely slow. Use with caution.</p>
<p>You can restart all containers in a pod using the restart command:</p>
<div class="codehilite"><pre><span></span>docker-compose restart
</pre></div>
<p><strong><em>WARNING:</em></strong> this will <strong><em>NOT</em></strong> pick up changes to
Dockerfiles or to files that are mounted into the container.
This simply restarts the container using the same image
(in memory) that was previously running, <strong><em>without</em></strong>
getting an up-to-date container image.</p>
<h2 id="workflow-for-docker-pod-updates">Workflow for Docker Pod Updates<a class="headerlink" href="#workflow-for-docker-pod-updates" title="Permanent link">&para;</a></h2>
<p>To minimize downtime, use the following workflow:</p>
<ul>
<li>Run <code>docker-compose build</code> to rebuild the images, leaving the pod running (they are not affected)</li>
<li>Run <code>docker-compose down</code> to bring the pod down</li>
<li>Run <code>docker-compose up</code> to bring the pod up</li>
</ul>
<p>(Add the <code>-d</code> flag to start the docker pod in the background.)</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../adding/" title="Adding Webhooks" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Adding Webhooks
</span>
</div>
</a>
<a href="../services/" title="Captain Hook Startup Services" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Captain Hook Startup Services
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 <a href="https://charlesreid1.com">Charles Reid</a>, released under the <a href="https://opensource.org/licenses/MIT">MIT license</a>
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.e72fd936.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
<script src="../search/main.js"></script>
</body>
</html>

568
Services/index.html

@ -0,0 +1,568 @@ @@ -0,0 +1,568 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/pod-webhooks/services/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="..">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.0.3">
<title>Captain Hook Startup Services - pod-webhooks</title>
<link rel="stylesheet" href="../assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.22915126.css">
<meta name="theme-color" content="#2196f3">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="../assets/fonts/material-icons.css">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="blue" data-md-color-accent="blue">
<svg class="md-svg">
<defs>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="../#running-hooks-subdomains-docker-pod-as-startup-service" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-header-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
pod-webhooks
</span>
<span class="md-header-nav__topic">
Captain Hook Startup Services
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
pod-webhooks
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Home" class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item">
<a href="../adding/" title="Adding Webhooks" class="md-nav__link">
Adding Webhooks
</a>
</li>
<li class="md-nav__item">
<a href="../running/" title="Running Captain Hook" class="md-nav__link">
Running Captain Hook
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Captain Hook Startup Services
</label>
<a href="./" title="Captain Hook Startup Services" class="md-nav__link md-nav__link--active">
Captain Hook Startup Services
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#running-hooks-subdomains-docker-pod-as-startup-service" title="Running Hooks-Subdomains Docker Pod as Startup Service" class="md-nav__link">
Running Hooks-Subdomains Docker Pod as Startup Service
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#docker-pod-startup-service" title="Docker Pod Startup Service" class="md-nav__link">
Docker Pod Startup Service
</a>
</li>
<li class="md-nav__item">
<a href="#captain-hooks-canary-startup-service" title="Captain Hook's Canary Startup Service" class="md-nav__link">
Captain Hook's Canary Startup Service
</a>
</li>
<li class="md-nav__item">
<a href="#installing-services" title="Installing Services" class="md-nav__link">
Installing Services
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../canary/" title="Captain Hook's Canary" class="md-nav__link">
Captain Hook's Canary
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#running-hooks-subdomains-docker-pod-as-startup-service" title="Running Hooks-Subdomains Docker Pod as Startup Service" class="md-nav__link">
Running Hooks-Subdomains Docker Pod as Startup Service
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#docker-pod-startup-service" title="Docker Pod Startup Service" class="md-nav__link">
Docker Pod Startup Service
</a>
</li>
<li class="md-nav__item">
<a href="#captain-hooks-canary-startup-service" title="Captain Hook's Canary Startup Service" class="md-nav__link">
Captain Hook's Canary Startup Service
</a>
</li>
<li class="md-nav__item">
<a href="#installing-services" title="Installing Services" class="md-nav__link">
Installing Services
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1>Captain Hook Startup Services</h1>
<h2 id="running-hooks-subdomains-docker-pod-as-startup-service">Running Hooks-Subdomains Docker Pod as Startup Service<a class="headerlink" href="#running-hooks-subdomains-docker-pod-as-startup-service" title="Permanent link">&para;</a></h2>
<p>The webhooks-subdomains docker pod requires two startup
services:</p>
<ul>
<li>
<p>Docker pod service - this startup service keeps the pod running,
and will restart it if it crashes</p>
</li>
<li>
<p>Captain Hook's canary - this watches a folder that is shared between
the docker pod host and the Captain Hook container, which allows the
pod to send triggers to the host.</p>
</li>
</ul>
<p>Also see the <code>scripts/</code> folder of this repo,
<a href="https://git.charlesreid1.com/docker/pod-webhooks">pod-webhooks</a>
(<a href="https://github.com/charlesreid1-docker/pod-webhooks">Github mirror</a>).</p>
<h3 id="docker-pod-startup-service">Docker Pod Startup Service<a class="headerlink" href="#docker-pod-startup-service" title="Permanent link">&para;</a></h3>
<p>This service keeps the webhooks docker pod service running
continuously. If the pod stops, this service will restart it.</p>
<p>(This service should not be running if you are troubleshooting
the docker pod, otherwise every time you try and stop the pod
it will respawn.)</p>
<p><strong><code>pod-webhooks.service:</code></strong></p>
<div class="codehilite"><pre><span></span>[Unit]
Description=webhooks and subdomains docker pod
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/local/bin/docker-compose -f /home/charles/codes/docker/pod-webhooks/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f /home/charles/codes/docker/pod-webhooks/docker-compose.yml down
[Install]
WantedBy=default.target
</pre></div>
<h3 id="captain-hooks-canary-startup-service">Captain Hook's Canary Startup Service<a class="headerlink" href="#captain-hooks-canary-startup-service" title="Permanent link">&para;</a></h3>
<p>This service just watches a folder for a particular
watchfile, and runs a script if it sees the watchfile
appear.</p>
<p><strong><code>captain-hook-canary.service:</code></strong></p>
<div class="codehilite"><pre><span></span>[Unit]
Description=captain hook canary script
Requires=pod-webhooks.service
After=pod-webhooks.service
[Service]
Restart=always
ExecStart=/home/charles/pod-webhooks/scripts/captain_hook_canary.sh
ExecStop=/usr/bin/pgrep -f captain_hook_canary | /usr/bin/xargs /bin/kill
[Install]
WantedBy=default.target
</pre></div>
<h3 id="installing-services">Installing Services<a class="headerlink" href="#installing-services" title="Permanent link">&para;</a></h3>
<p>Install the services by copying the <code>*.service</code> files
to <code>/etc/systemd/system/dockerpod-webhooks.servce</code>
and <code>/etc/systemd/system/captain-hook-canary.servce</code>,
and activate the startup services:</p>
<div class="codehilite"><pre><span></span>sudo systemctl enable pod-webhooks.service
sudo systemctl enable captain-hook-canary.service
</pre></div>
<p>Now you can start/stop the services with:</p>
<div class="codehilite"><pre><span></span>sudo systemctl (start|stop) pod-webhooks.service
sudo systemctl (start|stop) captain-hook-canary.service
</pre></div>
<p>As mentioned above, these services should be stopped before
doing a <code>docker-compose stop</code> or a <code>docker-compose up --build</code>
to keep the pod from respawning in the middle of the task.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../running/" title="Running Captain Hook" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Running Captain Hook
</span>
</div>
</a>
<a href="../canary/" title="Captain Hook's Canary" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Captain Hook's Canary
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 <a href="https://charlesreid1.com">Charles Reid</a>, released under the <a href="https://opensource.org/licenses/MIT">MIT license</a>
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.e72fd936.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
<script src="../search/main.js"></script>
</body>
</html>

4
assets/fonts/font-awesome.css vendored

File diff suppressed because one or more lines are too long

13
assets/fonts/material-icons.css

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
/*!
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE
* DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
* SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND
* LIMITATIONS UNDER THE LICENSE.
*/@font-face{font-family:"Material Icons";font-style:normal;font-weight:400;src:local("Material Icons"),local("MaterialIcons-Regular"),url("specimen/MaterialIcons-Regular.woff2") format("woff2"),url("specimen/MaterialIcons-Regular.woff") format("woff"),url("specimen/MaterialIcons-Regular.ttf") format("truetype")}

BIN
assets/fonts/specimen/FontAwesome.ttf

Binary file not shown.

BIN
assets/fonts/specimen/FontAwesome.woff

Binary file not shown.

BIN
assets/fonts/specimen/FontAwesome.woff2

Binary file not shown.

BIN
assets/fonts/specimen/MaterialIcons-Regular.ttf

Binary file not shown.

BIN
assets/fonts/specimen/MaterialIcons-Regular.woff

Binary file not shown.

BIN
assets/fonts/specimen/MaterialIcons-Regular.woff2

Binary file not shown.

BIN
assets/images/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

20
assets/images/icons/bitbucket.1b09e088.svg

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448"
viewBox="0 0 352 448" id="__bitbucket">
<path fill="currentColor" d="M203.75 214.75q2 15.75-12.625 25.25t-27.875
1.5q-9.75-4.25-13.375-14.5t-0.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875
6.875 16.875zM231.5 209.5q-3.5-26.75-28.25-41t-49.25-3.25q-15.75
7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2
38-21t12.5-42zM291.25
74q-5-6.75-14-11.125t-14.5-5.5-17.75-3.125q-72.75-11.75-141.5 0.5-10.75
1.75-16.5 3t-13.75 5.5-12.5 10.75q7.5 7 19 11.375t18.375 5.5 21.875
2.875q57 7.25 112 0.25 15.75-2 22.375-3t18.125-5.375 18.75-11.625zM305.5
332.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5
12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5t-19.125-6.75-18.25-10.875-13-15.375q-6.25-24-14.25-73l1.5-4
4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2
9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875
10-13.625 7.75q-63 31.5-152.5
22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875-1.375-8.75q-2.25-12.5-6.625-37.5t-7-40.375-5.875-36.875-5.5-39.5q0.75-6.5
4.375-12.125t7.875-9.375 11.25-7.5 11.5-5.625 12-4.625q31.25-11.5
78.25-16 94.75-9.25 169 12.5 38.75 11.5 53.75 30.5 4 5 4.125
12.75t-1.375 13.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

18
assets/images/icons/github.f0b8504a.svg

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="__github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

38
assets/images/icons/gitlab.6dd19c00.svg

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"
viewBox="0 0 500 500" id="__gitlab">
<g transform="translate(156.197863, 1.160267)">
<path fill="currentColor"
d="M93.667,473.347L93.667,473.347l90.684-279.097H2.983L93.667,
473.347L93.667,473.347z" />
</g>
<g transform="translate(28.531199, 1.160800)" opacity="0.7">
<path fill="currentColor"
d="M221.333,473.345L130.649,194.25H3.557L221.333,473.345L221.333,
473.345z" />
</g>
<g transform="translate(0.088533, 0.255867)" opacity="0.5">
<path fill="currentColor"
d="M32,195.155L32,195.155L4.441,279.97c-2.513,7.735,0.24,16.21,6.821,
20.99l238.514,173.29 L32,195.155L32,195.155z" />
</g>
<g transform="translate(29.421866, 280.255593)">
<path fill="currentColor"
d="M2.667-84.844h127.092L75.14-252.942c-2.811-8.649-15.047-8.649-17.856,
0L2.667-84.844 L2.667-84.844z" />
</g>
<g transform="translate(247.197860, 1.160800)" opacity="0.7">
<path fill="currentColor"
d="M2.667,473.345L93.351,194.25h127.092L2.667,473.345L2.667,
473.345z" />
</g>
<g transform="translate(246.307061, 0.255867)" opacity="0.5">
<path fill="currentColor"
d="M221.334,195.155L221.334,195.155l27.559,84.815c2.514,7.735-0.24,
16.21-6.821,20.99 L3.557,474.25L221.334,195.155L221.334,195.155z" />
</g>
<g transform="translate(336.973725, 280.255593)">
<path fill="currentColor"
d="M130.667-84.844H3.575l54.618-168.098c2.811-8.649,15.047-8.649,
17.856,0L130.667-84.844 L130.667-84.844z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
assets/javascripts/application.e72fd936.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.da.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,i,n;e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=(r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,t,s=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],o=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],u=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],c=new i;function l(){var e,r=c.limit-c.cursor;c.cursor>=n&&(e=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.find_among_b(o,4)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e)}this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var r,i=c.cursor;return function(){var r,i=c.cursor+3;if(n=c.limit,0<=i&&i<=c.limit){for(e=i;;){if(r=c.cursor,c.in_grouping(d,97,248)){c.cursor=r;break}if(c.cursor=r,r>=c.limit)return;c.cursor++}for(;!c.out_grouping(d,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(n=c.cursor)<e&&(n=e)}}(),c.limit_backward=i,c.cursor=c.limit,function(){var e,r;if(c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(s,32),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:c.in_grouping_b(u,97,229)&&c.slice_del()}}(),c.cursor=c.limit,l(),c.cursor=c.limit,function(){var e,r,i,t=c.limit-c.cursor;if(c.ket=c.cursor,c.eq_s_b(2,"st")&&(c.bra=c.cursor,c.eq_s_b(2,"ig")&&c.slice_del()),c.cursor=c.limit-t,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(a,5),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del(),i=c.limit-c.cursor,l(),c.cursor=c.limit-i;break;case 2:c.slice_from("løs")}}(),c.cursor=c.limit,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.out_grouping_b(d,97,248)?(c.bra=c.cursor,t=c.slice_to(t),c.limit_backward=r,c.eq_v_b(t)&&c.slice_del()):c.limit_backward=r),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});

1
assets/javascripts/lunr/lunr.de.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.du.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.es.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.fi.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.fr.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.hu.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.it.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.jp.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.jp=function(){this.pipeline.reset(),this.pipeline.add(e.jp.stopWordFilter,e.jp.stemmer),r?this.tokenizer=e.jp.tokenizer:(e.tokenizer&&(e.tokenizer=e.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.jp.tokenizer))};var t=new e.TinySegmenter;e.jp.tokenizer=function(n){if(!arguments.length||null==n||null==n)return[];if(Array.isArray(n))return n.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(var i=n.toString().toLowerCase().replace(/^\s+/,""),o=i.length-1;o>=0;o--)if(/\S/.test(i.charAt(o))){i=i.substring(0,o+1);break}return t.segment(i).filter(function(e){return!!e}).map(function(t){return r?new e.Token(t):t})},e.jp.stemmer=function(e){return e},e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.jp.stopWordFilter=function(t){if(-1===e.jp.stopWordFilter.stopWords.indexOf(r?t.toString():t))return t},e.jp.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}});

1
assets/javascripts/lunr/lunr.multi.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var i=Array.prototype.slice.call(arguments),t=i.join("-"),r="",n=[],s=[],p=0;p<i.length;++p)"en"==i[p]?(r+="\\w",n.unshift(e.stopWordFilter),n.push(e.stemmer),s.push(e.stemmer)):(r+=e[i[p]].wordCharacters,n.unshift(e[i[p]].stopWordFilter),n.push(e[i[p]].stemmer),s.push(e[i[p]].stemmer));var o=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(o,"lunr-multi-trimmer-"+t),n.unshift(o),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,n),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,s))}}}});

1
assets/javascripts/lunr/lunr.no.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,i;e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){var e,i,t=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],o=[new r("dt",-1,-1),new r("vt",-1,-1)],s=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],a=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],m=[119,125,149,1],l=new n;this.setCurrent=function(e){l.setCurrent(e)},this.getCurrent=function(){return l.getCurrent()},this.stem=function(){var r,n,u,d,c=l.cursor;return function(){var r,n=l.cursor+3;if(i=l.limit,0<=n||n<=l.limit){for(e=n;;){if(r=l.cursor,l.in_grouping(a,97,248)){l.cursor=r;break}if(r>=l.limit)return;l.cursor=r+1}for(;!l.out_grouping(a,97,248);){if(l.cursor>=l.limit)return;l.cursor++}(i=l.cursor)<e&&(i=e)}}(),l.limit_backward=c,l.cursor=l.limit,function(){var e,r,n;if(l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,e=l.find_among_b(t,29),l.limit_backward=r,e))switch(l.bra=l.cursor,e){case 1:l.slice_del();break;case 2:n=l.limit-l.cursor,l.in_grouping_b(m,98,122)?l.slice_del():(l.cursor=l.limit-n,l.eq_s_b(1,"k")&&l.out_grouping_b(a,97,248)&&l.slice_del());break;case 3:l.slice_from("er")}}(),l.cursor=l.limit,n=l.limit-l.cursor,l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,l.find_among_b(o,2)?(l.bra=l.cursor,l.limit_backward=r,l.cursor=l.limit-n,l.cursor>l.limit_backward&&(l.cursor--,l.bra=l.cursor,l.slice_del())):l.limit_backward=r),l.cursor=l.limit,l.cursor>=i&&(d=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,(u=l.find_among_b(s,11))?(l.bra=l.cursor,l.limit_backward=d,1==u&&l.slice_del()):l.limit_backward=d),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});

1
assets/javascripts/lunr/lunr.pt.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.ro.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.ru.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.stemmer.support.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s<t;s++)i[s]=r.charCodeAt(s);return i},!r&&""!=r||!t&&0!=t||!i)throw"Bad Among initialisation: s:"+r+", substring_i: "+t+", result: "+i;this.s_size=r.length,this.s=this.toCharArray(r),this.substring_i=t,this.result=i,this.method=s},SnowballProgram:function(){var r;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){r=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=r;return r=null,t},in_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e>s||e<i)return this.cursor++,!0;if(!(t[(e-=i)>>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e<i)return this.cursor--,!0;if(!(t[(e-=i)>>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor+s)!=i.charCodeAt(s))return!1;return this.cursor+=t,!0},eq_s_b:function(t,i){if(this.cursor-this.limit_backward<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor-t+s)!=i.charCodeAt(s))return!1;return this.cursor-=t,!0},find_among:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=l;m<_.s_size;m++){if(n+l==u){f=-1;break}if(f=r.charCodeAt(n+l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){if(o>=(_=t[s]).s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=(m=t[a]).s_size-1-l;_>=0;_--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-m.s[_])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var m;if(o>=(m=t[s]).s_size){if(this.cursor=n-m.s_size,!m.method)return m.result;var b=m.method();if(this.cursor=n-m.s_size,b)return m.result}if((s=m.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}});

1
assets/javascripts/lunr/lunr.sv.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,t;e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){var e,t,i=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],s=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],o=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],u=[119,127,149],m=new n;this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var r,n=m.cursor;return function(){var r,n=m.cursor+3;if(t=m.limit,0<=n||n<=m.limit){for(e=n;;){if(r=m.cursor,m.in_grouping(o,97,246)){m.cursor=r;break}if(m.cursor=r,m.cursor>=m.limit)return;m.cursor++}for(;!m.out_grouping(o,97,246);){if(m.cursor>=m.limit)return;m.cursor++}(t=m.cursor)<e&&(t=e)}}(),m.limit_backward=n,m.cursor=m.limit,function(){var e,r=m.limit_backward;if(m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(i,37),m.limit_backward=r,e))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.in_grouping_b(u,98,121)&&m.slice_del()}}(),m.cursor=m.limit,r=m.limit_backward,m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.find_among_b(s,7)&&(m.cursor=m.limit,m.ket=m.cursor,m.cursor>m.limit_backward&&(m.bra=--m.cursor,m.slice_del())),m.limit_backward=r),m.cursor=m.limit,function(){var e,r;if(m.cursor>=t){if(r=m.limit_backward,m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(a,5))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.slice_from("lös");break;case 3:m.slice_from("full")}m.limit_backward=r}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});

1
assets/javascripts/lunr/lunr.tr.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/tinyseg.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/modernizr.1aa3b519.js

File diff suppressed because one or more lines are too long

1176
assets/stylesheets/application-palette.22915126.css

File diff suppressed because it is too large Load Diff

2552
assets/stylesheets/application.451f80e5.css

File diff suppressed because it is too large Load Diff

1
b-captain-hook

@ -1 +0,0 @@ @@ -1 +0,0 @@
Subproject commit 361f59c21a733a484f48e9bd60bce2d94dbf7b1b

0
docs/css/custom.css → css/custom.css

1
d-nginx-subdomains

@ -1 +0,0 @@ @@ -1 +0,0 @@
Subproject commit a87dcd5f3d997596c87deec03d396f0911b4b03f

42
docker-compose.yml

@ -1,42 +0,0 @@ @@ -1,42 +0,0 @@
version: "3.3"
services:
stormy_nginx_subs:
restart: always
image: nginx
command: /bin/bash -c "nginx -g 'daemon off;'"
volumes:
- "./d-nginx-subdomains/conf.d:/etc/nginx/conf.d"
- "/www/pages.charlesreid1.red/htdocs:/www/pages.charlesreid1.red/htdocs:ro"
- "/www/hooks.charlesreid1.red/htdocs:/www/hooks.charlesreid1.red/htdocs:ro"
- "/www/bots.charlesreid1.red/htdocs:/www/bots.charlesreid1.red/htdocs:ro"
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "10"
ports:
- "7777:7777"
- "7778:7778"
- "7779:7779"
stormy_captain_hook:
restart: always
build: b-captain-hook
volumes:
- "/www/pages.charlesreid1.red:/www/pages.charlesreid1.red"
- "/www/hooks.charlesreid1.red:/www/hooks.charlesreid1.red"
- "/www/bots.charlesreid1.red:/www/bots.charlesreid1.red"
- "/tmp/triggers:/tmp/triggers"
- "./b-captain-hook/config.json:/app/config.json"
- "./b-captain-hook/hooks:/app/hooks"
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "10"
ports:
- "5000:5000"
depends_on:
- stormy_nginx_subs

42
docker-compose.yml.j2

@ -1,42 +0,0 @@ @@ -1,42 +0,0 @@
version: "3.3"
services:
stormy_nginx_subs:
restart: always
image: nginx
command: /bin/bash -c "nginx -g 'daemon off;'"
volumes:
- "./d-nginx-subdomains/conf.d:/etc/nginx/conf.d"
- "/www/pages.{{ server_name_default }}/htdocs:/www/pages.{{ server_name_default }}/htdocs:ro"
- "/www/hooks.{{ server_name_default }}/htdocs:/www/hooks.{{ server_name_default }}/htdocs:ro"
- "/www/bots.{{ server_name_default }}/htdocs:/www/bots.{{ server_name_default }}/htdocs:ro"
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "10"
ports:
- "7777:7777"
- "7778:7778"
- "7779:7779"
stormy_captain_hook:
restart: always
build: b-captain-hook
volumes:
- "/www/pages.{{ server_name_default }}:/www/pages.{{ server_name_default }}"
- "/www/hooks.{{ server_name_default }}:/www/hooks.{{ server_name_default }}"
- "/www/bots.{{ server_name_default }}:/www/bots.{{ server_name_default }}"
- "/tmp/triggers:/tmp/triggers"
- "./b-captain-hook/config.json:/app/config.json"
- "./b-captain-hook/hooks:/app/hooks"
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "10"
ports:
- "5000:5000"
depends_on:
- stormy_nginx_subs

44
docs/adding.md

@ -1,44 +0,0 @@ @@ -1,44 +0,0 @@
## Adding New Hooks
To add a hook to Captain Hook:
1. Create an executable script in [bots/b-captain-hook](https://git.charlesreid1.com/bots/b-captain-hook)
on git.charlesreid1.com with the name of the action, the name of the repo (not the owner),
and the name of the branch in the filename. For example, `push-my-dotfiles-master` would be
matched every time I `push` changes to the `master` branch of any repository named `my-dotfiles`.
2. Add, commit, and push your hook to the master branch of Captain Hook
3. Wait about 15 seconds for the canary script to run (it has to update
the Captain Hook git repo running on the remote server to the latest version
and restart the webhooks-subdomains docker pod.)
4. Open the `my-dotfiles` repository on git.charlesreid1.com, go to the
Settings > Webhooks page, and add a Gitea webhook.
5. Enter info:
a. Payload URL is the Captain Hook server, which is `https://hooks.charlesreid1.com/webhook`.
b. Content type is `application/json`
c. Secret is (that's my little secret)
d. Pick what events you would like to trigger webhooks, usually "just the push event"
6. Save the webhook, then click on the webhook again to open it back up.
Scroll down to the bottom right and click "Test Delivery".
You should see a green success sign.
## Debugging Failed Hooks
If you see a red warning sign:
* Ensure the webhooks docker pod is actually running okay (`docker ps` on the host machine)
* Ensure port 5000 is open in the Captain Hook container, and on the host machine
* Ensure you can see port 5000 of the `pod-webhooks` host machine from the `pod-charlesreid1` host machine
* Ensure there is actually a hook in the `hooks/` directory of the Captain Hook repo
Captain Hook repo: <https://git.charlesreid1.com/bots/b-captain-hook>
Captain Hook repo (Github mirror): <https://github.com/charlesreid1-docker/b-captain-hook>

148
docs/canary.md

@ -1,148 +0,0 @@ @@ -1,148 +0,0 @@
# Captain Hook's Canary
First things first: Captain Hook is the webhook server that
is part of the webhooks docker pod. It receives webhooks
from Github and Gitea and uses them to trigger scrips.
Links to [documentation](https://pages.charlesreid1.com/b-captain-hook)
and [code](https://git.charlesreid1.com/bots/b-captain-hook)
for Captain Hook.
Captain Hook's Canary is a mechanism by which the Captain Hook
webhooks server (running in a docker container) can trigger an action
on the host machine (running the pod). In this case the action is to
update Captain Hook and restart the docker pod anytime a webhook is
received indicating the Captain Hook repo has changed.
This is done by bind-mounting a host directory at `/tmp/triggers/`
inside the Captain Hook docker container. When Captain Hook receives
a webhook from Github or Gitea that indicates the Captain Hook
repo (<https://git.charlesreid1.com/bots/b-captain-hook> or
<https://github.com/charlesreid1/captain-hook>), it creates a
trigger file.
Meanwhile, on the host that is running the docker pod, a service
script is running continuously to check for that trigger file
every 10 seconds. If the trigger file is seen, it updates the
Captain Hook git repository on the host machine and then restarts
the docker pod.
Sections below cover the following scripts, all run on the host:
* The canary bash script
* The docker host pull script
* The canary statup service
## The Canary Bash Script
Note: this needs an associated systemd service.
See the services directory of the dotfiles repo.
This is a canary script for connecting
the Captain Hook container to the host
machine, and triggering tasks on the
host machine with webhooks.
The Captain Hook container mounts the
following host directory inside the
container (same location for host/container):
```
/tmp/triggers/
```
When a webhook in Captain Hook wants to
trigger an event on the host (blackbeard),
it puts a file in `/tmp/triggers/`.
Meanwhile, on the host, this script checks
every 10 seconds for trigger files.
Each webhook can create its own trigger file,
and this script processes each trigger differently.
```bash
#!/bin/bash
TRIGGER="/tmp/triggers/push-b-captain-hook-master"
UPDATE_SCRIPT="${HOME}/pod-webhooks/scripts/captain_hook_pull_host.py"
while true
do
# bootstrap-pull captain hook
if [ -f "$TRIGGER" ]; then
echo "CAPTAIN HOOK'S CANARY:"
echo "Running trigger to update Captain Hook on the host machine (user charles)"
sudo -H -u charles python $UPDATE_SCRIPT
echo "All done."
rm -f ${TRIGGER}
fi
sleep 10;
done
```
## The Pull Host Captain Hook Script
Next we have a python script that actually updates the host's
version of Captain Hook:
```python
#!/usr/bin/env python3
import subprocess
import os
import time
"""
Captain Hook: Pull Captain Hook on the Host
This script is called by the host machine
(blackbeard) running the Captain Hook container.
This is triggered by push actions to the
master branch of b-captain-hook.
The action is to update (git pull) the copy
of Captain Hook running on the host, and
restart the container pod.
"""
work_dir = os.path.join('/home','charles','pod-webhooks','b-captain-hook')
# Step 1:
# Update Captain Hook
pull_cmd = ['git','pull','origin','master']
subprocess.call(pull_cmd, cwd=work_dir)
time.sleep(5)
# Step 2:
# Restart Captain Hook pod
pod_restart = ['docker-compose','restart']
subprocess.call(pod_restart, cwd=work_dir)
```
## The Canary Startup Script
Here is the startup file that runs the Captain Hook's Canary bash script.
The stop directive uses pgrep to find the process id and stops any PIDs returned.
```
[Unit]
Description=captain hook canary script
Requires=pod-webhooks.service
After=pod-webhooks.service
[Service]
Restart=always
ExecStart=/home/charles/pod-webhooks/scripts/captain_hook_canary.sh
ExecStop=/usr/bin/pgrep -f captain_hook_canary | /usr/bin/xargs /bin/kill
[Install]
WantedBy=default.target
```
See [Services](services.md) for more info on what to do with this file.

176
docs/index.md

@ -1,176 +0,0 @@ @@ -1,176 +0,0 @@
# pod-webhooks
This docker pod runs two services:
* Captain Hook webhook server (python + flask)
* [b-captain-hook](https://git.charlesreid1.com/bots/b-captain-hook)
* Static content server for subdomain pages (nginx)
* [d-nginx-subdomains](https://git.charlesreid1.com/docker/d-nginx-subdomains)
These two services are in this repo as submodules.
## Links
See documentation page here: <https://pages.charlesreid1.com/pod-webhooks>
Source code on git.charlesreid1.com: <https://git.charlesreid1.com/docker/pod-webhooks>
Source code on github.com: <https://github.com/charlesreid1-docker/pod-webhooks>
## Initial Setup of Pages Subdomain
The pages.charlesreid1.com subdomain is served from content
in the directory `/www/pages.charlesreid1.com`.
To set this up with pages and sites that should exist already,
use the set up script at `scripts/pages_init_setup.py` and
run it on the pages.charlesreid1.com server:
```
python scripts/pages_init_setup.py
```
This will create the `/www/pages.charlesreid1.com/` directory
structure and will clone several repositories to populate it
with content.
## Adding Hooks
Since this is probably the only thing you'll care about once everything
is actually running... until it breaks.
[How To Add A Hook](adding.md)
## How It Works
See [Running.md](running.md) for info about running this docker pod.
* Running the Docker Pod from Comand Line
* Workflow for Docker Pod Updates
See [Services.md](services.md) for info about running startup services.
* Running the Docker Pod as a Startup Service
* Running Captain Hook's Canary (Script)
Enable/disable service (installs/uninstalls, but does not start):
```
sudo systemctl (enable|disable) pod-webhooks.service
sudo systemctl (enable|disable) captain-hook-canary.service
```
Start/stop:
```
sudo systemctl (start|stop) pod-webhooks.service
sudo systemctl (start|stop) captain-hook-canary.service
```
See [Captain Hook's Canary](canary.md) for details on the canary script that allows the
webhooks docker pod to trigger itself to be re-loaded when there are new hooks
added to captain hook.
## Volumes and Files
### Subdomains
The static files hosted on charlesreid1.com subdomains are contained in
subdirectories of `/www/*.charlesreid1.com/` and this is
mounted by the subdomains docker container that has rules
set up for which subdomains to serve.
### Captain Hook
Captain Hook mounts the `/www` folder, which is served by the subdomains
nginx server, as well as the hooks folder in the Captain Hook repository
(that's at `b-captain-hook/hooks`).
When there is a change pushed to a particular branch on git.charlesreid1.com,
the git.charlesreid1.com server will check if there is a corresponding hook that's
been added to Captain Hook for that repo and branch. If so, git.charlesreid1.com
runs that script. For pages.charlesreid1.com, that's usually just a git pull
on the contents of `/www/pages.charlesreid1.com/my-page`.
### Captain Hook's Canary
Captain Hook presents a bit of a paradox: what happens when Captain Hook installs
a hook for itself, and detects that Captain Hook itself has changed?
In this case, the webhooks docker pod needs to be able to tell the host machine
to restart the webhooks docker pod.
This is done by Captain Hook's Canary. This is a service script that checks every
10 seconds for a trigger file in a directory mounted between the host and container.
If the trigger file is present, the host will update its copy of Captain Hook,
then restart the webhooks-subdomains docker pod.
As per the [dotfiles/debian](https://git.charlesreid1.com/dotfiles/debian) repo,
the `captain_hook_canary.sh` canary will restart the webhooks docker pod if it
detects the presence following file:
```
/tmp/triggers/push-b-captain-hook-master
```
(The canary script will remove this file once it has restarted the webhooks docker pod.)
Now, a hook can be added to Captain Hook that will be run when there is a push event
on the master branch of [bots/b-captain-hook](https://git.charlesreid1.com/bots/b-captain-hook).
By creating a hook named `push-b-captain-hook-master` in the
`hooks/` directory of Captain Hook, and having it simply run
`touch /tmp/triggers/push-b-captain-hook-master`,
this webhook can trigger the Captain Hook's Canary service script,
which triggers a restart of the webhooks docker pod.
Code: <https://git.charlesreid1.com/bots/b-captain-hook/src/branch/master/hooks/push-b-captain-hook-master>
## Network
The `d-subodomains-nginx` container opens different ports for different
subdomains, and reverse-proxies requests from charlesreid1.com.
The port numbering starts at 7777 for pages.charlesreid1.com
and goes up from there, one port per subdomain.
Also see [pod-charlesreid1](https://git.charlesreid1.com/docker/pod-charlesreid1)
on git.charlesreid1.com for the nginx reverse proxy configuration.
Captain Hook runs a Flask server on port 5000 and listens for triggers
from git.charlesreid1.com (gitea) web hooks. These web hooks must have
the correct secret or the trigger will be ignored.
## Servers
[pod-webhooks](https://pages.charlesreid1.com/pod-webhooks/)
runs on a virtual server somewhere.
This pod's nginx service provides a backend that is
reverse-proxied by the machine running
[pod-charlesreid1](https://pages.charlesreid1.com/pod-charlesreid1)
(and the whole <https://charlesreid1.com> frontend).
It opens ports 7777+ and up (one per subdomain).
The [pod-charlesreid1](https://pages.charlesreid1.com/pod-charlesreid1)
docker pod (actually the
[d-nginx-charlesreid1](https://pages.charlesreid1.com/d-nginx-charlesreid1/)
submodule in that pod) contains the nginx
config files that control the reverse proxy
behavior of <https://charlesreid1.com>.
Like the nginx service in this webhooks pod, the Captain Hook
webhook service is also reverse-proxied by the main nginx frontend
running <https://charlesreid1.com> with the
[pod-charlesreid1](https://pages.charlesreid1.com/pod-charlesreid1)
docker pod. If a URL request for <https://hooks.charlesreid1.com>
is received by the <https://charlesreid1.com> server,
it is forwarded to the machine running the [pod-webhooks](https://git.charlesreid1.com/pod-webhooks)
docker pod, which decides whether it is a POST request
(that should be sent to this pod's Captain Hook) or a GET request
(that should be sent to this pod's nginx).

64
docs/running.md

@ -1,64 +0,0 @@ @@ -1,64 +0,0 @@
## The Docker Compose File
The `docker-compose.yml` file contains everything needed to
run the webhooks docker pod: a Captain Hook webhook server, and
an nginx server to serve up static pages for each subdomain.
Why use docker-compose instead of docker?
docker-compose is the preferred way to run multiple containers.
## Running Webhooks Docker Pod from Command Line
Run the pod in the foreground or background by running these
commands from the directory containing `docker-compose.yml`:
```
docker-compose up # interactive
docker-compose up -d # detached
```
If you want to rebuild all the containers before bringing
the pod up, add the `--build` flag:
```
docker-compose up --build
```
If you just want to rebuild the containers without bringing
them up,
```
docker-compose build
```
To rebuild absolutely everything from scratch,
```
docker-compose build --no-cache
```
***WARNING:*** this will re-download all aptitude packages,
which can be extremely slow. Use with caution.
You can restart all containers in a pod using the restart command:
```
docker-compose restart
```
***WARNING:*** this will ***NOT*** pick up changes to
Dockerfiles or to files that are mounted into the container.
This simply restarts the container using the same image
(in memory) that was previously running, ***without***
getting an up-to-date container image.
## Workflow for Docker Pod Updates
To minimize downtime, use the following workflow:
* Run `docker-compose build` to rebuild the images, leaving the pod running (they are not affected)
* Run `docker-compose down` to bring the pod down
* Run `docker-compose up` to bring the pod up
(Add the `-d` flag to start the docker pod in the background.)

93
docs/services.md

@ -1,93 +0,0 @@ @@ -1,93 +0,0 @@
## Running Hooks-Subdomains Docker Pod as Startup Service
The webhooks-subdomains docker pod requires two startup
services:
* Docker pod service - this startup service keeps the pod running,
and will restart it if it crashes
* Captain Hook's canary - this watches a folder that is shared between
the docker pod host and the Captain Hook container, which allows the
pod to send triggers to the host.
Also see the `scripts/` folder of this repo,
[pod-webhooks](https://git.charlesreid1.com/docker/pod-webhooks)
([Github mirror](https://github.com/charlesreid1-docker/pod-webhooks)).
### Docker Pod Startup Service
This service keeps the webhooks docker pod service running
continuously. If the pod stops, this service will restart it.
(This service should not be running if you are troubleshooting
the docker pod, otherwise every time you try and stop the pod
it will respawn.)
**`pod-webhooks.service:`**
```
[Unit]
Description=webhooks and subdomains docker pod
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/local/bin/docker-compose -f /home/charles/codes/docker/pod-webhooks/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f /home/charles/codes/docker/pod-webhooks/docker-compose.yml down
[Install]
WantedBy=default.target
```
### Captain Hook's Canary Startup Service
This service just watches a folder for a particular
watchfile, and runs a script if it sees the watchfile
appear.
**`captain-hook-canary.service:`**
```
[Unit]
Description=captain hook canary script
Requires=pod-webhooks.service
After=pod-webhooks.service
[Service]
Restart=always
ExecStart=/home/charles/pod-webhooks/scripts/captain_hook_canary.sh
ExecStop=/usr/bin/pgrep -f captain_hook_canary | /usr/bin/xargs /bin/kill
[Install]
WantedBy=default.target
```
### Installing Services
Install the services by copying the `*.service` files
to `/etc/systemd/system/dockerpod-webhooks.servce`
and `/etc/systemd/system/captain-hook-canary.servce`,
and activate the startup services:
```
sudo systemctl enable pod-webhooks.service
sudo systemctl enable captain-hook-canary.service
```
Now you can start/stop the services with:
```
sudo systemctl (start|stop) pod-webhooks.service
sudo systemctl (start|stop) captain-hook-canary.service
```
As mentioned above, these services should be stopped before
doing a `docker-compose stop` or a `docker-compose up --build`
to keep the pod from respawning in the middle of the task.

696
index.html

@ -0,0 +1,696 @@ @@ -0,0 +1,696 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/pod-webhooks/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href=".">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.0.3">
<title>pod-webhooks</title>
<link rel="stylesheet" href="assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="assets/stylesheets/application-palette.22915126.css">
<meta name="theme-color" content="#2196f3">
<script src="assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="assets/fonts/material-icons.css">
<link rel="stylesheet" href="css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="blue" data-md-color-accent="blue">
<svg class="md-svg">
<defs>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="#pod-webhooks" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-header-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
pod-webhooks
</span>
<span class="md-header-nav__topic">
Home
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="https://pages.charlesreid1.com/pod-webhooks" title="pod-webhooks" class="md-nav__button md-logo">
<i class="md-icon">dns</i>
</a>
pod-webhooks
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/docker/pod-webhooks" title="Go to repository" class="md-source" data-md-source="">
<div class="md-source__repository">
pod-webhooks
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Home
</label>
<a href="." title="Home" class="md-nav__link md-nav__link--active">
Home
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#links" title="Links" class="md-nav__link">
Links
</a>
</li>
<li class="md-nav__item">
<a href="#initial-setup-of-pages-subdomain" title="Initial Setup of Pages Subdomain" class="md-nav__link">
Initial Setup of Pages Subdomain
</a>
</li>
<li class="md-nav__item">
<a href="#adding-hooks" title="Adding Hooks" class="md-nav__link">
Adding Hooks
</a>
</li>
<li class="md-nav__item">
<a href="#how-it-works" title="How It Works" class="md-nav__link">
How It Works
</a>
</li>
<li class="md-nav__item">
<a href="#volumes-and-files" title="Volumes and Files" class="md-nav__link">
Volumes and Files
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#subdomains" title="Subdomains" class="md-nav__link">
Subdomains
</a>
</li>
<li class="md-nav__item">
<a href="#captain-hook" title="Captain Hook" class="md-nav__link">
Captain Hook
</a>
</li>
<li class="md-nav__item">
<a href="#captain-hooks-canary" title="Captain Hook's Canary" class="md-nav__link">
Captain Hook's Canary
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#network" title="Network" class="md-nav__link">
Network
</a>
</li>
<li class="md-nav__item">
<a href="#servers" title="Servers" class="md-nav__link">
Servers
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="adding/" title="Adding Webhooks" class="md-nav__link">
Adding Webhooks
</a>
</li>
<li class="md-nav__item">
<a href="running/" title="Running Captain Hook" class="md-nav__link">
Running Captain Hook
</a>
</li>
<li class="md-nav__item">
<a href="services/" title="Captain Hook Startup Services" class="md-nav__link">
Captain Hook Startup Services
</a>
</li>
<li class="md-nav__item">
<a href="canary/" title="Captain Hook's Canary" class="md-nav__link">
Captain Hook's Canary
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#links" title="Links" class="md-nav__link">
Links
</a>
</li>
<li class="md-nav__item">
<a href="#initial-setup-of-pages-subdomain" title="Initial Setup of Pages Subdomain" class="md-nav__link">
Initial Setup of Pages Subdomain
</a>
</li>
<li class="md-nav__item">
<a href="#adding-hooks" title="Adding Hooks" class="md-nav__link">
Adding Hooks
</a>
</li>
<li class="md-nav__item">
<a href="#how-it-works" title="How It Works" class="md-nav__link">
How It Works
</a>
</li>
<li class="md-nav__item">
<a href="#volumes-and-files" title="Volumes and Files" class="md-nav__link">
Volumes and Files
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#subdomains" title="Subdomains" class="md-nav__link">
Subdomains
</a>
</li>
<li class="md-nav__item">
<a href="#captain-hook" title="Captain Hook" class="md-nav__link">
Captain Hook
</a>
</li>
<li class="md-nav__item">
<a href="#captain-hooks-canary" title="Captain Hook's Canary" class="md-nav__link">
Captain Hook's Canary
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#network" title="Network" class="md-nav__link">
Network
</a>
</li>
<li class="md-nav__item">
<a href="#servers" title="Servers" class="md-nav__link">
Servers
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="pod-webhooks">pod-webhooks<a class="headerlink" href="#pod-webhooks" title="Permanent link">&para;</a></h1>
<p>This docker pod runs two services:</p>
<ul>
<li>Captain Hook webhook server (python + flask)<ul>
<li><a href="https://git.charlesreid1.com/bots/b-captain-hook">b-captain-hook</a></li>
</ul>
</li>
<li>Static content server for subdomain pages (nginx)<ul>
<li><a href="https://git.charlesreid1.com/docker/d-nginx-subdomains">d-nginx-subdomains</a></li>
</ul>
</li>
</ul>
<p>These two services are in this repo as submodules.</p>
<h2 id="links">Links<a class="headerlink" href="#links" title="Permanent link">&para;</a></h2>
<p>See documentation page here: <a href="https://pages.charlesreid1.com/pod-webhooks">https://pages.charlesreid1.com/pod-webhooks</a></p>
<p>Source code on git.charlesreid1.com: <a href="https://git.charlesreid1.com/docker/pod-webhooks">https://git.charlesreid1.com/docker/pod-webhooks</a></p>
<p>Source code on github.com: <a href="https://github.com/charlesreid1-docker/pod-webhooks">https://github.com/charlesreid1-docker/pod-webhooks</a></p>
<h2 id="initial-setup-of-pages-subdomain">Initial Setup of Pages Subdomain<a class="headerlink" href="#initial-setup-of-pages-subdomain" title="Permanent link">&para;</a></h2>
<p>The pages.charlesreid1.com subdomain is served from content
in the directory <code>/www/pages.charlesreid1.com</code>.</p>
<p>To set this up with pages and sites that should exist already,
use the set up script at <code>scripts/pages_init_setup.py</code> and
run it on the pages.charlesreid1.com server:</p>
<div class="codehilite"><pre><span></span>python scripts/pages_init_setup.py
</pre></div>
<p>This will create the <code>/www/pages.charlesreid1.com/</code> directory
structure and will clone several repositories to populate it
with content.</p>
<h2 id="adding-hooks">Adding Hooks<a class="headerlink" href="#adding-hooks" title="Permanent link">&para;</a></h2>
<p>Since this is probably the only thing you'll care about once everything
is actually running... until it breaks.</p>
<p><a href="adding/">How To Add A Hook</a></p>
<h2 id="how-it-works">How It Works<a class="headerlink" href="#how-it-works" title="Permanent link">&para;</a></h2>
<p>See <a href="running/">Running.md</a> for info about running this docker pod.</p>
<ul>
<li>Running the Docker Pod from Comand Line</li>
<li>Workflow for Docker Pod Updates</li>
</ul>
<p>See <a href="services/">Services.md</a> for info about running startup services.</p>
<ul>
<li>Running the Docker Pod as a Startup Service</li>
<li>Running Captain Hook's Canary (Script)</li>
</ul>
<p>Enable/disable service (installs/uninstalls, but does not start):</p>
<div class="codehilite"><pre><span></span>sudo systemctl (enable|disable) pod-webhooks.service
sudo systemctl (enable|disable) captain-hook-canary.service
</pre></div>
<p>Start/stop:</p>
<div class="codehilite"><pre><span></span>sudo systemctl (start|stop) pod-webhooks.service
sudo systemctl (start|stop) captain-hook-canary.service
</pre></div>
<p>See <a href="canary/">Captain Hook's Canary</a> for details on the canary script that allows the
webhooks docker pod to trigger itself to be re-loaded when there are new hooks
added to captain hook.</p>
<h2 id="volumes-and-files">Volumes and Files<a class="headerlink" href="#volumes-and-files" title="Permanent link">&para;</a></h2>
<h3 id="subdomains">Subdomains<a class="headerlink" href="#subdomains" title="Permanent link">&para;</a></h3>
<p>The static files hosted on charlesreid1.com subdomains are contained in
subdirectories of <code>/www/*.charlesreid1.com/</code> and this is
mounted by the subdomains docker container that has rules
set up for which subdomains to serve.</p>
<h3 id="captain-hook">Captain Hook<a class="headerlink" href="#captain-hook" title="Permanent link">&para;</a></h3>
<p>Captain Hook mounts the <code>/www</code> folder, which is served by the subdomains
nginx server, as well as the hooks folder in the Captain Hook repository
(that's at <code>b-captain-hook/hooks</code>).</p>
<p>When there is a change pushed to a particular branch on git.charlesreid1.com,
the git.charlesreid1.com server will check if there is a corresponding hook that's
been added to Captain Hook for that repo and branch. If so, git.charlesreid1.com
runs that script. For pages.charlesreid1.com, that's usually just a git pull
on the contents of <code>/www/pages.charlesreid1.com/my-page</code>.</p>
<h3 id="captain-hooks-canary">Captain Hook's Canary<a class="headerlink" href="#captain-hooks-canary" title="Permanent link">&para;</a></h3>
<p>Captain Hook presents a bit of a paradox: what happens when Captain Hook installs
a hook for itself, and detects that Captain Hook itself has changed?</p>
<p>In this case, the webhooks docker pod needs to be able to tell the host machine
to restart the webhooks docker pod.</p>
<p>This is done by Captain Hook's Canary. This is a service script that checks every
10 seconds for a trigger file in a directory mounted between the host and container.
If the trigger file is present, the host will update its copy of Captain Hook,
then restart the webhooks-subdomains docker pod.</p>
<p>As per the <a href="https://git.charlesreid1.com/dotfiles/debian">dotfiles/debian</a> repo,
the <code>captain_hook_canary.sh</code> canary will restart the webhooks docker pod if it
detects the presence following file:</p>
<div class="codehilite"><pre><span></span>/tmp/triggers/push-b-captain-hook-master
</pre></div>
<p>(The canary script will remove this file once it has restarted the webhooks docker pod.)</p>
<p>Now, a hook can be added to Captain Hook that will be run when there is a push event
on the master branch of <a href="https://git.charlesreid1.com/bots/b-captain-hook">bots/b-captain-hook</a>.
By creating a hook named <code>push-b-captain-hook-master</code> in the
<code>hooks/</code> directory of Captain Hook, and having it simply run
<code>touch /tmp/triggers/push-b-captain-hook-master</code>,
this webhook can trigger the Captain Hook's Canary service script,
which triggers a restart of the webhooks docker pod.</p>
<p>Code: <a href="https://git.charlesreid1.com/bots/b-captain-hook/src/branch/master/hooks/push-b-captain-hook-master">https://git.charlesreid1.com/bots/b-captain-hook/src/branch/master/hooks/push-b-captain-hook-master</a></p>
<h2 id="network">Network<a class="headerlink" href="#network" title="Permanent link">&para;</a></h2>
<p>The <code>d-subodomains-nginx</code> container opens different ports for different
subdomains, and reverse-proxies requests from charlesreid1.com.
The port numbering starts at 7777 for pages.charlesreid1.com
and goes up from there, one port per subdomain.</p>
<p>Also see <a href="https://git.charlesreid1.com/docker/pod-charlesreid1">pod-charlesreid1</a>
on git.charlesreid1.com for the nginx reverse proxy configuration.</p>
<p>Captain Hook runs a Flask server on port 5000 and listens for triggers
from git.charlesreid1.com (gitea) web hooks. These web hooks must have
the correct secret or the trigger will be ignored.</p>
<h2 id="servers">Servers<a class="headerlink" href="#servers" title="Permanent link">&para;</a></h2>
<p><a href="https://pages.charlesreid1.com/pod-webhooks/">pod-webhooks</a>
runs on a virtual server somewhere.</p>
<p>This pod's nginx service provides a backend that is
reverse-proxied by the machine running
<a href="https://pages.charlesreid1.com/pod-charlesreid1">pod-charlesreid1</a>
(and the whole <a href="https://charlesreid1.com">https://charlesreid1.com</a> frontend).
It opens ports 7777+ and up (one per subdomain).</p>
<p>The <a href="https://pages.charlesreid1.com/pod-charlesreid1">pod-charlesreid1</a>
docker pod (actually the
<a href="https://pages.charlesreid1.com/d-nginx-charlesreid1/">d-nginx-charlesreid1</a>
submodule in that pod) contains the nginx
config files that control the reverse proxy
behavior of <a href="https://charlesreid1.com">https://charlesreid1.com</a>.</p>
<p>Like the nginx service in this webhooks pod, the Captain Hook
webhook service is also reverse-proxied by the main nginx frontend
running <a href="https://charlesreid1.com">https://charlesreid1.com</a> with the
<a href="https://pages.charlesreid1.com/pod-charlesreid1">pod-charlesreid1</a>
docker pod. If a URL request for <a href="https://hooks.charlesreid1.com">https://hooks.charlesreid1.com</a>
is received by the <a href="https://charlesreid1.com">https://charlesreid1.com</a> server,
it is forwarded to the machine running the <a href="https://git.charlesreid1.com/pod-webhooks">pod-webhooks</a>
docker pod, which decides whether it is a POST request
(that should be sent to this pod's Captain Hook) or a GET request
(that should be sent to this pod's nginx).</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="adding/" title="Adding Webhooks" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Adding Webhooks
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 <a href="https://charlesreid1.com">Charles Reid</a>, released under the <a href="https://opensource.org/licenses/MIT">MIT license</a>
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="assets/javascripts/application.e72fd936.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:"."}})</script>
<script src="search/main.js"></script>
</body>
</html>

1
mkdocs-material

@ -1 +0,0 @@ @@ -1 +0,0 @@
Subproject commit b0c6890853aa9138baf5f9749862b927518ab656

38
mkdocs.yml

@ -1,38 +0,0 @@ @@ -1,38 +0,0 @@
site_name: pod-webhooks
site_url: https://pages.charlesreid1.com/pod-webhooks
repo_name: pod-webhooks
repo_url: https://git.charlesreid1.com/docker/pod-webhooks
edit_uri: ""
copyright: 'Copyright &copy; 2018 <a href="https://charlesreid1.com">Charles Reid</a>, released under the <a href="https://opensource.org/licenses/MIT">MIT license</a>'
docs_dir: docs
site_dir: site
extra_css:
- css/custom.css
theme:
name: null
custom_dir: 'mkdocs-material/material'
palette:
primary: 'blue'
accent: 'blue'
logo:
icon: 'dns'
font:
text: 'Roboto'
code: 'Roboto Mono'
nav:
- "Home": "index.md"
- "Adding Webhooks": "adding.md"
- "Running Captain Hook": "running.md"
- "Captain Hook Startup Services": "services.md"
- "Captain Hook's Canary": "canary.md"
# Extensions
markdown_extensions:
- admonition
- codehilite:
guess_lang: false
- toc:
permalink: true
strict: true

24
scripts/Readme.md

@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
# pod-webhooks scripts
Copy this `pod-webhooks.service` service script to
`/etc/systemd/system/pod-webhooks.service`:
```
sudo cp pod-webhooks.service /etc/systemd/system/pod-webhooks.service
```
Enable/disable the service:
```
sudo systemctl enable pod-webhooks
sudo systemctl disable pod-webhooks
```
Start/restart/stop the service:
```
sudo systemctl start pod-webhooks
sudo systemctl restart pod-webhooks
sudo systemctl stop pod-webhooks
```

89
scripts/apply_templates_captainhook.py

@ -1,89 +0,0 @@ @@ -1,89 +0,0 @@
import os, re, sys
import glob
from jinja2 import Environment, FileSystemLoader, select_autoescape
"""
Apply Default Values to
Captain Hook Jinja Templates
This script applies default values to
templates in this folder.
The templates are used by Ansible,
but this script uses the same template
engine as Ansible to apply template
variable values to the template files
and make real files.
variables are:
- `webhooks_install_dir` - location of pod-webhooks repo
- `username` - user/group name to change ownership to
- `server_name_default` - name of server
(e.g., charlesreid1.com or charlesreid1.red)
"""
# Where templates live
TEMPLATEDIR = '.'
# Where rendered templates will go
OUTDIR = 'output'
# Should existing (destination) files
# be overwritten if they exist?
OVERWRITE = True
# Template variables
TV = {
'server_name_default': 'charlesreid1.red',
'username': 'charles',
'webhooks_install_dir' : '/home/charles/pod-webhooks'
}
def apply_templates(template_dir, output_dir, template_vars, overwrite=False):
"""Apply the template variables
to the template files.
"""
if not os.path.exists(output_dir):
msg = "Error: output dir %s does not exist!"%(output_dir)
raise Exception(msg)
if not os.path.exists(template_dir):
msg = "Error: template dir %s does not exist!"%(output_dir)
raise Exception(msg)
# Jinja env
env = Environment(loader=FileSystemLoader('.'))
# Render templates
template_files = glob.glob('captain*.j2')
render_files = [re.sub('\.j2','',s) for s in template_files]
for rfile,tfile in zip(render_files,template_files):
# Get rendered template content
content = env.get_template(tfile).render(**template_vars)
# Write to file
dest = os.path.join(output_dir,rfile)
if os.path.exists(dest) and overwrite is False:
msg = "Error: template rendering destination %s already exists!"%(dest)
raise Exception(msg)
with open(dest,'w') as f:
f.write(content)
print("Rendered the following templates:%s\nOutput files:%s\n"%(
"".join(["\n- "+os.path.join(template_dir,j) for j in template_files]),
"".join(["\n- "+os.path.join(output_dir,j) for j in render_files])
))
if __name__=="__main__":
apply_templates(TEMPLATEDIR,OUTDIR,TV,OVERWRITE)

84
scripts/apply_templates_pod.py

@ -1,84 +0,0 @@ @@ -1,84 +0,0 @@
import os, re, sys
import glob
from jinja2 import Environment, FileSystemLoader, select_autoescape
"""
Apply Default Values to
pod-webhooks Jinja Templates
This script applies default values to
templates in this folder.
The templates are used by Ansible,
but this script uses the same template
engine as Ansible to apply template
variable values to the template files
and make real files.
variables are:
- `webhooks_install_dir` - location of pod-webhooks repo
(i.e., location of pod-webhooks docker-compose file)
"""
# Where templates live
TEMPLATEDIR = '.'
# Where rendered templates will go
OUTDIR = 'output'
# Should existing (destination) files
# be overwritten if they exist?
OVERWRITE = True
# Template variables
TV = {
'webhooks_install_dir' : '/home/charles/pod-webhooks'
}
def apply_templates(template_dir, output_dir, template_vars, overwrite=False):
"""Apply the template variables
to the template files.
"""
if not os.path.exists(output_dir):
msg = "Error: output dir %s does not exist!"%(output_dir)
raise Exception(msg)
if not os.path.exists(template_dir):
msg = "Error: template dir %s does not exist!"%(output_dir)
raise Exception(msg)
# Jinja env
env = Environment(loader=FileSystemLoader('.'))
# Render templates
template_files = glob.glob('*.service.j2')
render_files = [re.sub('\.j2','',s) for s in template_files]
for rfile,tfile in zip(render_files,template_files):
# Get rendered template content
content = env.get_template(tfile).render(**template_vars)
# Write to file
dest = os.path.join(output_dir,rfile)
if os.path.exists(dest) and overwrite is False:
msg = "Error: template rendering destination %s already exists!"%(dest)
raise Exception(msg)
with open(dest,'w') as f:
f.write(content)
print("Rendered the following templates:%s\nOutput files:%s\n"%(
"".join(["\n- "+os.path.join(template_dir,j) for j in template_files]),
"".join(["\n- "+os.path.join(output_dir,j) for j in render_files])
))
if __name__=="__main__":
apply_templates(TEMPLATEDIR,OUTDIR,TV,OVERWRITE)

90
scripts/apply_templates_subdomains.py

@ -1,90 +0,0 @@ @@ -1,90 +0,0 @@
import os, re, sys
import glob
import subprocess
from jinja2 import Environment, FileSystemLoader, select_autoescape
"""
Apply Default Values to
SUBDOMAINS Jinja Templates
This script applies default values to
templates in this folder.
The templates are used by Ansible,
but this script uses the same template
engine as Ansible to apply template
variable values to the template files
and make real files.
only variables are:
- `username` - user/group name to change ownership to
- `server_name_default` - name of server
(e.g., charlesreid1.com or charlesreid1.red)
"""
# Where templates live
TEMPLATEDIR = '.'
# Where rendered templates will go
OUTDIR = 'output'
# Should existing (destination) files
# be overwritten if they exist?
OVERWRITE = True
# Template variables
TV = {
'server_name_default': 'charlesreid1.red',
'username': 'charles'
}
def apply_templates(template_dir, output_dir, template_vars, overwrite=False):
"""Apply the template variables
to the template files.
"""
if not os.path.exists(output_dir):
msg = "Error: output dir %s does not exist!"%(output_dir)
raise Exception(msg)
if not os.path.exists(template_dir):
msg = "Error: template dir %s does not exist!"%(output_dir)
raise Exception(msg)
# Jinja env
env = Environment(loader=FileSystemLoader('.'))
# Render templates
template_files = glob.glob('*_setup.py.j2') + glob.glob('*_pull.py.j2')
render_files = [re.sub('\.j2','',s) for s in template_files]
for rfile,tfile in zip(render_files,template_files):
# Get rendered template content
content = env.get_template(tfile).render(**template_vars)
# Write to file
dest = os.path.join(output_dir,rfile)
if os.path.exists(dest) and overwrite is False:
msg = "Error: template rendering destination %s already exists!"%(dest)
raise Exception(msg)
with open(dest,'w') as f:
f.write(content)
x = 'executioner.py'
subprocess.call(['cp',x,os.path.join(output_dir,x)])
print("Rendered the following templates:%s\nOutput files:%s\n"%(
"".join(["\n- "+os.path.join(template_dir,j) for j in template_files]),
"".join(["\n- "+os.path.join(output_dir,j) for j in render_files])
))
if __name__=="__main__":
apply_templates(TEMPLATEDIR,OUTDIR,TV,OVERWRITE)

12
scripts/captain-hook-canary.service.j2

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
[Unit]
Description=captain hook canary script
Requires=pod-webhooks.service
After=pod-webhooks.service
[Service]
Restart=always
ExecStart={{ webhooks_install_dir }}/scripts/captain_hook_canary.sh
ExecStop=/usr/bin/pgrep -f captain_hook_canary | /usr/bin/xargs /bin/kill
[Install]
WantedBy=default.target

47
scripts/captain_hook_canary.sh.j2

@ -1,47 +0,0 @@ @@ -1,47 +0,0 @@
#!/bin/bash
: '
Captain Hook Canary Script (Template)
Note: this needs an associated systemd service.
See the services directory of the dotfiles repo.
This is a canary script for connecting
the Captain Hook container to the host
machine, and triggering tasks on the
host machine with webhooks.
The Captain Hook container mounts the
following host directory inside the
container (same location for host/container):
/tmp/triggers/
When a webhook in Captain Hook wants to
trigger an event on the host (blackbeard),
it puts a file in /tmp/triggers/.
Meanwhile, on the host, this script checks
every 10 seconds for trigger files.
Each webhook can create its own trigger file,
and this script processes each trigger differently.
'
while true
do
# bootstrap-pull captain hook
if [ -f "/tmp/triggers/push-b-captain-hook-master" ]; then
echo "CAPTAIN HOOK'S CANARY:"
echo "Running trigger to update Captain Hook on the host machine (user charles)"
sudo -H -u charles python {{ webhooks_install_dir }}/scripts/captain_hook_pull_host.py
echo "All done."
rm -f "/tmp/triggers/push-b-captain-hook-master"
touch /tmp/canary-yup-host-works
fi
sleep 10;
done

110
scripts/captain_hook_pull_host.py.j2

@ -1,110 +0,0 @@ @@ -1,110 +0,0 @@
#!/usr/bin/env python3
import subprocess
import os
import time
"""
Captain Hook: Pull Captain Hook on the Host
This script is called by the host machine
(blackbeard) running the Captain Hook container.
This is triggered by push actions to the
master branch of b-captain-hook.
The action is to update (git pull) the copy
of Captain Hook running on the host, and
restart the container pod.
"""
pod_dir = '{{ webhooks_install_dir }}'
work_dir = os.path.join(pod_dir,'b-captain-hook')
from datetime import datetime
d = datetime.now().strftime('%Y-m-%d')
with open('/tmp/captain_hook_pull_host_%s.log'%(d),'w') as f:
# Step 1:
# Update Captain Hook
co_cmd = ['git','checkout','master']
proc = subprocess.call(co_cmd, cwd=work_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
o = stdout.decode('utf-8')
e = stderr.decode('utf-8')
f.write(" ".join(co_cmd))
f.write("\n")
f.write("-"*40)
f.write("\n")
f.write(o)
f.write("\n")
f.write(e)
f.write("\n\n")
f_cmd = ['git','fetch','--all']
proc = subprocess.call(f_cmd, cwd=work_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
o = stdout.decode('utf-8')
e = stderr.decode('utf-8')
f.write(" ".join(f_cmd))
f.write("\n")
f.write("-"*40)
f.write("\n")
f.write(o)
f.write("\n")
f.write(e)
f.write("\n\n")
time.sleep(5)
pull_cmd = ['git','pull','origin','master']
proc = subprocess.call(pull_cmd, cwd=work_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
o = stdout.decode('utf-8')
e = stderr.decode('utf-8')
f.write(" ".join(pull_cmd))
f.write("\n")
f.write("-"*40)
f.write("\n")
f.write(o)
f.write("\n")
f.write(e)
f.write("\n\n")
time.sleep(10)
submod_cmd = ['git','submodule','update','--remote']
proc = subprocess.call(submod_cmd, cwd=work_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
o = stdout.decode('utf-8')
e = stderr.decode('utf-8')
f.write(" ".join(pull_cmd))
f.write("\n")
f.write("-"*40)
f.write("\n")
f.write(o)
f.write("\n")
f.write(e)
f.write("\n\n")
time.sleep(10)
# Step 2:
# Restart Captain Hook pod
pod_restart = ['systemctl','restart','pod-webhooks']
#pod_restart = ['docker-compose','restart']
proc = subprocess.call(pod_restart, cwd=pod_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
o = stdout.decode('utf-8')
e = stderr.decode('utf-8')
f.write(" ".join(pod_restart))
f.write("\n")
f.write("-"*40)
f.write("\n")
f.write(o)
f.write("\n")
f.write(e)
f.write("\n\n")

21
scripts/executioner.py

@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
#!/usr/bin/env python3
import subprocess
import os
def execute(cmd):
"""
A function to run a command and return the
lines of output as they are generated,
allowing the calling function to "stream"
the output of the command to print() or etc.
"""
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
for stdout_line in iter(p.stdout.readline, ""):
yield stdout_line
p.stdout.close()
err = "".join([j for j in iter(p.stderr.readline,"")])
return_code = p.wait()
if return_code:
yield err
raise subprocess.CalledProcessError(return_code, cmd)

125
scripts/pages_init_setup.py.j2

@ -1,125 +0,0 @@ @@ -1,125 +0,0 @@
#!/usr/bin/env python3
import subprocess
import os
from executioner import execute
"""
Pages Initial Setup
This script sets up the initial pages.charlesreid1.XYZ
folder structure and checks out all pages that should
be present initially at pages.charlesreid1.XYZ.
This clones the page for a given project to
/www/pages.charlesreid1.XYZ/htdocs/project-name
(where project = repo)
"""
SERVER_NAME_DEFAULT = '{{ server_name_default }}'
USERNAME = '{{ username }}'
# Repos must have a gh-pages branch
repo_names = '''bots/b-apollo
bots/b-captain-hook
bots/b-ginsberg
bots/b-milton
bots/uncle-archie
bots/boring-mind-machine
docker/d-gitea
docker/d-mediawiki
docker/d-mysql
docker/d-nginx-charlesreid1
docker/d-nginx-subdomains
docker/d-phpmyadmin
docker/d-python-files
docker/d-python-helium
charlesreid1/dont-sudo-pip
bots/embarcadero-mind-machine
charlesreid1/git-commit-ectomy
charlesreid1/git-subway-maps
charlesreid1/github-heroku-attack-rabbits
charlesreid1/how-do-i-heroku
charlesreid1/how-do-i-pandoc
charlesreid1/how-do-i-pelican
charlesreid1/how-do-i-pyenv
charlesreid1/how-do-i-snakemake
docker/pod-bots
docker/pod-charlesreid1
docker/pod-webhooks
bots/russian-rainbow-mind-machine
charlesreid1/scurvy-knave-theme
charlesreid1/translate-yer-docs
charlesreid1/wisko-manual'''.split('\n')
repo_urls = ['https://git.charlesreid1.com/%s.git'%(j) for j in repo_names]
root = '/www'
pages = 'pages.%s'%(SERVER_NAME_DEFAULT)
basedir = os.path.join(root,pages)
if not os.path.exists(basedir):
raise Exception("Error: base directory %s does not exist!"%(basedir))
for name,url in zip(repo_names,repo_urls):
# for a hypothetical repo "project":
#
# base dir: /www/pages.charlesreid1.com
# .git dir: /www/pages.charlesreid1.com/git.project
# htdocs dir: /www/pages.charlesreid1.com/htdocs/project
# Step 1: clone
# Construct the clone command to set up
# live htdocs directory for this project
repo_owner, repo_name = name.split("/")
clonepth = os.path.join(basedir,"htdocs",repo_name)
dotgitpth = os.path.join(basedir,"git.%s"%(repo_name))
if os.path.exists(clonepth):
print("Git repository has already been cloned, %s already exists on disk!"%(clonepth))
else:
clonecmd = ["git","clone",
"--separate-git-dir=%s"%(dotgitpth),
"-b","gh-pages",
url,clonepth]
print("About to clone gh-pages branch for %s using command:\n"%(name))
print(" $ " + " ".join(clonecmd))
print("\n")
try:
for loo in execute(clonecmd):
print(loo)
print("\n")
print("Done.")
except subprocess.CalledProcessError:
print("Failed on clone command for project %s"%(name))
print("Continuing...")
# Step 2: chown everybody
# Construct chown command
chowncmd = ['chown','-R',
USERNAME+":"+USERNAME,
basedir]
print("About to change owner of %s using command:\n"%(basedir))
print(" $ " + " ".join(chowncmd))
print("\n")
for loo in execute(chowncmd):
print(loo)
print("\n")
print("Done.")

129
scripts/pages_pull.py.j2

@ -1,129 +0,0 @@ @@ -1,129 +0,0 @@
#!/usr/bin/env python3
import subprocess
import os
from executioner import execute
"""
Pages Pull Script
This script pulls chnages to all repos in the
pages.charlesreid1.XYZ folder structure
This clones the page for a given project to
/www/pages.charlesreid1.XYZ/htdocs/project-name
(where project = repo)
"""
SERVER_NAME_DEFAULT = '{{ server_name_default }}'
USERNAME = '{{ username }}'
# Repos must have a gh-pages branch
repo_names = '''bots/b-apollo
bots/b-captain-hook
bots/b-ginsberg
bots/b-milton
bots/uncle-archie
bots/boring-mind-machine
docker/d-gitea
docker/d-mediawiki
docker/d-mysql
docker/d-nginx-charlesreid1
docker/d-nginx-subdomains
docker/d-phpmyadmin
docker/d-python-files
docker/d-python-helium
charlesreid1/dont-sudo-pip
bots/embarcadero-mind-machine
charlesreid1/git-commit-ectomy
charlesreid1/git-subway-maps
charlesreid1/github-heroku-attack-rabbits
charlesreid1/how-do-i-heroku
charlesreid1/how-do-i-pandoc
charlesreid1/how-do-i-pelican
charlesreid1/how-do-i-pyenv
charlesreid1/how-do-i-snakemake
docker/pod-bots
docker/pod-charlesreid1
docker/pod-webhooks
bots/russian-rainbow-mind-machine
charlesreid1/scurvy-knave-theme
charlesreid1/translate-yer-docs
charlesreid1/wisko-manual'''.split('\n')
repo_urls = ['https://git.charlesreid1.com/%s.git'%(j) for j in repo_names]
root = '/www'
pages = 'pages.%s'%(SERVER_NAME_DEFAULT)
basedir = os.path.join(root,pages)
htdocsdir = os.path.join(basedir,"htdocs")
if not os.path.exists(basedir):
raise Exception("Error: base directory %s does not exist!"%(basedir))
if not os.path.exists(htdocsdir):
raise Exception("Error: htdocs directory %s does not exist!"%(htdocsdir))
for name,url in zip(repo_names,repo_urls):
# for a hypothetical repo "project":
#
# base dir: /www/pages.charlesreid1.com
# .git dir: /www/pages.charlesreid1.com/git.project
# htdocs dir: /www/pages.charlesreid1.com/htdocs/project
# Step 1: pull
# Construct the git pull command to update
# the live htdocs directory for this project
repo_owner, repo_name = name.split("/")
workdir = os.path.join(basedir,"htdocs",repo_name)
dotgitdir = os.path.join(basedir,"git.%s"%(repo_name))
if not os.path.exists(workdir):
print("Git repository has not yet been cloned, %s does not exist on disk!"%(workdir))
else:
pullcmd = ['git',
'-C', basedir,
'--git-dir=%s'%(dotgitdir),
'--work-tree=%s'%(workdir),
'pull','origin','gh-pages']
print("About to pull gh-pages branch for %s using command:\n"%(name))
print(" $ " + " ".join(pullcmd))
print("\n")
try:
for loo in execute(pullcmd):
print(loo)
print("\n")
print("Done.")
except subprocess.CalledProcessError:
print("Failed on pull command for project %s"%(name))
print("Continuing...")
# Step 2: chown everybody
# Construct chown command
chowncmd = ['chown','-R',
USERNAME+":"+USERNAME,
basedir]
print("About to change owner of %s using command:\n"%(basedir))
print(" $ " + " ".join(chowncmd))
print("\n")
for loo in execute(chowncmd):
print(loo)
print("\n")
print("Done.")

14
scripts/pod-webhooks.service.j2

@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
# Hopefully this comment works
[Unit]
Description=webhooks and subdomains docker pod
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/local/bin/docker-compose -f {{ webhooks_install_dir }}/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f {{ webhooks_install_dir }}/docker-compose.yml down
[Install]
WantedBy=default.target

89
scripts/subdomains_init_setup.py.j2

@ -1,89 +0,0 @@ @@ -1,89 +0,0 @@
#!/usr/bin/env python3
import subprocess
import os
from executioner import execute
"""
Subdomains Initial Setup
This script sets up the initial folder structure
for the charlesreid1.com subdomains and their content.
"""
SERVER_NAME_DEFAULT = '{{ server_name_default }}'
USERNAME = '{{ username }}'
# Each subdomain page has an htdocs dir at
#
# /www/SUBDOMAIN.charlesreid1.XYZ/htdocs
#
# and a .git directory at
#
# /www/SUBDOMAIN.charlesreid1.XYZ/git.SUBDOMAIN.charlesreid1.XYZ
# Name of all subdomains to set up
sub_names = ['bots','pages','hooks']
subs = [n+'.'+SERVER_NAME_DEFAULT for n in sub_names]
# Use git.charlesreid1.com
# (Note we have to hard-code the suffix
# charlesreid1.com b/c that is the name
# of the repo for ALL subdomains)
urls = ['https://git.charlesreid1.com/charlesreid1/%s.charlesreid1.com'%(n) for n in sub_names]
#
# Use github.com (alternative)
# (Note we have to hard-code the suffix charlesreid1.com)
#urls = ['https://github.com/charlesreid1-docker/%s.charlesreid1.com'%(n) for n in sub_names]
# Base directory for all htdocs folders
pth = '/www'
# Create the base directory
subprocess.call(['mkdir','-p',pth])
# Step 1: clone htdocs dir for each subdomain
for subname, sub, url in zip(sub_names,subs,urls):
# Construct the clone command for the live
# htdocs directory for this subdomain
clonepth = os.path.join(pth,sub,'htdocs')
dotgitpth = os.path.join(pth,sub,'git.%s'%(subname))
if os.path.exists(clonepth):
print("Git repository has already been cloned, %s already exists on disk!"%(clonepth))
else:
clonecmd = ['git','clone',
'--separate-git-dir=%s'%(dotgitpth),
'-b','gh-pages',
url,clonepth]
print("About to clone htdocs dir for %s using command:\n"%(sub))
print(" $ " + " ".join(clonecmd))
print("\n")
for loo in execute(clonecmd):
print(loo)
print("\n")
print("Done.")
# Step 2: chown
# Construct chown command to chown everybody
chowncmd = ['chown','-R',USERNAME+":"+USERNAME,pth]
print("About to change owner of %s using command:\n"%(pth))
print(" $ " + " ".join(chowncmd))
print("\n")
for loo in execute(chowncmd):
print(loo)
print("\n")
print("Done.")

95
scripts/subdomains_pull.py.j2

@ -1,95 +0,0 @@ @@ -1,95 +0,0 @@
#!/usr/bin/env python3
import subprocess
import os
from executioner import execute
"""
Subdomains Pull Script
This script sets up the initial folder structure
for the charlesreid1.com subdomains and their content.
"""
SERVER_NAME_DEFAULT = '{{ server_name_default }}'
USERNAME = '{{ username }}'
# Each subdomain page has an htdocs dir at
#
# /www/SUBDOMAIN.charlesreid1.XYZ/htdocs
#
# and a .git directory at
#
# /www/SUBDOMAIN.charlesreid1.XYZ/git.SUBDOMAIN.charlesreid1.XYZ
# Name of all subdomains to set up
sub_names = ['bots','pages','hooks']
subs = [n+'.'+SERVER_NAME_DEFAULT for n in sub_names]
# Use git.charlesreid1.com
# (Note we have to hard-code the suffix
# charlesreid1.com b/c that is the name
# of the repo for ALL subdomains)
urls = ['https://git.charlesreid1.com/charlesreid1/%s.charlesreid1.com'%(n) for n in sub_names]
#
# Use github.com (alternative)
# (Note we have to hard-code the suffix charlesreid1.com)
#urls = ['https://github.com/charlesreid1-docker/%s.charlesreid1.com'%(n) for n in sub_names]
# Base directory for all htdocs folders
pth = '/www'
# Create the base directory
subprocess.call(['mkdir','-p',pth])
# Step 1: clone htdocs dir for each subdomain
for subname, sub, url in zip(sub_names,subs,urls):
# Step 1: pull
# Construct the git pull command to update
# the live htdocs directory for this project
basedir = os.path.join(pth,sub)
htdocsdir = os.path.join(basedir,"htdocs")
dotgitdir = os.path.join(basedir,"git.%s"%(subname))
if not os.path.exists(htdocsdir):
print("Git repository has not been cloned, %s does not exist on disk!"%(htdocsdir))
else:
# git pull, respecting the
# unusual .git/repo folder layout
pullcmd = ['git',
'-C', basedir,
'--git-dir=%s'%(dotgitdir),
'--work-tree=%s'%(htdocsdir),
'pull','origin','gh-pages']
print("About to pull htdocs dir for %s using command:\n"%(sub))
print(" $ " + " ".join(pullcmd))
print("\n")
for loo in execute(pullcmd):
print(loo)
print("\n")
print("Done.")
# Step 2: chown
# Construct chown command to chown everybody
chowncmd = ['chown','-R',USERNAME+":"+USERNAME,basedir]
print("About to change owner of %s using command:\n"%(basedir))
print(" $ " + " ".join(chowncmd))
print("\n")
for loo in execute(chowncmd):
print(loo)
print("\n")
print("Done.")

2986
search/lunr.js

File diff suppressed because it is too large Load Diff

96
search/main.js

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
function getSearchTermFromLocation() {
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == 'q') {
return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20'));
}
}
}
function joinUrl (base, path) {
if (path.substring(0, 1) === "/") {
// path starts with `/`. Thus it is absolute.
return path;
}
if (base.substring(base.length-1) === "/") {
// base ends with `/`
return base + path;
}
return base + "/" + path;
}
function formatResult (location, title, summary) {
return '<article><h3><a href="' + joinUrl(base_url, location) + '">'+ title + '</a></h3><p>' + summary +'</p></article>';
}
function displayResults (results) {
var search_results = document.getElementById("mkdocs-search-results");
while (search_results.firstChild) {
search_results.removeChild(search_results.firstChild);
}
if (results.length > 0){
for (var i=0; i < results.length; i++){
var result = results[i];
var html = formatResult(result.location, result.title, result.summary);
search_results.insertAdjacentHTML('beforeend', html);
}
} else {
search_results.insertAdjacentHTML('beforeend', "<p>No results found</p>");
}
}
function doSearch () {
var query = document.getElementById('mkdocs-search-query').value;
if (query.length > 2) {
if (!window.Worker) {
displayResults(search(query));
} else {
searchWorker.postMessage({query: query});
}
} else {
// Clear results for short queries
displayResults([]);
}
}
function initSearch () {
var search_input = document.getElementById('mkdocs-search-query');
if (search_input) {
search_input.addEventListener("keyup", doSearch);
}
var term = getSearchTermFromLocation();
if (term) {
search_input.value = term;
doSearch();
}
}
function onWorkerMessage (e) {
if (e.data.allowSearch) {
initSearch();
} else if (e.data.results) {
var results = e.data.results;
displayResults(results);
}
}
if (!window.Worker) {
console.log('Web Worker API not supported');
// load index in main thread
$.getScript(joinUrl(base_url, "search/worker.js")).done(function () {
console.log('Loaded worker');
init();
window.postMessage = function (msg) {
onWorkerMessage({data: msg});
};
}).fail(function (jqxhr, settings, exception) {
console.error('Could not load worker.js');
});
} else {
// Wrap search in a web worker
var searchWorker = new Worker(joinUrl(base_url, "search/worker.js"));
searchWorker.postMessage({init: true});
searchWorker.onmessage = onWorkerMessage;
}

1
search/search_index.json

File diff suppressed because one or more lines are too long

128
search/worker.js

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
var base_path = 'function' === typeof importScripts ? '.' : '/search/';
var allowSearch = false;
var index;
var documents = {};
var lang = ['en'];
var data;
function getScript(script, callback) {
console.log('Loading script: ' + script);
$.getScript(base_path + script).done(function () {
callback();
}).fail(function (jqxhr, settings, exception) {
console.log('Error: ' + exception);
});
}
function getScriptsInOrder(scripts, callback) {
if (scripts.length === 0) {
callback();
return;
}
getScript(scripts[0], function() {
getScriptsInOrder(scripts.slice(1), callback);
});
}
function loadScripts(urls, callback) {
if( 'function' === typeof importScripts ) {
importScripts.apply(null, urls);
callback();
} else {
getScriptsInOrder(urls, callback);
}
}
function onJSONLoaded () {
data = JSON.parse(this.responseText);
var scriptsToLoad = ['lunr.js'];
if (data.config && data.config.lang && data.config.lang.length) {
lang = data.config.lang;
}
if (lang.length > 1 || lang[0] !== "en") {
scriptsToLoad.push('lunr.stemmer.support.js');
if (lang.length > 1) {
scriptsToLoad.push('lunr.multi.js');
}
for (var i=0; i < lang.length; i++) {
if (lang[i] != 'en') {
scriptsToLoad.push(['lunr', lang[i], 'js'].join('.'));
}
}
}
loadScripts(scriptsToLoad, onScriptsLoaded);
}
function onScriptsLoaded () {
console.log('All search scripts loaded, building Lunr index...');
if (data.config && data.config.separator && data.config.separator.length) {
lunr.tokenizer.separator = new RegExp(data.config.separator);
}
if (data.index) {
index = lunr.Index.load(data.index);
data.docs.forEach(function (doc) {
documents[doc.location] = doc;
});
console.log('Lunr pre-built index loaded, search ready');
} else {
index = lunr(function () {
if (lang.length === 1 && lang[0] !== "en" && lunr[lang[0]]) {
this.use(lunr[lang[0]]);
} else if (lang.length > 1) {
this.use(lunr.multiLanguage.apply(null, lang)); // spread operator not supported in all browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Browser_compatibility
}
this.field('title');
this.field('text');
this.ref('location');
for (var i=0; i < data.docs.length; i++) {
var doc = data.docs[i];
this.add(doc);
documents[doc.location] = doc;
}
});
console.log('Lunr index built, search ready');
}
allowSearch = true;
postMessage({allowSearch: allowSearch});
}
function init () {
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", onJSONLoaded);
var index_path = base_path + '/search_index.json';
if( 'function' === typeof importScripts ){
index_path = 'search_index.json';
}
oReq.open("GET", index_path);
oReq.send();
}
function search (query) {
if (!allowSearch) {
console.error('Assets for search still loading');
return;
}
var resultDocuments = [];
var results = index.search(query);
for (var i=0; i < results.length; i++){
var result = results[i];
doc = documents[result.ref];
doc.summary = doc.text.substring(0, 200);
resultDocuments.push(doc);
}
return resultDocuments;
}
if( 'function' === typeof importScripts ) {
onmessage = function (e) {
if (e.data.init) {
init();
} else if (e.data.query) {
postMessage({ results: search(e.data.query) });
} else {
console.error("Worker - Unrecognized message: " + e);
}
};
}

28
sitemap.xml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://pages.charlesreid1.com/pod-webhooks/</loc>
<lastmod>2019-03-24</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/pod-webhooks/adding/</loc>
<lastmod>2019-03-24</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/pod-webhooks/running/</loc>
<lastmod>2019-03-24</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/pod-webhooks/services/</loc>
<lastmod>2019-03-24</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/pod-webhooks/canary/</loc>
<lastmod>2019-03-24</lastmod>
<changefreq>daily</changefreq>
</url>
</urlset>

BIN
sitemap.xml.gz

Binary file not shown.

6
utils-www/README.md

@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
# utils-www
`static_clone.py` - clones a repo with a separate git and working dir
`clone_into_volume.sh` - use docker cp and docker exec to copy the above script
into the container and execute it

21
utils-www/clone_into_volume.sh

@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
#!/bin/bash
NAME="podwebhooks_stormy_captain_hook_1"
SCRIPT="static_clone.py"
EXTRA="static_domains.py"
set -x
# copy stuff into container
docker cp ${SCRIPT} ${NAME}:/tmp/${SCRIPT}
docker cp ${EXTRA} ${NAME}:/tmp/${EXTRA}
# execute order 66
docker exec -it ${NAME} python /tmp/${SCRIPT}
# clean up
docker exec -it ${NAME} rm -f /tmp/${SCRIPT} /tmp/${EXTRA}
set +x

22
utils-www/pull_inside_volume.sh

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
#!/bin/bash
NAME="podwebhooks_stormy_captain_hook_1"
SCRIPT="static_pull.py"
EXTRA="static_domains.py"
set -x
# copy stuff into container
docker cp ${SCRIPT} ${NAME}:/tmp/${SCRIPT}
docker cp ${EXTRA} ${NAME}:/tmp/${EXTRA}
# execute order 66
docker exec -it ${NAME} python /tmp/${SCRIPT}
# clean up
docker exec -it ${NAME} rm -f /tmp/${SCRIPT} /tmp/${EXTRA}
set +x

32
utils-www/static_clone.py

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
import subprocess
import os
from static_domains import onepagers
if( os.path.isdir('/www') is False ):
mkdircmd = ["mkdir","/www"]
subprocess.call(mkdircmd)
for name in onepagers:
url = onepagers[name]
basedir = os.path.join("/www",name)
mkdircmd = ["mkdir","-p",basedir]
clonecmd = ["git","-C",basedir,"clone","--separate-git-dir=git","-b","gh-pages",url,"htdocs"]
if( os.path.isdir( os.path.join(basedir,"git") )
and os.path.isdir( os.path.join(basedir,"htdocs")) ):
print(" ")
print(" ")
print("ERROR: The directories /www/%s/git and /www/%s/htodcs"%(name,name))
print(" already exist. Use the pull script instead. ")
print(" ")
exit(1)
print(" ")
print("About to run the command:")
print(" $ " + " ".join(clonecmd))
print(" ")
subprocess.call(mkdircmd)
subprocess.call(clonecmd)

6
utils-www/static_domains.py

@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
onepagers = {
'pages.charlesreid1.com' : 'https://git.charlesreid1.com/charlesreid1/pages.charlesreid1.com',
'hooks.charlesreid1.com' : 'https://git.charlesreid1.com/charlesreid1/hooks.charlesreid1.com',
'bots.charlesreid1.com' : 'https://git.charlesreid1.com/charlesreid1/bots.charlesreid1.com'
}

36
utils-www/static_pull.py

@ -1,36 +0,0 @@ @@ -1,36 +0,0 @@
import subprocess
import os
from static_domains import onepagers
if( os.path.isdir('/www') is False ):
print(" ")
print(" ")
print("ERROR: The /www directory does not exist.")
print(" Run the clone script instead.")
print(" ")
print(" ")
exit(1)
for name in onepagers:
url = onepagers[name]
basedir = os.path.join("/www",name)
pullcmd = ["git","-C",basedir,"--git-dir=git","--work-tree=htdocs","pull","origin","gh-pages"]
if( os.path.isdir( os.path.join(basedir,"git") is False )
or os.path.isdir( os.path.join(basedir,"htdocs")) is False ):
print(" ")
print(" ")
print("ERROR: The directories /www/%s/git and /www/%s/htodcs"%(name,name))
print(" do not exist. Use the clone script instead. ")
print(" ")
exit(1)
print(" ")
print("About to run the command:")
print(" $ " + " ".join(pullcmd))
print(" ")
subprocess.call(pullcmd)
Loading…
Cancel
Save