runsheets 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +98 -0
- data/LICENSE.txt +21 -0
- data/README.md +277 -0
- data/bin/runsheets +12 -0
- data/examples/about-the-examples.md +40 -0
- data/examples/directory_based_runbooks/hello/rollback.md +11 -0
- data/examples/directory_based_runbooks/hello/runbook.md +40 -0
- data/examples/directory_based_runbooks/hello/steps/010-say-hello.md +33 -0
- data/examples/directory_based_runbooks/hello/steps/020-inspect-ruby.md +28 -0
- data/examples/directory_based_runbooks/hello/steps/030-take-a-breath.md +11 -0
- data/examples/directory_based_runbooks/hello/steps/035-keep-a-clock-running.md +21 -0
- data/examples/directory_based_runbooks/hello/steps/040-exercise-failure.md +26 -0
- data/examples/directory_based_runbooks/hello/steps/045-check-the-greeting.md +18 -0
- data/examples/directory_based_runbooks/hello/verify.md +18 -0
- data/examples/directory_based_runbooks/staging-teardown/rollback.md +28 -0
- data/examples/directory_based_runbooks/staging-teardown/runbook.md +57 -0
- data/examples/directory_based_runbooks/staging-teardown/steps/010-confirm-nothing-to-preserve.md +18 -0
- data/examples/directory_based_runbooks/staging-teardown/steps/020-snapshot-the-database.md +47 -0
- data/examples/directory_based_runbooks/staging-teardown/steps/030-stop-the-pipeline.md +32 -0
- data/examples/directory_based_runbooks/staging-teardown/steps/040-drain-the-ecs-services.md +35 -0
- data/examples/directory_based_runbooks/staging-teardown/steps/050-record-the-final-row-counts.md +41 -0
- data/examples/directory_based_runbooks/staging-teardown/steps/060-delete-the-stack.md +56 -0
- data/examples/directory_based_runbooks/staging-teardown/verify.md +40 -0
- data/examples/single_md_file_runbooks/db-maintenance.md +163 -0
- data/examples/single_md_file_runbooks/disk-space-triage.md +90 -0
- data/examples/single_md_file_runbooks/disk-usage-glossary.md +48 -0
- data/examples/single_md_file_runbooks/policies/cleanup-policy.md +33 -0
- data/examples/single_md_file_runbooks/policies/images/triage-flow.svg +44 -0
- data/examples/single_md_file_runbooks/runbooks_with_scripts/.loki +17 -0
- data/examples/single_md_file_runbooks/runbooks_with_scripts/asgard-tasks.md +135 -0
- data/examples/single_md_file_runbooks/runbooks_with_scripts/checks.loki +27 -0
- data/examples/single_md_file_runbooks/runbooks_with_scripts/greet.loki +6 -0
- data/lib/runsheets/assets.rb +780 -0
- data/lib/runsheets/block.rb +118 -0
- data/lib/runsheets/cli.rb +424 -0
- data/lib/runsheets/config/defaults.yml +44 -0
- data/lib/runsheets/config.rb +139 -0
- data/lib/runsheets/diff.rb +67 -0
- data/lib/runsheets/execution.rb +144 -0
- data/lib/runsheets/executor.rb +157 -0
- data/lib/runsheets/expectation.rb +101 -0
- data/lib/runsheets/fences.rb +172 -0
- data/lib/runsheets/front_matter.rb +29 -0
- data/lib/runsheets/library.rb +268 -0
- data/lib/runsheets/pages/chooser.rb +408 -0
- data/lib/runsheets/pages/search.rb +119 -0
- data/lib/runsheets/pages/tree.rb +88 -0
- data/lib/runsheets/pages.rb +947 -0
- data/lib/runsheets/redactor.rb +88 -0
- data/lib/runsheets/renderer.rb +229 -0
- data/lib/runsheets/run.rb +330 -0
- data/lib/runsheets/run_record.rb +371 -0
- data/lib/runsheets/runbook.rb +301 -0
- data/lib/runsheets/search.rb +129 -0
- data/lib/runsheets/session.rb +307 -0
- data/lib/runsheets/session_log.rb +114 -0
- data/lib/runsheets/single_file.rb +93 -0
- data/lib/runsheets/step.rb +91 -0
- data/lib/runsheets/version.rb +5 -0
- data/lib/runsheets/web.rb +537 -0
- data/lib/runsheets.rb +90 -0
- data/sig/runsheets.rbs +4 -0
- metadata +226 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Cleanup policy
|
|
2
|
+
|
|
3
|
+
What may be deleted to free space, and what may not. Used by the
|
|
4
|
+
[disk space triage](../disk-space-triage.md) runbook. Terms are explained
|
|
5
|
+
in the [glossary](../disk-usage-glossary.md).
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Safe to delete
|
|
10
|
+
|
|
11
|
+
- Build caches and intermediate artifacts the next build recreates.
|
|
12
|
+
- Package manager caches (`~/.cache`, `~/.npm/_cacache`, gem and bundler
|
|
13
|
+
caches).
|
|
14
|
+
- Rotated and compressed logs older than 14 days.
|
|
15
|
+
- Anything under `/tmp` older than a day that no running process holds open.
|
|
16
|
+
|
|
17
|
+
## Ask first
|
|
18
|
+
|
|
19
|
+
- Uncompressed logs of a service that is still running. Truncate them
|
|
20
|
+
instead of deleting, so the service keeps writing to the same file.
|
|
21
|
+
- Container images and volumes. An unused-looking volume may hold the only
|
|
22
|
+
copy of something.
|
|
23
|
+
|
|
24
|
+
## Never delete
|
|
25
|
+
|
|
26
|
+
- Database files, even when the database is stopped.
|
|
27
|
+
- Anything under a backup or snapshot directory.
|
|
28
|
+
- Files you cannot identify. Find their owner first.
|
|
29
|
+
|
|
30
|
+
## When something was deleted by mistake
|
|
31
|
+
|
|
32
|
+
Stop, do not write more to that file system, and contact the owner of the
|
|
33
|
+
host. Restore from backup before trying anything clever.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 150" width="760" height="150" role="img" aria-labelledby="t d">
|
|
2
|
+
<title id="t">Disk space triage</title>
|
|
3
|
+
<desc id="d">Measure with df, find with du, check the cleanup policy, clean by hand, then verify use is under the threshold; loop back to find if it is not.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
6
|
+
<path d="M0 0 10 5 0 10z" fill="#8b95a8"/>
|
|
7
|
+
</marker>
|
|
8
|
+
</defs>
|
|
9
|
+
<g font-family="-apple-system, Segoe UI, Helvetica, Arial, sans-serif" font-size="14" text-anchor="middle">
|
|
10
|
+
<g>
|
|
11
|
+
<rect x="10" y="40" width="120" height="56" rx="10" fill="#10263d" stroke="#5ab0ff" stroke-width="1.5"/>
|
|
12
|
+
<text x="70" y="64" fill="#d9dee8" font-weight="600">Measure</text>
|
|
13
|
+
<text x="70" y="83" fill="#8b95a8" font-size="12" font-family="ui-monospace, Menlo, monospace">df -h</text>
|
|
14
|
+
</g>
|
|
15
|
+
<g>
|
|
16
|
+
<rect x="160" y="40" width="120" height="56" rx="10" fill="#10263d" stroke="#5ab0ff" stroke-width="1.5"/>
|
|
17
|
+
<text x="220" y="64" fill="#d9dee8" font-weight="600">Find</text>
|
|
18
|
+
<text x="220" y="83" fill="#8b95a8" font-size="12" font-family="ui-monospace, Menlo, monospace">du -sh</text>
|
|
19
|
+
</g>
|
|
20
|
+
<g>
|
|
21
|
+
<rect x="310" y="40" width="130" height="56" rx="10" fill="#211a3a" stroke="#a78bfa" stroke-width="1.5"/>
|
|
22
|
+
<text x="375" y="64" fill="#d9dee8" font-weight="600">Check policy</text>
|
|
23
|
+
<text x="375" y="83" fill="#8b95a8" font-size="12">plain document</text>
|
|
24
|
+
</g>
|
|
25
|
+
<g>
|
|
26
|
+
<rect x="470" y="40" width="120" height="56" rx="10" fill="#33240f" stroke="#ffb454" stroke-width="1.5"/>
|
|
27
|
+
<text x="530" y="64" fill="#d9dee8" font-weight="600">Clean</text>
|
|
28
|
+
<text x="530" y="83" fill="#8b95a8" font-size="12">by hand</text>
|
|
29
|
+
</g>
|
|
30
|
+
<g>
|
|
31
|
+
<rect x="620" y="40" width="130" height="56" rx="10" fill="#0f2e24" stroke="#3ddc97" stroke-width="1.5"/>
|
|
32
|
+
<text x="685" y="64" fill="#d9dee8" font-weight="600">Verify</text>
|
|
33
|
+
<text x="685" y="83" fill="#8b95a8" font-size="12">use ≤ threshold</text>
|
|
34
|
+
</g>
|
|
35
|
+
<g stroke="#8b95a8" stroke-width="1.5" fill="none" marker-end="url(#arrow)">
|
|
36
|
+
<path d="M130 68h28"/>
|
|
37
|
+
<path d="M280 68h28"/>
|
|
38
|
+
<path d="M440 68h28"/>
|
|
39
|
+
<path d="M590 68h28"/>
|
|
40
|
+
<path d="M685 96v28H220v-26" stroke-dasharray="5 4"/>
|
|
41
|
+
</g>
|
|
42
|
+
<text x="452" y="140" fill="#8b95a8" font-size="12">still over: find more</text>
|
|
43
|
+
</g>
|
|
44
|
+
</svg>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Asgard entry point for the asgard-tasks.md example runbook.
|
|
3
|
+
#
|
|
4
|
+
# asgard looks for a .loki file in its working directory, then in each
|
|
5
|
+
# directory above it. runsheets runs a single-file runbook's blocks in the
|
|
6
|
+
# runbook's own directory, so `asgard` in one of its blocks finds this file
|
|
7
|
+
# first, ahead of the repository's own .loki further up.
|
|
8
|
+
#
|
|
9
|
+
# This file loads the task files beside it (the glob skips .loki itself):
|
|
10
|
+
# greet.loki greet NAME
|
|
11
|
+
# checks.loki ruby_check, disk_check [DIR], and health, which runs both
|
|
12
|
+
|
|
13
|
+
import "*.loki"
|
|
14
|
+
|
|
15
|
+
class Tasks
|
|
16
|
+
header "runbook tasks: defined beside asgard-tasks.md"
|
|
17
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Runbook tasks from local .loki files
|
|
3
|
+
when_to_use: >
|
|
4
|
+
An example of a runbook whose blocks call asgard tasks defined in .loki
|
|
5
|
+
files kept beside it, so a long or reusable script lives in a task file
|
|
6
|
+
and the runbook block stays one line.
|
|
7
|
+
prerequisites:
|
|
8
|
+
- The `asgard` command on PATH (`gem install asgard`)
|
|
9
|
+
escalation: Nobody; this runbook only reads.
|
|
10
|
+
tags: [asgard, loki, scripts, safe, example]
|
|
11
|
+
inputs:
|
|
12
|
+
- name: NAME
|
|
13
|
+
prompt: Who to greet
|
|
14
|
+
default: operator
|
|
15
|
+
- name: TARGET_DIR
|
|
16
|
+
prompt: Directory whose file system disk_check measures
|
|
17
|
+
default: /tmp
|
|
18
|
+
- name: MAX_USE
|
|
19
|
+
prompt: Highest acceptable disk use, in percent
|
|
20
|
+
default: "95"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Runbook tasks from local .loki files
|
|
24
|
+
|
|
25
|
+
This runbook is one markdown file, and its scripts are
|
|
26
|
+
[asgard](https://github.com/MadBomber/asgard) tasks in `.loki` files in
|
|
27
|
+
the same directory:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
runbooks_with_scripts/
|
|
31
|
+
asgard-tasks.md this runbook
|
|
32
|
+
.loki asgard's entry point: imports the other .loki files
|
|
33
|
+
greet.loki greet NAME
|
|
34
|
+
checks.loki ruby_check, disk_check [DIR], and health, which runs both
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Two facts make it work:
|
|
38
|
+
|
|
39
|
+
- runsheets runs a single-file runbook's blocks in the directory holding
|
|
40
|
+
the runbook (a step's `cwd` can change that).
|
|
41
|
+
- asgard looks for a `.loki` file in its working directory first, then in
|
|
42
|
+
each directory above. The `.loki` here is found before any other, such as
|
|
43
|
+
the one at the root of the runsheets repository.
|
|
44
|
+
|
|
45
|
+
The `.loki` file marks the directory as asgard's project root and loads
|
|
46
|
+
the task files beside it:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
import "*.loki"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Each task file reopens `class Tasks`, as in `greet.loki`:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
class Tasks
|
|
56
|
+
desc "greet NAME", "Say hello to NAME"
|
|
57
|
+
def greet(name = "World") = puts "Hello, #{name}, from a task beside the runbook!"
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A block then calls the task by name, with runbook inputs as arguments or
|
|
62
|
+
in the environment. Every block in this runbook only reads.
|
|
63
|
+
|
|
64
|
+
## Find the local task file
|
|
65
|
+
<!-- kind: verify, timeout: 30 -->
|
|
66
|
+
|
|
67
|
+
`asgard --doctor` reports which `.loki` file it is using. It should be the
|
|
68
|
+
one beside this runbook. The doctor's full report also lists every
|
|
69
|
+
imported file and the tasks each defines; the block prints only the line
|
|
70
|
+
that names the file in use.
|
|
71
|
+
|
|
72
|
+
```bash run
|
|
73
|
+
asgard --doctor | grep -o 'using .loki marker: [^[:cntrl:]]*'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```text expect
|
|
77
|
+
using .loki marker: {{any}}/runbooks_with_scripts/.loki
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## List the tasks
|
|
81
|
+
|
|
82
|
+
The task list comes from the local `.loki` files, together with asgard's
|
|
83
|
+
built-in commands (`help`, `schedule`, `tree`).
|
|
84
|
+
|
|
85
|
+
```bash run
|
|
86
|
+
asgard tree
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Run a task with an argument
|
|
90
|
+
<!-- timeout: 30 -->
|
|
91
|
+
|
|
92
|
+
`greet` is defined in `greet.loki`. The `NAME` input is passed as its
|
|
93
|
+
argument.
|
|
94
|
+
|
|
95
|
+
```bash run
|
|
96
|
+
asgard greet "$NAME"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```text expect
|
|
100
|
+
Hello, {{any}}, from a task beside the runbook!
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Run a task with dependencies
|
|
104
|
+
<!-- timeout: 60 -->
|
|
105
|
+
|
|
106
|
+
`health` in `checks.loki` declares `depends_on [:ruby_check, :disk_check]`,
|
|
107
|
+
so asgard runs both checks in parallel before it. A dependency gets no
|
|
108
|
+
arguments, so `disk_check` reads its directory from `TARGET_DIR` and its
|
|
109
|
+
limit from `MAX_USE`, both runbook inputs in the environment. If either
|
|
110
|
+
check fails, `health` does not run and the block fails.
|
|
111
|
+
|
|
112
|
+
```bash run
|
|
113
|
+
asgard health
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The two checks run in parallel and may print in either order.
|
|
117
|
+
|
|
118
|
+
```text expect
|
|
119
|
+
{{any}}_check: {{any}}
|
|
120
|
+
{{any}}_check: {{any}}
|
|
121
|
+
health: all checks passed
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Verify
|
|
125
|
+
|
|
126
|
+
Disk use under `TARGET_DIR` is at or below `MAX_USE`, checked by the same
|
|
127
|
+
task the health check runs, this time called directly with an argument.
|
|
128
|
+
|
|
129
|
+
```bash run
|
|
130
|
+
asgard disk_check "$TARGET_DIR"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Rollback
|
|
134
|
+
|
|
135
|
+
Nothing to undo: no task in this directory changes anything.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "shellwords"
|
|
4
|
+
|
|
5
|
+
class Tasks
|
|
6
|
+
desc "ruby_check", "Report the Ruby that asgard runs on"
|
|
7
|
+
def ruby_check = puts "ruby_check: ruby #{RUBY_VERSION}"
|
|
8
|
+
|
|
9
|
+
# DIR defaults to TARGET_DIR from the environment, which is how a runbook
|
|
10
|
+
# input reaches a task run as a dependency, with no arguments.
|
|
11
|
+
desc "disk_check [DIR]", "Fail when the file system holding DIR is more than MAX_USE percent full"
|
|
12
|
+
def disk_check(dir = env(:target_dir, "."))
|
|
13
|
+
used = disk_use(dir)
|
|
14
|
+
limit = env(:max_use, "95").to_i
|
|
15
|
+
puts "disk_check: #{dir} is #{used}% used, limit #{limit}%"
|
|
16
|
+
exit 1 if used > limit
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
depends_on [:ruby_check, :disk_check]
|
|
20
|
+
desc "Run every check, in parallel"
|
|
21
|
+
def health = puts "health: all checks passed"
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# Percent used of the file system holding +dir+, from POSIX df output.
|
|
26
|
+
def disk_use(dir) = `df -P #{Shellwords.escape(dir)}`.lines.last.split[4].to_i
|
|
27
|
+
end
|