Add pre-commit hooks for code quality #19

Merged
eblume merged 1 commit from add-pre-commit into main 2026-01-16 19:33:03 -08:00
57 changed files with 1013 additions and 625 deletions
Showing only changes of commit 5894d134a8 - Show all commits

Add pre-commit hooks for code quality and fix all lint violations

Introduces pre-commit framework with hooks for:
- General file hygiene (trailing whitespace, EOF, large files)
- Secret detection (TruffleHog)
- YAML linting (yamllint)
- Ansible linting (ansible-lint)
- Python linting/formatting (ruff)
- Shell script analysis (shellcheck, shfmt)
- TOML formatting (taplo)
- JSON formatting (prettier)

Fixes 91+ ansible-lint violations:
- Renamed variables to use role prefixes (e.g., brew_start -> alloy_brew_start)
- Capitalized handler names per convention
- Added changed_when to command tasks
- Fixed template usage in task names

Fixes shellcheck warnings:
- Removed unused variables
- Fixed SC2155 (declare and assign separately)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Erich Blume 2026-01-16 19:29:53 -08:00

19
.ansible-lint Normal file
View file

@ -0,0 +1,19 @@
---
# Ansible-lint configuration
# Set profile to production for stricter checking
profile: production
# Exclude paths
exclude_paths:
- .venv/
- pulumi/.venv/
# Make ansible-lint aware of project structure
project_dir: ansible
# Skip some rules that are too noisy for this project
skip_list:
- galaxy # Don't require galaxy metadata in roles
- yaml[line-length] # Don't enforce line length limits
- no-handler # Some tasks intentionally run conditionally, not as handlers

9
.gitignore vendored
View file

@ -1 +1,10 @@
.claude/settings.local.json .claude/settings.local.json
# Python
__pycache__/
*.py[cod]
*.pyo
.venv/
# OS
.DS_Store

82
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,82 @@
---
# See https://pre-commit.com for more information
# Run: uvx pre-commit run --all-files
# Install: uvx pre-commit install
repos:
# General file hygiene
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
args: ['--maxkb=1000']
- id: check-merge-conflict
- id: check-json
- id: check-yaml
args: ['--unsafe'] # Allow custom tags (ansible uses them)
- id: check-toml
# Secret detection
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.92.5
hooks:
- id: trufflehog
entry: trufflehog git file://. --since-commit HEAD --no-verification --fail
stages: [pre-commit, pre-push]
# YAML linting
- repo: https://github.com/adrienverge/yamllint
rev: v1.38.0
hooks:
- id: yamllint
args: ['-c', '.yamllint.yaml']
# Ansible linting
- repo: local
hooks:
- id: ansible-lint
name: ansible-lint
entry: env ANSIBLE_ROLES_PATH=ansible/roles ansible-lint
language: python
files: ^ansible/
additional_dependencies:
- ansible-lint>=26.1.1
- ansible-core>=2.15
# Python - ruff for linting and formatting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.13
hooks:
- id: ruff
args: ['--fix']
- id: ruff-format
# Shell scripts - shellcheck and shfmt
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
args: ['--severity=warning']
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.12.0-2
hooks:
- id: shfmt
args: ['-i', '2', '-ci', '-bn'] # 2-space indent, case indent, binary newline
# TOML - taplo
- repo: https://github.com/ComPWA/taplo-pre-commit
rev: v0.9.3
hooks:
- id: taplo-format
- id: taplo-lint
# JSON formatting (prettier for consistent style)
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.8.0
hooks:
- id: prettier
types_or: [json]
args: ['--tab-width', '2']

29
.yamllint.yaml Normal file
View file

@ -0,0 +1,29 @@
---
extends: default
rules:
line-length:
max: 120
level: warning
truthy:
allowed-values: ['true', 'false', 'yes', 'no']
comments:
min-spaces-from-content: 1
braces:
min-spaces-inside: 0
max-spaces-inside: 1
brackets:
min-spaces-inside: 0
max-spaces-inside: 0
indentation:
spaces: 2
indent-sequences: consistent
# Required for ansible-lint compatibility
comments-indentation: false
octal-values:
forbid-implicit-octal: true
forbid-explicit-octal: true
ignore:
- .venv/
- pulumi/.venv/

View file

@ -49,6 +49,31 @@ LLM-assisted development. I want to include a personal note here that I don't
know entirely how I feel about LLMs in our current era, but it felt important know entirely how I feel about LLMs in our current era, but it felt important
to learn. to learn.
## Development
### Pre-commit Hooks
This repo uses [pre-commit](https://pre-commit.com) for code quality and consistency. Install hooks with:
```bash
uvx pre-commit install
```
Run all hooks manually:
```bash
uvx pre-commit run --all-files
```
Hooks include:
- **General**: trailing whitespace, end-of-file fixer, large files, merge conflicts
- **Secrets**: [TruffleHog](https://github.com/trufflesecurity/trufflehog) for secret detection
- **YAML**: yamllint, ansible-lint
- **Python**: ruff (linting + formatting)
- **Shell**: shellcheck, shfmt
- **TOML**: taplo
- **JSON**: prettier
## Documentation ## Documentation
Detailed documentation lives in my personal zettelkasten, which is not included in this repository. You can view the docs with: Detailed documentation lives in my personal zettelkasten, which is not included in this repository. You can view the docs with:

View file

@ -1,3 +1,4 @@
---
all: all:
children: children:
servers: servers:

View file

@ -19,7 +19,7 @@
- name: Set PostgreSQL superuser password fact - name: Set PostgreSQL superuser password fact
ansible.builtin.set_fact: ansible.builtin.set_fact:
pg_superuser_password: "{{ _pg_superuser_pw.stdout }}" postgresql_superuser_password: "{{ _pg_superuser_pw.stdout }}"
no_log: true no_log: true
tags: [postgresql] tags: [postgresql]
@ -67,7 +67,7 @@
- name: Build PostgreSQL user password lookup - name: Build PostgreSQL user password lookup
ansible.builtin.set_fact: ansible.builtin.set_fact:
pg_user_passwords: postgresql_user_passwords:
miniflux: "{{ _miniflux_db_pw.stdout }}" miniflux: "{{ _miniflux_db_pw.stdout }}"
borgmatic: "{{ _borgmatic_db_pw.stdout }}" borgmatic: "{{ _borgmatic_db_pw.stdout }}"
alloy: "{{ _pg_alloy_pw.stdout }}" alloy: "{{ _pg_alloy_pw.stdout }}"

View file

@ -1,5 +1,6 @@
--- ---
- name: restart alloy - name: Restart alloy
ansible.builtin.command: brew services restart grafana-alloy ansible.builtin.command: brew services restart grafana-alloy
async: 120 async: 120
poll: 0 poll: 0
changed_when: true

View file

@ -31,7 +31,9 @@
- name: Fetch PostgreSQL metrics password from 1Password - name: Fetch PostgreSQL metrics password from 1Password
ansible.builtin.command: ansible.builtin.command:
cmd: op --vault {{ alloy_op_vault }} item get {{ alloy_op_postgres_item }} --fields {{ alloy_op_postgres_field }} --reveal cmd: >-
op --vault {{ alloy_op_vault }} item get {{ alloy_op_postgres_item }}
--fields {{ alloy_op_postgres_field }} --reveal
delegate_to: localhost delegate_to: localhost
register: alloy_postgres_password_result register: alloy_postgres_password_result
changed_when: false changed_when: false
@ -55,7 +57,7 @@
src: postgres_queries.yaml.j2 src: postgres_queries.yaml.j2
dest: "{{ alloy_config_dir }}/postgres_queries.yaml" dest: "{{ alloy_config_dir }}/postgres_queries.yaml"
mode: '0600' mode: '0600'
notify: restart alloy notify: Restart alloy
when: alloy_collect_postgres | default(false) when: alloy_collect_postgres | default(false)
- name: Deploy alloy configuration - name: Deploy alloy configuration
@ -63,11 +65,11 @@
src: config.alloy.j2 src: config.alloy.j2
dest: "{{ alloy_config_dir }}/config.alloy" dest: "{{ alloy_config_dir }}/config.alloy"
mode: '0600' mode: '0600'
notify: restart alloy notify: Restart alloy
no_log: true no_log: true
- name: Ensure alloy service is started - name: Ensure alloy service is started
ansible.builtin.command: brew services start grafana-alloy ansible.builtin.command: brew services start grafana-alloy
register: brew_start register: alloy_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in alloy_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -1,5 +1,6 @@
--- ---
- name: reload borgmatic - name: Reload borgmatic
ansible.builtin.shell: | ansible.builtin.shell: |
launchctl unload ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist 2>/dev/null || true launchctl unload ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist launchctl load ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist
changed_when: true

View file

@ -19,15 +19,16 @@
src: borgmatic.plist.j2 src: borgmatic.plist.j2
dest: ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist dest: ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist
mode: '0644' mode: '0644'
notify: reload borgmatic notify: Reload borgmatic
- name: Check if borgmatic LaunchAgent is loaded - name: Check if borgmatic LaunchAgent is loaded
ansible.builtin.command: launchctl list mcquack.eblume.borgmatic ansible.builtin.command: launchctl list mcquack.eblume.borgmatic
register: launchctl_check register: borgmatic_launchctl_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Load borgmatic LaunchAgent if not loaded - name: Load borgmatic LaunchAgent if not loaded
ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.borgmatic.plist
when: launchctl_check.rc != 0 when: borgmatic_launchctl_check.rc != 0
changed_when: true
failed_when: false failed_when: false

View file

@ -1,5 +1,6 @@
--- ---
- name: reload devpi - name: Reload devpi
ansible.builtin.shell: | ansible.builtin.shell: |
launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi.plist 2>/dev/null || true launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist
changed_when: true

View file

@ -40,15 +40,16 @@
src: devpi.plist.j2 src: devpi.plist.j2
dest: ~/Library/LaunchAgents/mcquack.eblume.devpi.plist dest: ~/Library/LaunchAgents/mcquack.eblume.devpi.plist
mode: '0644' mode: '0644'
notify: reload devpi notify: Reload devpi
- name: Check if devpi LaunchAgent is loaded - name: Check if devpi LaunchAgent is loaded
ansible.builtin.command: launchctl list mcquack.eblume.devpi ansible.builtin.command: launchctl list mcquack.eblume.devpi
register: launchctl_check register: devpi_launchctl_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Load devpi LaunchAgent if not loaded - name: Load devpi LaunchAgent if not loaded
ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist
when: launchctl_check.rc != 0 when: devpi_launchctl_check.rc != 0
changed_when: true
failed_when: false failed_when: false

View file

@ -1,5 +1,6 @@
--- ---
- name: reload devpi-metrics - name: Reload devpi-metrics
ansible.builtin.shell: | ansible.builtin.shell: |
launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist 2>/dev/null || true launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist
changed_when: true

View file

@ -22,15 +22,16 @@
src: devpi-metrics.plist.j2 src: devpi-metrics.plist.j2
dest: ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist dest: ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist
mode: '0644' mode: '0644'
notify: reload devpi-metrics notify: Reload devpi-metrics
- name: Check if devpi-metrics LaunchAgent is loaded - name: Check if devpi-metrics LaunchAgent is loaded
ansible.builtin.command: launchctl list mcquack.eblume.devpi-metrics ansible.builtin.command: launchctl list mcquack.eblume.devpi-metrics
register: launchctl_check register: devpi_metrics_launchctl_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Load devpi-metrics LaunchAgent if not loaded - name: Load devpi-metrics LaunchAgent if not loaded
ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist
when: launchctl_check.rc != 0 when: devpi_metrics_launchctl_check.rc != 0
changed_when: true
failed_when: false failed_when: false

View file

@ -1,3 +1,4 @@
--- ---
- name: restart forgejo - name: Restart forgejo
ansible.builtin.command: brew services restart forgejo ansible.builtin.command: brew services restart forgejo
changed_when: true

View file

@ -18,11 +18,12 @@
Forgejo config not found at /opt/homebrew/var/forgejo/custom/conf/app.ini Forgejo config not found at /opt/homebrew/var/forgejo/custom/conf/app.ini
This file contains secrets and is not managed by ansible. This file contains secrets and is not managed by ansible.
To restore from backup, run: To restore from backup, run:
borgmatic --config ~/.config/borgmatic/config.yaml extract --archive latest --path /opt/homebrew/var/forgejo/custom/conf/app.ini borgmatic --config ~/.config/borgmatic/config.yaml extract --archive latest \
--path /opt/homebrew/var/forgejo/custom/conf/app.ini
when: not forgejo_config.stat.exists when: not forgejo_config.stat.exists
- name: Ensure forgejo service is started - name: Ensure forgejo service is started
ansible.builtin.command: brew services start forgejo ansible.builtin.command: brew services start forgejo
register: brew_start register: forgejo_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in forgejo_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -116,9 +116,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -183,9 +181,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -194,7 +190,12 @@
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 },
"id": 4, "id": 4,
"options": { "options": {
"legend": {"calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true}, "legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "single", "sort": "none" } "tooltip": { "mode": "single", "sort": "none" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",
@ -249,9 +250,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -260,7 +259,12 @@
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 },
"id": 5, "id": 5,
"options": { "options": {
"legend": {"calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true}, "legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "single", "sort": "none" } "tooltip": { "mode": "single", "sort": "none" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",
@ -315,9 +319,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -326,7 +328,12 @@
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 12 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 12 },
"id": 6, "id": 6,
"options": { "options": {
"legend": {"calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true}, "legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "single", "sort": "none" } "tooltip": { "mode": "single", "sort": "none" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",
@ -360,9 +367,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },

View file

@ -69,9 +69,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
}, },
@ -115,9 +113,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
}, },
@ -239,7 +235,12 @@
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 },
"id": 5, "id": 5,
"options": { "options": {
"legend": { "calcs": ["mean", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true }, "legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",
@ -303,7 +304,12 @@
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 },
"id": 6, "id": 6,
"options": { "options": {
"legend": { "calcs": ["mean", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true }, "legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",
@ -361,7 +367,12 @@
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 12 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 12 },
"id": 7, "id": 7,
"options": { "options": {
"legend": { "calcs": ["lastNotNull"], "displayMode": "table", "placement": "bottom", "showLegend": true }, "legend": {
"calcs": ["lastNotNull"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",
@ -425,7 +436,12 @@
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 12 }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 12 },
"id": 8, "id": 8,
"options": { "options": {
"legend": { "calcs": ["sum"], "displayMode": "table", "placement": "bottom", "showLegend": true }, "legend": {
"calcs": ["sum"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"pluginVersion": "10.0.0", "pluginVersion": "10.0.0",

View file

@ -37,7 +37,11 @@
"graphMode": "none", "graphMode": "none",
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto" "textMode": "auto"
}, },
"targets": [ "targets": [
@ -71,7 +75,11 @@
"graphMode": "none", "graphMode": "none",
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto" "textMode": "auto"
}, },
"targets": [ "targets": [
@ -105,7 +113,11 @@
"graphMode": "none", "graphMode": "none",
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto" "textMode": "auto"
}, },
"targets": [ "targets": [
@ -144,7 +156,11 @@
"graphMode": "area", "graphMode": "area",
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto" "textMode": "auto"
}, },
"targets": [ "targets": [
@ -183,7 +199,11 @@
"graphMode": "area", "graphMode": "area",
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto" "textMode": "auto"
}, },
"targets": [ "targets": [
@ -222,7 +242,11 @@
"graphMode": "area", "graphMode": "area",
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto" "textMode": "auto"
}, },
"targets": [ "targets": [
@ -281,26 +305,51 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byName", "options": "user" }, "matcher": { "id": "byName", "options": "user" },
"properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "system" }, "matcher": { "id": "byName", "options": "system" },
"properties": [{"id": "color", "value": {"fixedColor": "orange", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "orange", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "nice" }, "matcher": { "id": "byName", "options": "nice" },
"properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "iowait" }, "matcher": { "id": "byName", "options": "iowait" },
"properties": [{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "red", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 6 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 6 },
"id": 10, "id": 10,
"options": { "options": {
"legend": {"calcs": ["mean", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -350,22 +399,42 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byName", "options": "1m" }, "matcher": { "id": "byName", "options": "1m" },
"properties": [{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "red", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "5m" }, "matcher": { "id": "byName", "options": "5m" },
"properties": [{"id": "color", "value": {"fixedColor": "orange", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "orange", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "15m" }, "matcher": { "id": "byName", "options": "15m" },
"properties": [{"id": "color", "value": {"fixedColor": "yellow", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "yellow", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 6 }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 6 },
"id": 11, "id": 11,
"options": { "options": {
"legend": {"calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "max", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -436,30 +505,60 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byName", "options": "Wired" }, "matcher": { "id": "byName", "options": "Wired" },
"properties": [{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "red", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "Active" }, "matcher": { "id": "byName", "options": "Active" },
"properties": [{"id": "color", "value": {"fixedColor": "orange", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "orange", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "Compressed" }, "matcher": { "id": "byName", "options": "Compressed" },
"properties": [{"id": "color", "value": {"fixedColor": "purple", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "purple", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "Inactive" }, "matcher": { "id": "byName", "options": "Inactive" },
"properties": [{"id": "color", "value": {"fixedColor": "yellow", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "yellow", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "Free" }, "matcher": { "id": "byName", "options": "Free" },
"properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 15 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 15 },
"id": 20, "id": 20,
"options": { "options": {
"legend": {"calcs": ["mean", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -522,7 +621,11 @@
"id": 21, "id": 21,
"options": { "options": {
"orientation": "auto", "orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"showThresholdLabels": false, "showThresholdLabels": false,
"showThresholdMarkers": true "showThresholdMarkers": true
}, },
@ -572,18 +675,33 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byName", "options": "Used" }, "matcher": { "id": "byName", "options": "Used" },
"properties": [{"id": "color", "value": {"fixedColor": "orange", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "orange", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byName", "options": "Total" }, "matcher": { "id": "byName", "options": "Total" },
"properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 8, "x": 16, "y": 15 }, "gridPos": { "h": 8, "w": 8, "x": 16, "y": 15 },
"id": 22, "id": 22,
"options": { "options": {
"legend": {"calcs": ["mean", "lastNotNull"], "displayMode": "table", "placement": "bottom", "showLegend": true}, "legend": {
"calcs": ["mean", "lastNotNull"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -647,18 +765,33 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byRegexp", "options": ".*Read.*" }, "matcher": { "id": "byRegexp", "options": ".*Read.*" },
"properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byRegexp", "options": ".*Write.*" }, "matcher": { "id": "byRegexp", "options": ".*Write.*" },
"properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 24 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 24 },
"id": 30, "id": 30,
"options": { "options": {
"legend": {"calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "max", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -714,18 +847,33 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byRegexp", "options": ".*Read.*" }, "matcher": { "id": "byRegexp", "options": ".*Read.*" },
"properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byRegexp", "options": ".*Write.*" }, "matcher": { "id": "byRegexp", "options": ".*Write.*" },
"properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 24 }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 24 },
"id": 31, "id": 31,
"options": { "options": {
"legend": {"calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "max", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -780,7 +928,11 @@
"minVizHeight": 10, "minVizHeight": 10,
"minVizWidth": 0, "minVizWidth": 0,
"orientation": "horizontal", "orientation": "horizontal",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"showUnfilled": true, "showUnfilled": true,
"valueMode": "color" "valueMode": "color"
}, },
@ -833,7 +985,12 @@
"gridPos": { "h": 6, "w": 12, "x": 12, "y": 33 }, "gridPos": { "h": 6, "w": 12, "x": 12, "y": 33 },
"id": 41, "id": 41,
"options": { "options": {
"legend": {"calcs": ["lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -891,18 +1048,33 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byRegexp", "options": ".*Receive.*" }, "matcher": { "id": "byRegexp", "options": ".*Receive.*" },
"properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byRegexp", "options": ".*Transmit.*" }, "matcher": { "id": "byRegexp", "options": ".*Transmit.*" },
"properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 40 }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 40 },
"id": 50, "id": 50,
"options": { "options": {
"legend": {"calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "max", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -958,18 +1130,33 @@
"overrides": [ "overrides": [
{ {
"matcher": { "id": "byRegexp", "options": ".*Receive.*" }, "matcher": { "id": "byRegexp", "options": ".*Receive.*" },
"properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
]
}, },
{ {
"matcher": { "id": "byRegexp", "options": ".*Transmit.*" }, "matcher": { "id": "byRegexp", "options": ".*Transmit.*" },
"properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}] "properties": [
{
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
]
} }
] ]
}, },
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 40 }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 40 },
"id": 51, "id": 51,
"options": { "options": {
"legend": {"calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["mean", "max", "lastNotNull"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [
@ -1027,7 +1214,12 @@
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 48 }, "gridPos": { "h": 8, "w": 24, "x": 0, "y": 48 },
"id": 52, "id": 52,
"options": { "options": {
"legend": {"calcs": ["sum"], "displayMode": "table", "placement": "right", "showLegend": true}, "legend": {
"calcs": ["sum"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" } "tooltip": { "mode": "multi", "sort": "desc" }
}, },
"targets": [ "targets": [

View file

@ -19,8 +19,18 @@
"mode": "thresholds" "mode": "thresholds"
}, },
"mappings": [ "mappings": [
{"options": {"0": {"color": "red", "index": 0, "text": "DOWN"}}, "type": "value"}, {
{"options": {"1": {"color": "green", "index": 1, "text": "UP"}}, "type": "value"} "options": {
"0": { "color": "red", "index": 0, "text": "DOWN" }
},
"type": "value"
},
{
"options": {
"1": { "color": "green", "index": 1, "text": "UP" }
},
"type": "value"
}
], ],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
@ -71,9 +81,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "blue", "value": null }]
{"color": "blue", "value": null}
]
}, },
"unit": "string" "unit": "string"
}, },
@ -215,9 +223,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "purple", "value": null }]
{"color": "purple", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -262,9 +268,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "blue", "value": null }]
{"color": "blue", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -309,9 +313,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -356,9 +358,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "orange", "value": null }]
{"color": "orange", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -403,9 +403,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "purple", "value": null }]
{"color": "purple", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -481,9 +479,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -491,13 +487,19 @@
{ {
"matcher": { "id": "byName", "options": "Playing" }, "matcher": { "id": "byName", "options": "Playing" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
] ]
}, },
{ {
"matcher": { "id": "byName", "options": "Paused" }, "matcher": { "id": "byName", "options": "Paused" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "yellow", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "yellow", "mode": "fixed" }
}
] ]
} }
] ]
@ -579,9 +581,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -589,13 +589,19 @@
{ {
"matcher": { "id": "byName", "options": "Video Transcode" }, "matcher": { "id": "byName", "options": "Video Transcode" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "red", "mode": "fixed" }
}
] ]
}, },
{ {
"matcher": { "id": "byName", "options": "Audio Transcode" }, "matcher": { "id": "byName", "options": "Audio Transcode" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "orange", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "orange", "mode": "fixed" }
}
] ]
} }
] ]

View file

@ -65,9 +65,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
} }
@ -108,9 +106,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
} }
@ -151,9 +147,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "decbytes" "unit": "decbytes"
} }
@ -225,9 +219,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
} }
@ -300,9 +292,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "decbytes" "unit": "decbytes"
} }
@ -375,9 +365,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "ops" "unit": "ops"
} }
@ -465,9 +453,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
} }
@ -545,9 +531,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{ "color": "green", "value": null }
]
}, },
"unit": "short" "unit": "short"
} }

View file

@ -68,9 +68,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -114,9 +112,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "blue", "value": null }]
{"color": "blue", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -160,9 +156,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "orange", "value": null }]
{"color": "orange", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -206,9 +200,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "decbytes" "unit": "decbytes"
}, },
@ -252,9 +244,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "purple", "value": null }]
{"color": "purple", "value": null}
]
}, },
"unit": "decbytes" "unit": "decbytes"
}, },
@ -348,9 +338,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "decbytes" "unit": "decbytes"
}, },
@ -395,9 +383,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "blue", "value": null }]
{"color": "blue", "value": null}
]
}, },
"unit": "decbytes" "unit": "decbytes"
}, },
@ -473,9 +459,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "Bps" "unit": "Bps"
}, },
@ -483,13 +467,19 @@
{ {
"matcher": { "id": "byName", "options": "Download" }, "matcher": { "id": "byName", "options": "Download" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
] ]
}, },
{ {
"matcher": { "id": "byName", "options": "Upload" }, "matcher": { "id": "byName", "options": "Upload" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
] ]
} }
] ]
@ -571,9 +561,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "short" "unit": "short"
}, },
@ -662,9 +650,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "Bps" "unit": "Bps"
}, },
@ -672,13 +658,19 @@
{ {
"matcher": { "id": "byName", "options": "Download Rate" }, "matcher": { "id": "byName", "options": "Download Rate" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "green", "mode": "fixed" }
}
] ]
}, },
{ {
"matcher": { "id": "byName", "options": "Upload Rate" }, "matcher": { "id": "byName", "options": "Upload Rate" },
"properties": [ "properties": [
{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}} {
"id": "color",
"value": { "fixedColor": "blue", "mode": "fixed" }
}
] ]
} }
] ]
@ -761,9 +753,7 @@
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [{ "color": "green", "value": null }]
{"color": "green", "value": null}
]
}, },
"unit": "decbytes" "unit": "decbytes"
}, },

View file

@ -1,3 +1,4 @@
--- ---
- name: restart grafana - name: Restart grafana
ansible.builtin.command: brew services restart grafana ansible.builtin.command: brew services restart grafana
changed_when: true

View file

@ -19,31 +19,31 @@
src: grafana.ini.j2 src: grafana.ini.j2
dest: /opt/homebrew/etc/grafana/grafana.ini dest: /opt/homebrew/etc/grafana/grafana.ini
mode: '0644' mode: '0644'
notify: restart grafana notify: Restart grafana
- name: Deploy grafana datasources config - name: Deploy grafana datasources config
ansible.builtin.template: ansible.builtin.template:
src: datasources.yaml.j2 src: datasources.yaml.j2
dest: /opt/homebrew/etc/grafana/provisioning/datasources/datasources.yaml dest: /opt/homebrew/etc/grafana/provisioning/datasources/datasources.yaml
mode: '0644' mode: '0644'
notify: restart grafana notify: Restart grafana
- name: Deploy grafana dashboards provider config - name: Deploy grafana dashboards provider config
ansible.builtin.template: ansible.builtin.template:
src: dashboards.yaml.j2 src: dashboards.yaml.j2
dest: /opt/homebrew/etc/grafana/provisioning/dashboards/default.yaml dest: /opt/homebrew/etc/grafana/provisioning/dashboards/default.yaml
mode: '0644' mode: '0644'
notify: restart grafana notify: Restart grafana
- name: Deploy grafana dashboard JSON files - name: Deploy grafana dashboard JSON files
ansible.builtin.copy: ansible.builtin.copy:
src: "dashboards/" src: "dashboards/"
dest: /opt/homebrew/etc/grafana/provisioning/dashboards/ dest: /opt/homebrew/etc/grafana/provisioning/dashboards/
mode: '0644' mode: '0644'
notify: restart grafana notify: Restart grafana
- name: Ensure grafana service is started - name: Ensure grafana service is started
ansible.builtin.command: brew services start grafana ansible.builtin.command: brew services start grafana
register: brew_start register: grafana_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in grafana_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -1,5 +1,6 @@
--- ---
- name: restart kiwix-serve - name: Restart kiwix-serve
ansible.builtin.shell: | ansible.builtin.shell: |
launchctl unload ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist 2>/dev/null || true launchctl unload ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist
changed_when: true

View file

@ -11,7 +11,7 @@
- name: Check transmission daemon is responding - name: Check transmission daemon is responding
ansible.builtin.command: transmission-remote -l ansible.builtin.command: transmission-remote -l
register: transmission_check register: kiwix_transmission_check
changed_when: false changed_when: false
failed_when: false failed_when: false
when: kiwix_use_transmission when: kiwix_use_transmission
@ -19,7 +19,7 @@
- name: Fail if transmission is not running - name: Fail if transmission is not running
ansible.builtin.fail: ansible.builtin.fail:
msg: "Transmission daemon is not responding. Ensure transmission role ran successfully." msg: "Transmission daemon is not responding. Ensure transmission role ran successfully."
when: kiwix_use_transmission and transmission_check.rc != 0 when: kiwix_use_transmission and kiwix_transmission_check.rc != 0
# Find which declared archives don't have torrents yet (single shell command) # Find which declared archives don't have torrents yet (single shell command)
- name: Find declared archives missing from transmission - name: Find declared archives missing from transmission
@ -37,7 +37,7 @@
{% endfor %} {% endfor %}
args: args:
executable: /bin/bash executable: /bin/bash
register: missing_torrents register: kiwix_missing_torrents
changed_when: false changed_when: false
when: kiwix_use_transmission when: kiwix_use_transmission
@ -45,14 +45,14 @@
- name: Add missing torrents to transmission - name: Add missing torrents to transmission
ansible.builtin.command: > ansible.builtin.command: >
transmission-remote -a "{{ kiwix_torrent_base_url }}/{{ item }}.torrent" transmission-remote -a "{{ kiwix_torrent_base_url }}/{{ item }}.torrent"
loop: "{{ missing_torrents.stdout_lines | default([]) }}" loop: "{{ kiwix_missing_torrents.stdout_lines | default([]) }}"
loop_control: loop_control:
label: "{{ item | basename }}" label: "{{ item | basename }}"
when: when:
- kiwix_use_transmission - kiwix_use_transmission
- missing_torrents.stdout_lines | default([]) | length > 0 - kiwix_missing_torrents.stdout_lines | default([]) | length > 0
register: torrent_add register: kiwix_torrent_add
changed_when: torrent_add.rc == 0 changed_when: kiwix_torrent_add.rc == 0
# --- Kiwix startup: serve whatever completed ZIM files exist --- # --- Kiwix startup: serve whatever completed ZIM files exist ---
# This is decoupled from the declared inventory - it just serves what's available. # This is decoupled from the declared inventory - it just serves what's available.
@ -63,7 +63,7 @@
paths: "{{ transmission_download_dir }}" paths: "{{ transmission_download_dir }}"
patterns: "*.zim" patterns: "*.zim"
file_type: file file_type: file
register: completed_zim_files register: kiwix_completed_zim_files
when: kiwix_use_transmission when: kiwix_use_transmission
# Check which ZIM files already have symlinks in kiwix directory # Check which ZIM files already have symlinks in kiwix directory
@ -71,10 +71,10 @@
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ kiwix_zim_dir }}/{{ item.path | basename }}" path: "{{ kiwix_zim_dir }}/{{ item.path | basename }}"
get_checksum: false get_checksum: false
loop: "{{ completed_zim_files.files | default([]) }}" loop: "{{ kiwix_completed_zim_files.files | default([]) }}"
loop_control: loop_control:
label: "{{ item.path | basename }}" label: "{{ item.path | basename }}"
register: existing_symlinks register: kiwix_existing_symlinks
when: kiwix_use_transmission when: kiwix_use_transmission
# Create symlinks for any completed ZIM files not yet linked # Create symlinks for any completed ZIM files not yet linked
@ -83,14 +83,14 @@
src: "{{ item.item.path }}" src: "{{ item.item.path }}"
dest: "{{ kiwix_zim_dir }}/{{ item.item.path | basename }}" dest: "{{ kiwix_zim_dir }}/{{ item.item.path | basename }}"
state: link state: link
loop: "{{ existing_symlinks.results | default([]) }}" loop: "{{ kiwix_existing_symlinks.results | default([]) }}"
loop_control: loop_control:
label: "{{ item.item.path | basename }}" label: "{{ item.item.path | basename }}"
when: when:
- kiwix_use_transmission - kiwix_use_transmission
- item.stat is defined - item.stat is defined
- not item.stat.exists - not item.stat.exists
notify: restart kiwix-serve notify: Restart kiwix-serve
# --- Fallback: Direct HTTP download (original behavior) --- # --- Fallback: Direct HTTP download (original behavior) ---
- name: Check which ZIM archives exist (direct download mode) - name: Check which ZIM archives exist (direct download mode)
@ -100,7 +100,7 @@
loop: "{{ kiwix_zim_archives }}" loop: "{{ kiwix_zim_archives }}"
loop_control: loop_control:
label: "{{ item.filename }}" label: "{{ item.filename }}"
register: zim_stat register: kiwix_zim_stat
when: not kiwix_use_transmission when: not kiwix_use_transmission
- name: Download missing ZIM archives (direct download mode) - name: Download missing ZIM archives (direct download mode)
@ -109,14 +109,14 @@
dest: "{{ kiwix_zim_dir }}/{{ item.item.filename }}" dest: "{{ kiwix_zim_dir }}/{{ item.item.filename }}"
mode: '0644' mode: '0644'
timeout: 3600 timeout: 3600
loop: "{{ zim_stat.results | default([]) }}" loop: "{{ kiwix_zim_stat.results | default([]) }}"
loop_control: loop_control:
label: "{{ item.item.filename | default('unknown') }}" label: "{{ item.item.filename | default('unknown') }}"
when: when:
- not kiwix_use_transmission - not kiwix_use_transmission
- item.stat is defined - item.stat is defined
- not item.stat.exists - not item.stat.exists
notify: restart kiwix-serve notify: Restart kiwix-serve
# --- Determine which archives are available --- # --- Determine which archives are available ---
- name: Find available ZIM archives in kiwix directory - name: Find available ZIM archives in kiwix directory
@ -124,11 +124,11 @@
paths: "{{ kiwix_zim_dir }}" paths: "{{ kiwix_zim_dir }}"
patterns: "*.zim" patterns: "*.zim"
file_type: any # includes symlinks file_type: any # includes symlinks
register: available_zim_files register: kiwix_available_zim_files
- name: Build list of available archive filenames - name: Build list of available archive filenames
ansible.builtin.set_fact: ansible.builtin.set_fact:
kiwix_available_archives: "{{ available_zim_files.files | map(attribute='path') | map('basename') | list }}" kiwix_available_archives: "{{ kiwix_available_zim_files.files | map(attribute='path') | map('basename') | list }}"
# --- LaunchAgent deployment --- # --- LaunchAgent deployment ---
- name: Deploy kiwix-serve LaunchAgent plist - name: Deploy kiwix-serve LaunchAgent plist
@ -136,15 +136,16 @@
src: kiwix-serve.plist.j2 src: kiwix-serve.plist.j2
dest: ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist dest: ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist
mode: '0644' mode: '0644'
notify: restart kiwix-serve notify: Restart kiwix-serve
- name: Check if kiwix-serve LaunchAgent is loaded - name: Check if kiwix-serve LaunchAgent is loaded
ansible.builtin.command: launchctl list mcquack.eblume.kiwix-serve ansible.builtin.command: launchctl list mcquack.eblume.kiwix-serve
register: launchctl_check register: kiwix_launchctl_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Load kiwix-serve LaunchAgent if not loaded - name: Load kiwix-serve LaunchAgent if not loaded
ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist
when: launchctl_check.rc != 0 when: kiwix_launchctl_check.rc != 0
changed_when: true
failed_when: false failed_when: false

View file

@ -1,5 +1,6 @@
--- ---
- name: restart loki - name: Restart loki
ansible.builtin.command: brew services restart loki ansible.builtin.command: brew services restart loki
async: 120 async: 120
poll: 0 poll: 0
changed_when: true

View file

@ -29,10 +29,10 @@
src: loki-config.yaml.j2 src: loki-config.yaml.j2
dest: "{{ loki_config_file }}" dest: "{{ loki_config_file }}"
mode: '0644' mode: '0644'
notify: restart loki notify: Restart loki
- name: Ensure loki service is started - name: Ensure loki service is started
ansible.builtin.command: brew services start loki ansible.builtin.command: brew services start loki
register: brew_start register: loki_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in loki_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -1,5 +1,6 @@
--- ---
- name: restart miniflux - name: Restart miniflux
ansible.builtin.command: brew services restart miniflux ansible.builtin.command: brew services restart miniflux
async: 120 async: 120
poll: 0 poll: 0
changed_when: true

View file

@ -54,11 +54,11 @@
src: miniflux.conf.j2 src: miniflux.conf.j2
dest: "{{ miniflux_config_file }}" dest: "{{ miniflux_config_file }}"
mode: '0600' mode: '0600'
notify: restart miniflux notify: Restart miniflux
no_log: true no_log: true
- name: Ensure miniflux service is started - name: Ensure miniflux service is started
ansible.builtin.command: brew services start miniflux ansible.builtin.command: brew services start miniflux
register: brew_start register: miniflux_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in miniflux_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -1,4 +1,5 @@
--- ---
- name: restart node_exporter - name: Restart node_exporter
ansible.builtin.command: brew services restart node_exporter ansible.builtin.command: brew services restart node_exporter
listen: restart node_exporter listen: Restart node_exporter
changed_when: true

View file

@ -13,10 +13,10 @@
src: node_exporter.args.j2 src: node_exporter.args.j2
dest: /opt/homebrew/etc/node_exporter.args dest: /opt/homebrew/etc/node_exporter.args
mode: '0644' mode: '0644'
notify: restart node_exporter notify: Restart node_exporter
- name: Ensure node_exporter service is started - name: Ensure node_exporter service is started
ansible.builtin.command: brew services start node_exporter ansible.builtin.command: brew services start node_exporter
register: brew_start register: node_exporter_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in node_exporter_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -2,10 +2,10 @@
# Plex metrics collection configuration # Plex metrics collection configuration
# Plex server URL # Plex server URL
plex_url: "http://localhost:32400" plex_metrics_url: "http://localhost:32400"
# Path to file containing Plex token (should have 600 permissions) # Path to file containing Plex token (should have 600 permissions)
plex_token_file: "/Users/erichblume/.plex-token" plex_metrics_token_file: "/Users/erichblume/.plex-token"
# Metrics collection interval in seconds # Metrics collection interval in seconds
plex_metrics_interval: 60 plex_metrics_interval: 60

View file

@ -1,5 +1,6 @@
--- ---
- name: reload plex-metrics - name: Reload plex-metrics
ansible.builtin.shell: | ansible.builtin.shell: |
launchctl unload ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist 2>/dev/null || true launchctl unload ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist launchctl load ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist
changed_when: true

View file

@ -10,22 +10,23 @@
src: plex-metrics.sh.j2 src: plex-metrics.sh.j2
dest: "{{ plex_metrics_script }}" dest: "{{ plex_metrics_script }}"
mode: '0755' mode: '0755'
notify: reload plex-metrics notify: Reload plex-metrics
- name: Deploy plex-metrics LaunchAgent plist - name: Deploy plex-metrics LaunchAgent plist
ansible.builtin.template: ansible.builtin.template:
src: plex-metrics.plist.j2 src: plex-metrics.plist.j2
dest: ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist dest: ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist
mode: '0644' mode: '0644'
notify: reload plex-metrics notify: Reload plex-metrics
- name: Check if plex-metrics LaunchAgent is loaded - name: Check if plex-metrics LaunchAgent is loaded
ansible.builtin.command: launchctl list mcquack.eblume.plex-metrics ansible.builtin.command: launchctl list mcquack.eblume.plex-metrics
register: launchctl_check register: plex_metrics_launchctl_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Load plex-metrics LaunchAgent if not loaded - name: Load plex-metrics LaunchAgent if not loaded
ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.plex-metrics.plist
when: launchctl_check.rc != 0 when: plex_metrics_launchctl_check.rc != 0
changed_when: true
failed_when: false failed_when: false

View file

@ -4,8 +4,8 @@
set -euo pipefail set -euo pipefail
PLEX_URL="{{ plex_url }}" PLEX_URL="{{ plex_metrics_url }}"
TOKEN_FILE="{{ plex_token_file }}" TOKEN_FILE="{{ plex_metrics_token_file }}"
OUTPUT_FILE="{{ plex_metrics_dir }}/plex.prom" OUTPUT_FILE="{{ plex_metrics_dir }}/plex.prom"
TEMP_FILE="${OUTPUT_FILE}.tmp" TEMP_FILE="${OUTPUT_FILE}.tmp"

View file

@ -1,5 +1,6 @@
--- ---
- name: restart postgresql - name: Restart postgresql
ansible.builtin.command: brew services restart {{ postgresql_formula }} ansible.builtin.command: brew services restart {{ postgresql_formula }}
async: 120 async: 120
poll: 0 poll: 0
changed_when: true

View file

@ -4,7 +4,7 @@
# Passwords are fetched from 1Password at runtime using the `op` CLI. # Passwords are fetched from 1Password at runtime using the `op` CLI.
# Requires: `op` authenticated on the control machine (run `op signin` first). # Requires: `op` authenticated on the control machine (run `op signin` first).
- name: Install {{ postgresql_formula }} via homebrew - name: Install postgresql via homebrew
community.general.homebrew: community.general.homebrew:
name: "{{ postgresql_formula }}" name: "{{ postgresql_formula }}"
state: present state: present
@ -17,49 +17,49 @@
ansible.builtin.command: ansible.builtin.command:
cmd: op --vault {{ postgresql_op_vault }} item get {{ postgresql_op_superuser_item }} --fields password --reveal cmd: op --vault {{ postgresql_op_vault }} item get {{ postgresql_op_superuser_item }} --fields password --reveal
delegate_to: localhost delegate_to: localhost
register: pg_superuser_password_result register: postgresql_superuser_password_result
changed_when: false changed_when: false
no_log: true no_log: true
check_mode: false check_mode: false
when: pg_superuser_password is not defined when: postgresql_superuser_password is not defined
- name: Set superuser password fact - name: Set superuser password fact
ansible.builtin.set_fact: ansible.builtin.set_fact:
pg_superuser_password: "{{ pg_superuser_password_result.stdout }}" postgresql_superuser_password: "{{ postgresql_superuser_password_result.stdout }}"
no_log: true no_log: true
when: pg_superuser_password is not defined when: postgresql_superuser_password is not defined
- name: Fetch user passwords from 1Password - name: Fetch user passwords from 1Password
ansible.builtin.command: ansible.builtin.command:
cmd: op --vault {{ postgresql_op_vault }} item get {{ item.op_item }} --fields {{ item.op_field }} --reveal cmd: op --vault {{ postgresql_op_vault }} item get {{ item.op_item }} --fields {{ item.op_field }} --reveal
delegate_to: localhost delegate_to: localhost
loop: "{{ postgresql_users }}" loop: "{{ postgresql_users }}"
register: pg_user_passwords_result register: postgresql_user_passwords_result
changed_when: false changed_when: false
no_log: true no_log: true
check_mode: false check_mode: false
when: pg_user_passwords is not defined when: postgresql_user_passwords is not defined
- name: Build user password lookup - name: Build user password lookup
ansible.builtin.set_fact: ansible.builtin.set_fact:
pg_user_passwords: "{{ pg_user_passwords | default({}) | combine({item.item.name: item.stdout}) }}" postgresql_user_passwords: "{{ postgresql_user_passwords | default({}) | combine({item.item.name: item.stdout}) }}"
loop: "{{ pg_user_passwords_result.results }}" loop: "{{ postgresql_user_passwords_result.results }}"
no_log: true no_log: true
when: pg_user_passwords is not defined when: postgresql_user_passwords is not defined
# === Initialize PostgreSQL cluster === # === Initialize PostgreSQL cluster ===
- name: Check if postgresql data directory is initialized - name: Check if postgresql data directory is initialized
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ postgresql_data_dir }}/PG_VERSION" path: "{{ postgresql_data_dir }}/PG_VERSION"
register: pg_data register: postgresql_data_check
- name: Create temporary password file for initdb - name: Create temporary password file for initdb
ansible.builtin.copy: ansible.builtin.copy:
content: "{{ pg_superuser_password }}" content: "{{ postgresql_superuser_password }}"
dest: /tmp/.pg_init_pwfile dest: /tmp/.pg_init_pwfile
mode: '0600' mode: '0600'
when: not pg_data.stat.exists when: not postgresql_data_check.stat.exists
no_log: true no_log: true
- name: Initialize postgresql database cluster with superuser password - name: Initialize postgresql database cluster with superuser password
@ -69,13 +69,14 @@
--locale=en_US.UTF-8 -E UTF-8 --locale=en_US.UTF-8 -E UTF-8
--pwfile=/tmp/.pg_init_pwfile --pwfile=/tmp/.pg_init_pwfile
{{ postgresql_data_dir }} {{ postgresql_data_dir }}
when: not pg_data.stat.exists when: not postgresql_data_check.stat.exists
changed_when: true
- name: Remove temporary password file - name: Remove temporary password file
ansible.builtin.file: ansible.builtin.file:
path: /tmp/.pg_init_pwfile path: /tmp/.pg_init_pwfile
state: absent state: absent
when: not pg_data.stat.exists when: not postgresql_data_check.stat.exists
# === Configure and start PostgreSQL === # === Configure and start PostgreSQL ===
@ -84,19 +85,19 @@
src: pg_hba.conf.j2 src: pg_hba.conf.j2
dest: "{{ postgresql_config_dir }}/pg_hba.conf" dest: "{{ postgresql_config_dir }}/pg_hba.conf"
mode: '0600' mode: '0600'
notify: restart postgresql notify: Restart postgresql
- name: Ensure postgresql service is started - name: Ensure postgresql service is started
ansible.builtin.command: brew services start {{ postgresql_formula }} ansible.builtin.command: brew services start {{ postgresql_formula }}
register: brew_start register: postgresql_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in postgresql_brew_start.stdout"
failed_when: false failed_when: false
- name: Wait for postgresql to accept connections - name: Wait for postgresql to accept connections
ansible.builtin.command: > ansible.builtin.command: >
{{ postgresql_bin_dir }}/pg_isready -h localhost -p {{ postgresql_port }} {{ postgresql_bin_dir }}/pg_isready -h localhost -p {{ postgresql_port }}
register: pg_ready register: postgresql_ready
until: pg_ready.rc == 0 until: postgresql_ready.rc == 0
retries: 10 retries: 10
delay: 2 delay: 2
changed_when: false changed_when: false
@ -108,9 +109,9 @@
{{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -tAc {{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -tAc
"SELECT 1 FROM pg_roles WHERE rolname = '{{ item.name }}';" "SELECT 1 FROM pg_roles WHERE rolname = '{{ item.name }}';"
environment: environment:
PGPASSWORD: "{{ pg_superuser_password }}" PGPASSWORD: "{{ postgresql_superuser_password }}"
loop: "{{ postgresql_users }}" loop: "{{ postgresql_users }}"
register: user_check register: postgresql_user_check
changed_when: false changed_when: false
failed_when: false failed_when: false
no_log: true no_log: true
@ -118,10 +119,10 @@
- name: Create postgresql users with passwords - name: Create postgresql users with passwords
ansible.builtin.command: > ansible.builtin.command: >
{{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -c {{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -c
"CREATE USER {{ item.item.name }} WITH PASSWORD '{{ pg_user_passwords[item.item.name] }}';" "CREATE USER {{ item.item.name }} WITH PASSWORD '{{ postgresql_user_passwords[item.item.name] }}';"
environment: environment:
PGPASSWORD: "{{ pg_superuser_password }}" PGPASSWORD: "{{ postgresql_superuser_password }}"
loop: "{{ user_check.results }}" loop: "{{ postgresql_user_check.results }}"
when: item.stdout != "1" when: item.stdout != "1"
changed_when: true changed_when: true
no_log: true no_log: true
@ -129,9 +130,9 @@
- name: Update postgresql user passwords (idempotent) - name: Update postgresql user passwords (idempotent)
ansible.builtin.command: > ansible.builtin.command: >
{{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -c {{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -c
"ALTER USER {{ item.name }} WITH PASSWORD '{{ pg_user_passwords[item.name] }}';" "ALTER USER {{ item.name }} WITH PASSWORD '{{ postgresql_user_passwords[item.name] }}';"
environment: environment:
PGPASSWORD: "{{ pg_superuser_password }}" PGPASSWORD: "{{ postgresql_superuser_password }}"
loop: "{{ postgresql_users }}" loop: "{{ postgresql_users }}"
changed_when: false changed_when: false
no_log: true no_log: true
@ -140,9 +141,10 @@
- name: Grant roles to users - name: Grant roles to users
ansible.builtin.command: > ansible.builtin.command: >
{{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -c "GRANT {{ item.1 }} TO {{ item.0.name }};" {{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }}
-d postgres -c "GRANT {{ item.1 }} TO {{ item.0.name }};"
environment: environment:
PGPASSWORD: "{{ pg_superuser_password }}" PGPASSWORD: "{{ postgresql_superuser_password }}"
loop: "{{ postgresql_users | subelements('roles', skip_missing=True) }}" loop: "{{ postgresql_users | subelements('roles', skip_missing=True) }}"
changed_when: false changed_when: false
no_log: true no_log: true
@ -154,9 +156,9 @@
{{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -tAc {{ postgresql_bin_dir }}/psql -h localhost -U {{ postgresql_superuser }} -d postgres -tAc
"SELECT 1 FROM pg_database WHERE datname = '{{ item.name }}';" "SELECT 1 FROM pg_database WHERE datname = '{{ item.name }}';"
environment: environment:
PGPASSWORD: "{{ pg_superuser_password }}" PGPASSWORD: "{{ postgresql_superuser_password }}"
loop: "{{ postgresql_databases }}" loop: "{{ postgresql_databases }}"
register: db_check register: postgresql_db_check
changed_when: false changed_when: false
failed_when: false failed_when: false
no_log: true no_log: true
@ -167,8 +169,8 @@
--owner={{ item.item.owner }} --owner={{ item.item.owner }}
{{ item.item.name }} {{ item.item.name }}
environment: environment:
PGPASSWORD: "{{ pg_superuser_password }}" PGPASSWORD: "{{ postgresql_superuser_password }}"
loop: "{{ db_check.results }}" loop: "{{ postgresql_db_check.results }}"
when: item.stdout != "1" when: item.stdout != "1"
changed_when: true changed_when: true
no_log: true no_log: true
@ -181,7 +183,7 @@
ansible.builtin.copy: ansible.builtin.copy:
content: | content: |
# Managed by ansible - only read-only roles # Managed by ansible - only read-only roles
localhost:{{ postgresql_port }}:*:borgmatic:{{ pg_user_passwords['borgmatic'] }} localhost:{{ postgresql_port }}:*:borgmatic:{{ postgresql_user_passwords['borgmatic'] }}
dest: ~/.pgpass dest: ~/.pgpass
mode: '0600' mode: '0600'
no_log: true no_log: true

View file

@ -1,3 +1,4 @@
--- ---
- name: restart prometheus - name: Restart prometheus
ansible.builtin.command: brew services restart prometheus ansible.builtin.command: brew services restart prometheus
changed_when: true

View file

@ -9,17 +9,17 @@
src: prometheus.yml.j2 src: prometheus.yml.j2
dest: /opt/homebrew/etc/prometheus.yml dest: /opt/homebrew/etc/prometheus.yml
mode: '0644' mode: '0644'
notify: restart prometheus notify: Restart prometheus
- name: Configure prometheus.args - name: Configure prometheus.args
ansible.builtin.template: ansible.builtin.template:
src: prometheus.args.j2 src: prometheus.args.j2
dest: /opt/homebrew/etc/prometheus.args dest: /opt/homebrew/etc/prometheus.args
mode: '0644' mode: '0644'
notify: restart prometheus notify: Restart prometheus
- name: Ensure prometheus service is started - name: Ensure prometheus service is started
ansible.builtin.command: brew services start prometheus ansible.builtin.command: brew services start prometheus
register: brew_start register: prometheus_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in prometheus_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -2,7 +2,7 @@
# Tailscale serve configuration for this host # Tailscale serve configuration for this host
# Each service maps a Tailscale service name to local endpoints # Each service maps a Tailscale service name to local endpoints
tailscale_services: tailscale_serve_services:
- name: svc:grafana - name: svc:grafana
https: https:
port: 443 port: 443

View file

@ -1,23 +1,24 @@
--- ---
- name: Get current tailscale serve status - name: Get current tailscale serve status
ansible.builtin.command: tailscale serve status --json ansible.builtin.command: tailscale serve status --json
register: serve_status register: tailscale_serve_status
changed_when: false changed_when: false
- name: Parse serve status - name: Parse serve status
ansible.builtin.set_fact: ansible.builtin.set_fact:
serve_config: "{{ ((serve_status.stdout | default('{}', true)) | from_json).Services | default({}) }}" tailscale_serve_config: "{{ ((tailscale_serve_status.stdout | default('{}', true)) | from_json).Services | default({}) }}"
# Configure HTTPS if service doesn't have Web config yet # Configure HTTPS if service doesn't have Web config yet
- name: Configure HTTPS services - name: Configure HTTPS services
ansible.builtin.command: > ansible.builtin.command: >
tailscale serve --service="{{ item.name }}" tailscale serve --service="{{ item.name }}"
--https={{ item.https.port }} {{ item.https.upstream }} --https={{ item.https.port }} {{ item.https.upstream }}
loop: "{{ tailscale_services }}" loop: "{{ tailscale_serve_services }}"
when: when:
- item.https is defined - item.https is defined
- serve_config[item.name] is not defined or serve_config[item.name].Web is not defined - tailscale_serve_config[item.name] is not defined or tailscale_serve_config[item.name].Web is not defined
register: https_result register: tailscale_serve_https_result
changed_when: true
failed_when: false failed_when: false
# Configure TCP if service doesn't have the specific port configured yet # Configure TCP if service doesn't have the specific port configured yet
@ -25,12 +26,13 @@
ansible.builtin.command: > ansible.builtin.command: >
tailscale serve --service="{{ item.name }}" tailscale serve --service="{{ item.name }}"
--tcp={{ item.tcp.port }} {{ item.tcp.upstream }} --tcp={{ item.tcp.port }} {{ item.tcp.upstream }}
loop: "{{ tailscale_services }}" loop: "{{ tailscale_serve_services }}"
when: when:
- item.tcp is defined - item.tcp is defined
- serve_config[item.name] is not defined or - tailscale_serve_config[item.name] is not defined or
serve_config[item.name].TCP is not defined or tailscale_serve_config[item.name].TCP is not defined or
serve_config[item.name].TCP[item.tcp.port | string] is not defined or tailscale_serve_config[item.name].TCP[item.tcp.port | string] is not defined or
serve_config[item.name].TCP[item.tcp.port | string].TCPForward is not defined tailscale_serve_config[item.name].TCP[item.tcp.port | string].TCPForward is not defined
register: tcp_result register: tailscale_serve_tcp_result
changed_when: true
failed_when: false failed_when: false

View file

@ -1,3 +1,4 @@
--- ---
- name: restart transmission - name: Restart transmission
ansible.builtin.command: brew services restart transmission-cli ansible.builtin.command: brew services restart transmission-cli
changed_when: true

View file

@ -29,12 +29,12 @@
dest: "{{ transmission_config_dir }}/settings.json" dest: "{{ transmission_config_dir }}/settings.json"
mode: '0600' mode: '0600'
check_mode: true check_mode: true
register: settings_check register: transmission_settings_check
- name: Stop transmission before config changes - name: Stop transmission before config changes
ansible.builtin.command: brew services stop transmission-cli ansible.builtin.command: brew services stop transmission-cli
when: settings_check.changed when: transmission_settings_check.changed
register: brew_stop register: transmission_brew_stop
changed_when: false changed_when: false
failed_when: false failed_when: false
@ -43,10 +43,10 @@
src: settings.json.j2 src: settings.json.j2
dest: "{{ transmission_config_dir }}/settings.json" dest: "{{ transmission_config_dir }}/settings.json"
mode: '0600' mode: '0600'
notify: restart transmission notify: Restart transmission
- name: Ensure transmission service is started - name: Ensure transmission service is started
ansible.builtin.command: brew services start transmission-cli ansible.builtin.command: brew services start transmission-cli
register: brew_start register: transmission_brew_start
changed_when: "'Successfully started' in brew_start.stdout" changed_when: "'Successfully started' in transmission_brew_start.stdout"
failed_when: false failed_when: false

View file

@ -1,7 +1,7 @@
--- ---
transmission_rpc_host: 127.0.0.1 transmission_metrics_rpc_host: 127.0.0.1
transmission_rpc_port: 9091 transmission_metrics_rpc_port: 9091
transmission_metrics_dir: /opt/homebrew/var/node_exporter/textfile transmission_metrics_dir: /opt/homebrew/var/node_exporter/textfile
transmission_metrics_script: /Users/erichblume/bin/transmission-metrics transmission_metrics_script: /Users/erichblume/bin/transmission-metrics
transmission_metrics_interval: 60 # seconds between metric collection transmission_metrics_interval: 60 # seconds between metric collection
transmission_log_dir: /opt/homebrew/var/log transmission_metrics_log_dir: /opt/homebrew/var/log

View file

@ -1,5 +1,6 @@
--- ---
- name: reload transmission-metrics - name: Reload transmission-metrics
ansible.builtin.shell: | ansible.builtin.shell: |
launchctl unload ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist 2>/dev/null || true launchctl unload ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist
changed_when: true

View file

@ -4,22 +4,23 @@
src: transmission-metrics.sh.j2 src: transmission-metrics.sh.j2
dest: "{{ transmission_metrics_script }}" dest: "{{ transmission_metrics_script }}"
mode: '0755' mode: '0755'
notify: reload transmission-metrics notify: Reload transmission-metrics
- name: Deploy transmission-metrics LaunchAgent plist - name: Deploy transmission-metrics LaunchAgent plist
ansible.builtin.template: ansible.builtin.template:
src: transmission-metrics.plist.j2 src: transmission-metrics.plist.j2
dest: ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist dest: ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist
mode: '0644' mode: '0644'
notify: reload transmission-metrics notify: Reload transmission-metrics
- name: Check if transmission-metrics LaunchAgent is loaded - name: Check if transmission-metrics LaunchAgent is loaded
ansible.builtin.command: launchctl list mcquack.eblume.transmission-metrics ansible.builtin.command: launchctl list mcquack.eblume.transmission-metrics
register: launchctl_check register: transmission_metrics_launchctl_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Load transmission-metrics LaunchAgent if not loaded - name: Load transmission-metrics LaunchAgent if not loaded
ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist
when: launchctl_check.rc != 0 when: transmission_metrics_launchctl_check.rc != 0
changed_when: true
failed_when: false failed_when: false

View file

@ -19,8 +19,8 @@
<key>RunAtLoad</key> <key>RunAtLoad</key>
<true/> <true/>
<key>StandardErrorPath</key> <key>StandardErrorPath</key>
<string>{{ transmission_log_dir }}/transmission-metrics.err.log</string> <string>{{ transmission_metrics_log_dir }}/transmission-metrics.err.log</string>
<key>StandardOutPath</key> <key>StandardOutPath</key>
<string>{{ transmission_log_dir }}/transmission-metrics.out.log</string> <string>{{ transmission_metrics_log_dir }}/transmission-metrics.out.log</string>
</dict> </dict>
</plist> </plist>

View file

@ -4,7 +4,7 @@
set -euo pipefail set -euo pipefail
RPC_URL="http://{{ transmission_rpc_host }}:{{ transmission_rpc_port }}/transmission/rpc" RPC_URL="http://{{ transmission_metrics_rpc_host }}:{{ transmission_metrics_rpc_port }}/transmission/rpc"
OUTPUT_FILE="{{ transmission_metrics_dir }}/transmission.prom" OUTPUT_FILE="{{ transmission_metrics_dir }}/transmission.prom"
TEMP_FILE="${OUTPUT_FILE}.tmp" TEMP_FILE="${OUTPUT_FILE}.tmp"

View file

@ -6,7 +6,6 @@ set -euo pipefail
# Colors for output # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
FAILED=0 FAILED=0

View file

@ -3,8 +3,10 @@
set -euo pipefail set -euo pipefail
export TAILSCALE_OAUTH_CLIENT_ID=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_id) TAILSCALE_OAUTH_CLIENT_ID=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_id)
export TAILSCALE_OAUTH_CLIENT_SECRET=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_secret --reveal) export TAILSCALE_OAUTH_CLIENT_ID
TAILSCALE_OAUTH_CLIENT_SECRET=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_secret --reveal)
export TAILSCALE_OAUTH_CLIENT_SECRET
export TAILSCALE_TAILNET="tail8d86e.ts.net" export TAILSCALE_TAILNET="tail8d86e.ts.net"
cd "$(dirname "$0")/../pulumi" cd "$(dirname "$0")/../pulumi"

View file

@ -3,8 +3,10 @@
set -euo pipefail set -euo pipefail
export TAILSCALE_OAUTH_CLIENT_ID=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_id) TAILSCALE_OAUTH_CLIENT_ID=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_id)
export TAILSCALE_OAUTH_CLIENT_SECRET=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_secret --reveal) export TAILSCALE_OAUTH_CLIENT_ID
TAILSCALE_OAUTH_CLIENT_SECRET=$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get wi6bkf7bcccwfy4eu776ab4p4u --fields client_secret --reveal)
export TAILSCALE_OAUTH_CLIENT_SECRET
export TAILSCALE_TAILNET="tail8d86e.ts.net" export TAILSCALE_TAILNET="tail8d86e.ts.net"
cd "$(dirname "$0")/../pulumi" cd "$(dirname "$0")/../pulumi"

View file

@ -1,2 +1,3 @@
---
config: config:
tailscale:tailnet: tail8d86e.ts.net tailscale:tailnet: tail8d86e.ts.net

View file

@ -1,3 +1,4 @@
---
name: blumeops-tailnet name: blumeops-tailnet
runtime: runtime:
name: python name: python

View file

@ -2,7 +2,4 @@
name = "blumeops-tailnet" name = "blumeops-tailnet"
version = "0.1.0" version = "0.1.0"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = ["pulumi>=3.0.0", "pulumi-tailscale>=0.24.0"]
"pulumi>=3.0.0",
"pulumi-tailscale>=0.24.0",
]