mirror of
https://github.com/natelandau/ansible-homelab-config.git
synced 2025-11-18 01:43:40 -05:00
Initial commit
This commit is contained in:
22
templates/Tdarr_Node_Config.json.j2
Normal file
22
templates/Tdarr_Node_Config.json.j2
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"nodeID": "{{ inventory_hostname }}",
|
||||
"nodeIP": "{{ ansible_host }}",
|
||||
"nodePort": "{{ tdarr_node_port }}",
|
||||
"serverIP": "{% for h in groups['lan'] if hostvars[h].is_tdarr_server == true %}{{ hostvars[h].ansible_host }}{% endfor %}",
|
||||
"serverPort": "{{ tdarr_server_port }}",
|
||||
{% if ansible_os_family == 'Darwin' and ansible_architecture == 'arm64' -%}
|
||||
"handbrakePath": "/opt/homebrew/bin/HandBrakeCLI",
|
||||
"ffmpegPath": "/opt/homebrew/bin/ffmpeg",
|
||||
{% else %}
|
||||
"handbrakePath": "/usr/local/bin/HandBrakeCLI",
|
||||
"ffmpegPath": "/usr/local/bin/ffmpeg",
|
||||
{%- endif %}
|
||||
|
||||
"mkvpropeditPath": "",
|
||||
"pathTranslators": [
|
||||
{
|
||||
"server": "",
|
||||
"node": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
13
templates/Tdarr_Server_Config.json.j2
Normal file
13
templates/Tdarr_Server_Config.json.j2
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"serverPort": "{{ tdarr_server_port }}",
|
||||
"webUIPort": "{{ tdarr_webui_port }}",
|
||||
"serverIP": "{% for h in groups['lan'] if hostvars[h].is_tdarr_server == true %}{{ hostvars[h].ansible_host }}{% endfor %}",
|
||||
{% if ansible_os_family == 'Darwin' and ansible_architecture == 'arm64' -%}
|
||||
"handbrakePath": "/opt/homebrew/bin/HandBrakeCLI",
|
||||
"ffmpegPath": "/opt/homebrew/bin/ffmpeg",
|
||||
{% else %}
|
||||
"handbrakePath": "/usr/local/bin/HandBrakeCLI",
|
||||
"ffmpegPath": "/usr/local/bin/ffmpeg"
|
||||
{%- endif %}
|
||||
|
||||
}
|
||||
128
templates/consul.hcl.j2
Normal file
128
templates/consul.hcl.j2
Normal file
@@ -0,0 +1,128 @@
|
||||
# ----------------------------------------- General Info
|
||||
"datacenter" = "{{ datacenter_name }}" # NOTE: changing the datacenter requires generating new certificates
|
||||
"node_name" = "{{ inventory_hostname }}"
|
||||
"domain" = "consul"
|
||||
{% if is_consul_server %}
|
||||
"server" = true
|
||||
"ui_config" = {
|
||||
"enabled" = true
|
||||
}
|
||||
{% else %}
|
||||
"ui_config" = {
|
||||
"enabled" = false
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
# ----------------------------------------- Files and Logs
|
||||
{% if 'synology' in inventory_hostname %}
|
||||
"data_dir" = "/consul/data"
|
||||
"log_file" = "/consul/data/logs/consul.log"
|
||||
{% else %}
|
||||
"data_dir" = "{{ consul_opt_dir }}"
|
||||
"log_file" = "{{ consul_opt_dir }}/logs/consul.log"
|
||||
{% endif %}
|
||||
"log_level" = "warn"
|
||||
|
||||
"log_rotate_max_files" = 5
|
||||
"enable_syslog" = false
|
||||
|
||||
# ----------------------------------------- Networking
|
||||
"addresses" = {
|
||||
"dns" = "0.0.0.0"
|
||||
"grpc" = "0.0.0.0"
|
||||
"http" = "0.0.0.0"
|
||||
"https" = "0.0.0.0"
|
||||
}
|
||||
"ports" = {
|
||||
"dns" = 8600
|
||||
"http" = 8500
|
||||
"server" = 8300
|
||||
}
|
||||
|
||||
{% if 'linode' in group_names %}
|
||||
"advertise_addr" = "{{ linode_private_ip }}"
|
||||
"bind_addr" = "{{ linode_private_ip }}"
|
||||
"client_addr" = "{{ linode_private_ip }} {{ '{{' }} GetInterfaceIP \"docker0\" {{ '}}' }}"
|
||||
{% elif 'synology' in inventory_hostname %}
|
||||
"advertise_addr" = "{{ synology_second_ip }}"
|
||||
"bind_addr" = "{{ synology_second_ip }}"
|
||||
"client_addr" = "{{ synology_second_ip }} {{ '{{' }} GetInterfaceIP \"docker0\" {{ '}}' }}"
|
||||
{% else %}
|
||||
"advertise_addr" = "{{ ansible_default_ipv4.address }}"
|
||||
"bind_addr" = "{{ ansible_default_ipv4.address }}"
|
||||
"client_addr" = "{{ ansible_default_ipv4.address }} {{ '{{' }} GetInterfaceIP \"docker0\" {{ '}}' }}"
|
||||
{% endif %}
|
||||
"retry_interval" = "30s"
|
||||
"retry_interval_wan" = "30s"
|
||||
{% if 'linode' in group_names %}
|
||||
"retry_join" = [{% for h in groups['linode-cluster'] if hostvars[h].is_consul_server == true %}"{{ hostvars[h].linode_private_ip }}"{% if not loop.last %}, {% endif %}{% endfor %}]
|
||||
{% else %}
|
||||
"retry_join" = [{% for h in groups['lan'] if hostvars[h].is_consul_server == true %}"{{ hostvars[h].ansible_host }}"{% if not loop.last %}, {% endif %}{% endfor %}]
|
||||
{% if is_consul_server %}
|
||||
{% if 'linode' in group_names %}
|
||||
"join_wan" = [{% for h in groups['linode-cluster'] if hostvars[h].is_consul_server == true %}"{{ hostvars[h].ansible_host }}"{% if not loop.last %}, {% endif %}{% endfor %}]
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# ----------------------------------------- Security
|
||||
"encrypt" = "{{ consul_encryprion_key }}"
|
||||
{% if is_consul_server %} {# Consul Servers #}
|
||||
"verify_incoming" = true
|
||||
"verify_outgoing" = true
|
||||
"verify_server_hostname" = true
|
||||
{% if 'synology' in inventory_hostname %} {# necessary, since running in docker container #}
|
||||
"ca_file" = "/consul/data/certs/consul-agent-ca.pem"
|
||||
"cert_file" = "/consul/data/certs/{{ datacenter_name }}-server-consul-0.pem"
|
||||
"key_file" = "/consul/data/certs/{{ datacenter_name }}-server-consul-0-key.pem"
|
||||
{% else %}
|
||||
"ca_file" = "{{ consul_opt_dir }}/certs/consul-agent-ca.pem"
|
||||
"cert_file" = "{{ consul_opt_dir }}/certs/{{ datacenter_name }}-server-consul-0.pem"
|
||||
"key_file" = "{{ consul_opt_dir }}/certs/{{ datacenter_name }}-server-consul-0-key.pem"
|
||||
{% endif %}
|
||||
"auto_encrypt" = {
|
||||
"allow_tls" = true
|
||||
}
|
||||
{% else %} {# Consul Clients #}
|
||||
"verify_incoming" = false
|
||||
"verify_outgoing" = true
|
||||
"verify_server_hostname" = true
|
||||
{% if 'synology' in inventory_hostname %} {# necessary, since running in docker container #}
|
||||
"ca_file" = "/consul/data/certs/consul-agent-ca.pem"
|
||||
{% else %}
|
||||
"ca_file" = "{{ consul_opt_dir }}/certs/consul-agent-ca.pem"
|
||||
{% endif %}
|
||||
"auto_encrypt" = {
|
||||
"tls" = true
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
"acl" = {
|
||||
enabled = false
|
||||
default_policy = "allow"
|
||||
enable_token_persistence = true
|
||||
}
|
||||
|
||||
# ----------------------------------------- Cluster Operations
|
||||
|
||||
{% if is_cluster_leader is defined %}
|
||||
{% if is_cluster_leader %}
|
||||
"bootstrap" = true
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
"disable_update_check" = false
|
||||
"enable_local_script_checks" = false
|
||||
"enable_script_checks" = false
|
||||
"skip_leave_on_interrupt" = true
|
||||
"leave_on_terminate" = false
|
||||
"primary_datacenter" = "{{ datacenter_name }}"
|
||||
"performance" = {
|
||||
"leave_drain_time" = "5s"
|
||||
"raft_multiplier" = 1
|
||||
"rpc_hold_timeout" = "7s"
|
||||
}
|
||||
{# telemetry = {
|
||||
"dogstatsd_addr" = "localhost:8125"
|
||||
"disable_hostname" = true
|
||||
"disable_compat_1.9" = true
|
||||
} #}
|
||||
32
templates/consul.launchd.j2
Normal file
32
templates/consul.launchd.j2
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/sbin</string>
|
||||
</dict>
|
||||
<key>KeepAlive</key>
|
||||
<dict>
|
||||
<key>PathState</key>
|
||||
<dict>
|
||||
<key>{{ mac_keep_alive_file }}</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>SuccessfulExit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Label</key>
|
||||
<string>com.{{ my_username }}.consul</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/consul</string>
|
||||
<string>agent</string>
|
||||
<string>-config-dir</string>
|
||||
<string>{{ interpolated_consul_configuration_dir }}</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
21
templates/consul.service.j2
Normal file
21
templates/consul.service.j2
Normal file
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description="HashiCorp Consul - A service mesh solution"
|
||||
Documentation=https://www.consul.io/
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
After=docker.service
|
||||
Requires=docker.service
|
||||
ConditionFileNotEmpty={{ interpolated_consul_configuration_dir }}/consul.hcl
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
User=consul
|
||||
Group=consul
|
||||
ExecStart=/usr/local/bin/consul agent -config-dir={{ interpolated_consul_configuration_dir }}
|
||||
ExecReload=/usr/local/bin/consul reload
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
67
templates/consul_services/consul_synology_checks.json.j2
Normal file
67
templates/consul_services/consul_synology_checks.json.j2
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"services": [{
|
||||
"name": "sabnzbd",
|
||||
"id": "sabnzbd",
|
||||
"tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.services.sabnzbd.loadbalancer.server.port=8080",
|
||||
"traefik.http.routers.sabnzbd.rule=Host(`sab.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.sabnzbd.entryPoints=web,websecure",
|
||||
"traefik.http.routers.sabnzbd.service=sabnzbd",
|
||||
"traefik.http.routers.sabnzbd.tls=true",
|
||||
"traefik.http.routers.sabnzbd.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.sabnzbd.middlewares=authelia@file"
|
||||
],
|
||||
"checks": [{
|
||||
"id": "sabnzbd-http-check",
|
||||
"http": "http://{{ synology_second_ip }}:8080",
|
||||
"interval": "30s",
|
||||
"timeout": "5s",
|
||||
"success_before_passing": 3,
|
||||
"failures_before_critical": 3
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "synology",
|
||||
"id": "synology",
|
||||
"tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.services.synology.loadbalancer.server.port=5000",
|
||||
"traefik.http.routers.synology.rule=Host(`nas.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.synology.entryPoints=web,websecure",
|
||||
"traefik.http.routers.synology.service=synology",
|
||||
"traefik.http.routers.synology.tls=true",
|
||||
"traefik.http.routers.synology.tls.certresolver=cloudflare"
|
||||
],
|
||||
"checks": [{
|
||||
"id": "synology-http-check",
|
||||
"http": "http://{{ synology_second_ip }}:5000",
|
||||
"interval": "30s",
|
||||
"timeout": "5s",
|
||||
"success_before_passing": 3,
|
||||
"failures_before_critical": 3
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "asntoip",
|
||||
"id": "asntoip",
|
||||
"tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.services.asntoip.loadbalancer.server.port=5151",
|
||||
"traefik.http.routers.asntoip.rule=Host(`asntoip.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.asntoip.entryPoints=web,websecure",
|
||||
"traefik.http.routers.asntoip.service=asntoip",
|
||||
"traefik.http.routers.asntoip.tls=true",
|
||||
"traefik.http.routers.asntoip.tls.certresolver=cloudflare"
|
||||
],
|
||||
"checks": [{
|
||||
"id": "asntoip-http-check",
|
||||
"http": "http://{{ synology_second_ip }}:5151",
|
||||
"interval": "30s",
|
||||
"timeout": "5s",
|
||||
"success_before_passing": 3,
|
||||
"failures_before_critical": 3
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
25
templates/consul_services/tdarr_service.json.j2
Normal file
25
templates/consul_services/tdarr_service.json.j2
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"services": [{
|
||||
"name": "tdarr",
|
||||
"id": "tdarr",
|
||||
"tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.services.tdarr.loadbalancer.server.port={{ tdarr_webui_port }}",
|
||||
"traefik.http.routers.tdarr.rule=Host(`tdarr.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.tdarr.entryPoints=web,websecure",
|
||||
"traefik.http.routers.tdarr.service=tdarr",
|
||||
"traefik.http.routers.tdarr.tls=true",
|
||||
"traefik.http.routers.tdarr.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.tdarr.middlewares=authelia@file"
|
||||
],
|
||||
"checks": [{
|
||||
"id": "tdarr-http-check",
|
||||
"http": "http://{{ ansible_host }}:{{ tdarr_webui_port }}",
|
||||
"interval": "30s",
|
||||
"timeout": "30s",
|
||||
"success_before_passing": 3,
|
||||
"failures_before_critical": 3
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
11
templates/docker_compose_files/synology_asn-to-ip.yml.j2
Normal file
11
templates/docker_compose_files/synology_asn-to-ip.yml.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
asn-to-ip:
|
||||
image: ddimick/asn-to-ip:latest
|
||||
hostname: asn-to-ip
|
||||
container_name: asn-to-ip
|
||||
network_mode: "bridge"
|
||||
ports:
|
||||
- 5151:5000
|
||||
restart: unless-stopped
|
||||
13
templates/docker_compose_files/synology_consul.yml.j2
Normal file
13
templates/docker_compose_files/synology_consul.yml.j2
Normal file
@@ -0,0 +1,13 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
consul:
|
||||
image: consul:latest
|
||||
hostname: consul
|
||||
container_name: consul
|
||||
network_mode: "host"
|
||||
volumes:
|
||||
- /volume1/docker/consul/data:/consul/data
|
||||
- /volume1/docker/consul/config:/consul/config
|
||||
command: consul agent -config-dir=/consul/config
|
||||
restart: unless-stopped
|
||||
18
templates/docker_compose_files/synology_diun.yml.j2
Normal file
18
templates/docker_compose_files/synology_diun.yml.j2
Normal file
@@ -0,0 +1,18 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
diun:
|
||||
image: ghcr.io/crazy-max/diun
|
||||
hostname: diun
|
||||
container_name: diun
|
||||
network_mode: "bridge"
|
||||
environment:
|
||||
- "TZ=America/New_York"
|
||||
- "DIUN_WATCH_SCHEDULE=26 */48 * * *"
|
||||
- "DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=true"
|
||||
- "DIUN_NOTIF_PUSHOVER_TOKEN={{ pushover_token }}"
|
||||
- "DIUN_NOTIF_PUSHOVER_RECIPIENT={{ pushover_recipient }}"
|
||||
- "DIUN_WATCH_FIRSTCHECKNOTIF=false"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
restart: unless-stopped
|
||||
17
templates/docker_compose_files/synology_plex.yml.j2
Normal file
17
templates/docker_compose_files/synology_plex.yml.j2
Normal file
@@ -0,0 +1,17 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
plex:
|
||||
image: ghcr.io/linuxserver/plex:latest
|
||||
hostname: plex
|
||||
container_name: plex
|
||||
network_mode: "host"
|
||||
environment:
|
||||
- "TZ=America/New_York"
|
||||
- "PGID=101"
|
||||
- "PUID={{ ansible_user_uid }}"
|
||||
- "VERSION=docker"
|
||||
volumes:
|
||||
- /volume1/media/media:/data/media
|
||||
- /volume1/docker/plex:/config
|
||||
restart: unless-stopped
|
||||
14
templates/docker_compose_files/synology_promtail.yml.j2
Normal file
14
templates/docker_compose_files/synology_promtail.yml.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
promtail:
|
||||
image: grafana/promtail
|
||||
hostname: promtail
|
||||
container_name: promtail
|
||||
ports:
|
||||
- 9080:9080
|
||||
network_mode: "bridge"
|
||||
volumes:
|
||||
- /volume1/docker/promtail/config.yml:/etc/promtail/config.yml
|
||||
- /var/log:/var/log:ro
|
||||
restart: unless-stopped
|
||||
23
templates/docker_compose_files/synology_sabnzbd.yml.j2
Normal file
23
templates/docker_compose_files/synology_sabnzbd.yml.j2
Normal file
@@ -0,0 +1,23 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
sabnzbd:
|
||||
image: ghcr.io/linuxserver/sabnzbd
|
||||
hostname: sabnzbd
|
||||
container_name: sabnzbd
|
||||
network_mode: "bridge"
|
||||
environment:
|
||||
- "TZ=America/New_York"
|
||||
- "PGID=101"
|
||||
- "PUID={{ ansible_user_uid }}"
|
||||
volumes:
|
||||
- /var/services/homes/{{ my_username }}:/{{ my_username }}
|
||||
- /volume1/nate:/nate
|
||||
- /volume1/media/downloads/nzb:/nzbd
|
||||
- /volume1/media/downloads/temp:/incomplete-downloads
|
||||
- /volume1/media/downloads/complete:/downloads
|
||||
- /volume1/docker/sabnzbd:/config
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 9090:9090
|
||||
restart: unless-stopped
|
||||
29
templates/docker_compose_files/synology_tdarr_node.yml.j2
Normal file
29
templates/docker_compose_files/synology_tdarr_node.yml.j2
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
tdarr_node:
|
||||
image: haveagitgat/tdarr_node:latest
|
||||
hostname: tdarr_node
|
||||
container_name: tdarr_node
|
||||
network_mode: "bridge"
|
||||
environment:
|
||||
- "nodeID={{ inventory_hostname }}"
|
||||
- "nodeIP={{ ansible_host }}"
|
||||
- "nodePort={{ tdarr_node_port }}"
|
||||
- "serverIP={% for h in groups['lan'] if hostvars[h].is_tdarr_server == true %}{{ hostvars[h].ansible_host }}{% endfor %}"
|
||||
- "serverPort={{ tdarr_server_port }}"
|
||||
- "TZ=America/New_York"
|
||||
- "PGID=101"
|
||||
- "PUID={{ ansible_user_uid }}"
|
||||
volumes:
|
||||
- /volume1/docker/tdarr_node:/app/configs
|
||||
- /volume1/media/media/movies:/movies
|
||||
- /volume1/media/tdarr_tmp:/tdarr_tmp
|
||||
- /volume1/media/tdarr_complete:/tdarr_complete
|
||||
ports:
|
||||
- {{ tdarr_node_port }}:{{ tdarr_node_port }}
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
privileged: true
|
||||
restart: unless-stopped
|
||||
14
templates/docker_compose_files/synology_telegraf.yml.j2
Normal file
14
templates/docker_compose_files/synology_telegraf.yml.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
telegraf:
|
||||
image: nuntz/telegraf-snmp:latest
|
||||
hostname: telegraf
|
||||
container_name: nuntz-telegraf-snmp
|
||||
network_mode: "host"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- /volume1/docker/telegraf/mibs:/usr/share/snmp/mibs
|
||||
- /volume1/docker/telegraf/logs:/var/logs/telegraf
|
||||
- /volume1/docker/telegraf/config:/etc/telegraf
|
||||
restart: unless-stopped
|
||||
217
templates/nomad.hcl.j2
Normal file
217
templates/nomad.hcl.j2
Normal file
@@ -0,0 +1,217 @@
|
||||
# ----------------------------------------- General Info
|
||||
name = "{{ inventory_hostname }}"
|
||||
region = "global"
|
||||
datacenter = "{{ datacenter_name }}"
|
||||
|
||||
# ----------------------------------------- Files and Logs
|
||||
data_dir = "{{ nomad_opt_dir_location }}"
|
||||
plugin_dir = "{{ nomad_opt_dir_location }}/plugins"
|
||||
log_level = "warn"
|
||||
log_file = "{{ nomad_opt_dir_location }}/logs/nomad.log"
|
||||
log_rotate_max_files = 5
|
||||
enable_syslog = false
|
||||
|
||||
# ----------------------------------------- Networking
|
||||
bind_addr = "0.0.0.0" # the default
|
||||
|
||||
advertise {
|
||||
{% if 'linode' in group_names %}
|
||||
http = "{{ linode_private_ip }}:4646"
|
||||
rpc = "{{ linode_private_ip }}:4647"
|
||||
serf = "{{ linode_private_ip }}:4648" # non-default ports may be specified
|
||||
{% elif 'synology' in group_names %}
|
||||
http = "{{ synology_second_ip }}:4646"
|
||||
rpc = "{{ synology_second_ip }}:4647"
|
||||
serf = "{{ synology_second_ip }}:4648" # non-default ports may be specified
|
||||
{% else %}
|
||||
http = "{{ ansible_host }}:4646"
|
||||
rpc = "{{ ansible_host }}:4647"
|
||||
serf = "{{ ansible_host }}:4648" # non-default ports may be specified
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------- Consul Integration
|
||||
consul {
|
||||
{% if 'linode' in group_names %}
|
||||
address = "{{ linode_private_ip }}:8500"
|
||||
{% elif 'synology' in group_names %}
|
||||
address = "{{ synology_second_ip }}:8500"
|
||||
{% else %}
|
||||
address = "{{ ansible_host }}:8500"
|
||||
{% endif %}
|
||||
server_service_name = "nomad-servers"
|
||||
client_service_name = "nomad-clients"
|
||||
auto_advertise = true
|
||||
server_auto_join = true
|
||||
client_auto_join = true
|
||||
|
||||
{% if is_nomad_server %}
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.nomad-server.entryPoints=web,websecure",
|
||||
"traefik.http.routers.nomad-server.service=nomad-server",
|
||||
"traefik.http.routers.nomad-server.rule=Host(`nomad.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.nomad-server.tls=true",
|
||||
"traefik.http.routers.nomad-server.middlewares=authelia@file,redirectScheme@file",
|
||||
"traefik.http.services.nomad-server.loadbalancer.server.port=4646"
|
||||
]
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
# ----------------------------------------- CLient Config
|
||||
client {
|
||||
enabled = true
|
||||
{% if 'pis' in group_names %}
|
||||
node_class = "rpi"
|
||||
{% elif 'macs' in group_names %}
|
||||
node_class = "mac"
|
||||
{% elif 'synology' in group_names %}
|
||||
node_class = "synology"
|
||||
{% endif %}
|
||||
reserved {
|
||||
cpu = 250
|
||||
memory = 100
|
||||
reserved_ports = "22"
|
||||
}
|
||||
{% if not is_nomad_server %}
|
||||
{% if 'linode' in group_names %}
|
||||
server_join {
|
||||
retry_join = [{% for h in groups['linode'] if hostvars[h].is_nomad_server == true %}"{{ hostvars[h].ansible_host }}"{% if not loop.last %}, {% endif %}{% endfor %}]
|
||||
retry_max = 3
|
||||
retry_interval = "15s"
|
||||
}
|
||||
{% else %}
|
||||
server_join {
|
||||
retry_join = [{% for h in groups['lan'] if hostvars[h].is_nomad_server == true %}"{{ hostvars[h].ansible_host }}"{% if not loop.last %}, {% endif %}{% endfor %}]
|
||||
retry_max = 3
|
||||
retry_interval = "15s"
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
meta {
|
||||
# These are variables that can be used in Nomad job files
|
||||
PUID = "{{ ansible_user_uid }}"
|
||||
PGID = "{{ ansible_user_gid }}"
|
||||
nfsStorageRoot = "{{ interpolated_nfs_service_storage }}"
|
||||
localStorageRoot = "{{ interpolated_localfs_service_storage }}"
|
||||
{% if 'macs' in group_names %}
|
||||
restoreCommand = "/usr/local/bin/service_restore"
|
||||
restoreCommand1 = "--verbose"
|
||||
restoreCommand2 = "--job"
|
||||
restoreCommand3 = ""
|
||||
backupCommand = "/usr/local/bin/service_backups"
|
||||
backupCommandArg1 = "--verbose"
|
||||
backupCommandArg2 = "--loglevel=INFO"
|
||||
backupCommandArg3 = ""
|
||||
backupAllocArg1 = "--verbose"
|
||||
backupAllocArg2 = "--loglevel=INFO"
|
||||
backupAllocArg3 = "--allocation"
|
||||
backupAllocArg4 = "--delete"
|
||||
backupAllocArg5 = "--job"
|
||||
backupAllocArg6 = ""
|
||||
{% else %}
|
||||
restoreCommand = "sudo"
|
||||
restoreCommand1 = "/usr/local/bin/service_restore"
|
||||
restoreCommand2 = "--job"
|
||||
restoreCommand3 = "--verbose"
|
||||
backupCommand = "sudo"
|
||||
backupCommandArg1 = "/usr/local/bin/service_backups"
|
||||
backupCommandArg2 = "--verbose"
|
||||
backupCommandArg3 = "--loglevel=INFO"
|
||||
backupAllocArg1 = "/usr/local/bin/service_backups"
|
||||
backupAllocArg2 = "--verbose"
|
||||
backupAllocArg3 = "--loglevel=INFO"
|
||||
backupAllocArg4 = "--allocation"
|
||||
backupAllocArg5 = "--job"
|
||||
backupAllocArg6 = "--delete"
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
} # /client
|
||||
|
||||
{% if is_nomad_server %}
|
||||
# ----------------------------------------- Server Config
|
||||
server {
|
||||
enabled = true
|
||||
encrypt = "{{ nomad_encryption_key }}"
|
||||
{% if 'linode' in group_names %}
|
||||
bootstrap_expect = 1
|
||||
{% else %}
|
||||
bootstrap_expect = 3
|
||||
{% endif %}
|
||||
node_gc_threshold = "15m"
|
||||
job_gc_interval = "15m"
|
||||
job_gc_threshold = "6h"
|
||||
heartbeat_grace = "60s"
|
||||
min_heartbeat_ttl = "20s"
|
||||
raft_protocol = "3"
|
||||
|
||||
server_join {
|
||||
retry_join = [{% for h in groups['lan'] if hostvars[h].is_nomad_server == true %}"{{ hostvars[h].ansible_host }}"{% if not loop.last %}, {% endif %}{% endfor %}]
|
||||
retry_max = 3
|
||||
retry_interval = "15s"
|
||||
}
|
||||
}
|
||||
|
||||
autopilot {
|
||||
cleanup_dead_servers = true
|
||||
last_contact_threshold = "200ms"
|
||||
max_trailing_logs = 250
|
||||
server_stabilization_time = "10s"
|
||||
enable_redundancy_zones = false
|
||||
disable_upgrade_migration = false
|
||||
enable_custom_upgrades = false
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if is_nomad_server and is_nomad_client %}
|
||||
client {
|
||||
enabled = true
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
# ----------------------------------------- Telemety
|
||||
telemetry = {
|
||||
publish_allocation_metrics = true
|
||||
publish_node_metrics = true
|
||||
collection_interval = "10s"
|
||||
filter_default = false
|
||||
datadog_address = "localhost:8125"
|
||||
prefix_filter = [
|
||||
"+nomad.client.allocations.running",
|
||||
"+nomad.client.allocations.terminal",
|
||||
"+nomad.client.allocs.cpu.allocated",
|
||||
"+nomad.client.allocs.cpu.total_percent",
|
||||
"+nomad.client.allocs.memory.allocated",
|
||||
"+nomad.client.allocs.memory.swap",
|
||||
"+nomad.client.allocs.memory.usage",
|
||||
"+nomad.nomad.job_status.dead",
|
||||
"+nomad.nomad.job_status.running",
|
||||
"+nomad.nomad.job_status.pending",
|
||||
"+nomad.nomad.job_summary.running",
|
||||
"+nomad.nomad.job_summary.complete",
|
||||
"+nomad.nomad.job_summary.lost",
|
||||
"+nomad.nomad.job_summary.failed"]
|
||||
}
|
||||
|
||||
# ----------------------------------------- Plugins
|
||||
plugin "raw_exec" {
|
||||
config {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
plugin "docker" {
|
||||
config {
|
||||
allow_caps = [ "ALL" ]
|
||||
allow_privileged = true
|
||||
|
||||
volumes {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
36
templates/nomad.launchd.j2
Normal file
36
templates/nomad.launchd.j2
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/sbin</string>
|
||||
</dict>
|
||||
<key>KeepAlive</key>
|
||||
<dict>
|
||||
<key>PathState</key>
|
||||
<dict>
|
||||
<key>{{ mac_keep_alive_file }}</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>SuccessfulExit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Label</key>
|
||||
<string>com.{{ my_username }}.nomad</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/nomad</string>
|
||||
<string>agent</string>
|
||||
<string>-config</string>
|
||||
<string>{{ nomad_configuration_dir }}</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/usr/local/var/log/nomad.log</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/usr/local/var/log/nomad.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
25
templates/nomad.service.j2
Normal file
25
templates/nomad.service.j2
Normal file
@@ -0,0 +1,25 @@
|
||||
[Unit]
|
||||
Description=Nomad
|
||||
Documentation=https://nomadproject.io/docs/
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
ConditionFileNotEmpty={{ nomad_configuration_dir }}/nomad.hcl
|
||||
|
||||
[Service]
|
||||
{# {% if 'linode' in group_names %} #}
|
||||
User=nomad
|
||||
Group=nomad
|
||||
{# {% endif %} #}
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
ExecStart=/usr/local/bin/nomad agent -config {{ nomad_configuration_dir }}
|
||||
KillMode=process
|
||||
KillSignal=SIGINT
|
||||
LimitNOFILE=infinity
|
||||
LimitNPROC=infinity
|
||||
Restart=on-failure
|
||||
RestartSec=2
|
||||
StartLimitBurst=3
|
||||
TasksMax=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
21
templates/nomad_jobs/backup_fs.hcl
Normal file
21
templates/nomad_jobs/backup_fs.hcl
Normal file
@@ -0,0 +1,21 @@
|
||||
job "backup_local_filesystems" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "sysbatch"
|
||||
|
||||
periodic {
|
||||
cron = "0 */8 * * * *"
|
||||
prohibit_overlap = true
|
||||
time_zone = "America/New_York"
|
||||
}
|
||||
|
||||
task "do_backups" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupCommandArg1}", "${meta.backupCommandArg2}", "${meta.backupCommandArg3}"]
|
||||
}
|
||||
} // /task do_backups
|
||||
|
||||
} //job
|
||||
88
templates/nomad_jobs/changedetection.hcl
Normal file
88
templates/nomad_jobs/changedetection.hcl
Normal file
@@ -0,0 +1,88 @@
|
||||
job "changedetection" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "changedetection" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "webUI" {
|
||||
to = "5000"
|
||||
}
|
||||
}
|
||||
|
||||
task "changedetection" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
BASE_URL = "https://changes.{{ homelab_domain_name }}"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "dgtlmoon/changedetection.io:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/changedetection:/datastore"
|
||||
]
|
||||
ports = ["webUI"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "webUI"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`changes.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 100 # MHz
|
||||
memory = 150 # MB
|
||||
} // resources
|
||||
|
||||
} // task changedetection
|
||||
} // group
|
||||
} // job
|
||||
109
templates/nomad_jobs/chronograf.hcl
Normal file
109
templates/nomad_jobs/chronograf.hcl
Normal file
@@ -0,0 +1,109 @@
|
||||
job "chronograf" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "chronograf" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "chronografPort" {
|
||||
to = "8888"
|
||||
}
|
||||
}
|
||||
|
||||
task "await-influxdb" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
args = [
|
||||
"-c",
|
||||
"echo -n 'Waiting for influxdb.service.consul to come alive'; until nslookup influxdb.service.consul 2>&1 >/dev/null; do echo '.'; sleep 2; done"
|
||||
]
|
||||
network_mode = "host"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 200
|
||||
memory = 128
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task
|
||||
|
||||
task "chronograf" {
|
||||
|
||||
// env {
|
||||
// KEY = "VALUE"
|
||||
// }
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "chronograf:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["chronografPort"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "chronografPort"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "chronografPort"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
// resources {
|
||||
// cpu = 40 # MHz
|
||||
// memory = 10 # MB
|
||||
// } // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
100
templates/nomad_jobs/code.hcl
Normal file
100
templates/nomad_jobs/code.hcl
Normal file
@@ -0,0 +1,100 @@
|
||||
job "code" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "code" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port1" {
|
||||
// static = "80"
|
||||
to = "3000"
|
||||
}
|
||||
}
|
||||
|
||||
task "code" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
SUDO_PASSWORD = "{{ simple_web_password }}"
|
||||
PROXY_DOMAIN = "code.{{ homelab_domain_name }}"
|
||||
CONNECTION_TOKEN = "1234"
|
||||
DOCKER_MODS = "linuxserver/mods:code-server-python3|linuxserver/mods:code-server-shellcheck|linuxserver/mods:universal-git|linuxserver/mods:code-server-zsh"
|
||||
// CONNECTION_TOKEN = supersecrettoken
|
||||
// CONNECTION_SECRET = supersecrettoken
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "lscr.io/linuxserver/openvscode-server"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/${NOMAD_JOB_NAME}:/config"
|
||||
]
|
||||
ports = ["port1"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "port1"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.middlewares=authelia@file,redirectScheme@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "port1"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1500 # MHz
|
||||
memory = 300 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
64
templates/nomad_jobs/diagnostics.hcl
Normal file
64
templates/nomad_jobs/diagnostics.hcl
Normal file
@@ -0,0 +1,64 @@
|
||||
job "diagnostics" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
group "diagnostics" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
task "diagnostics" {
|
||||
|
||||
// env {
|
||||
// KEY = "VALUE"
|
||||
// }
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "alpine:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
args = [
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"chmod 755 /local/bootstrap.sh && /local/bootstrap.sh"
|
||||
]
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/backups/config_backups:/backups",
|
||||
"${meta.localStorageRoot}:/docker"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
template {
|
||||
destination = "local/bootstrap.sh"
|
||||
data = <<EOH
|
||||
#!/bin/sh
|
||||
|
||||
apk update
|
||||
apk add --no-cache bash
|
||||
apk add --no-cache bind-tools
|
||||
apk add --no-cache curl
|
||||
apk add --no-cache git
|
||||
apk add --no-cache jq
|
||||
apk add --no-cache openssl
|
||||
apk add --no-cache iperf3
|
||||
apk add --no-cache nano
|
||||
apk add --no-cache wget
|
||||
|
||||
tail -f /dev/null # Keep container running
|
||||
EOH
|
||||
}
|
||||
|
||||
} // tasks
|
||||
} // group
|
||||
} // job
|
||||
41
templates/nomad_jobs/diun.hcl
Normal file
41
templates/nomad_jobs/diun.hcl
Normal file
@@ -0,0 +1,41 @@
|
||||
job "diun" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "system"
|
||||
|
||||
group "diun" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
task "diun" {
|
||||
|
||||
env {
|
||||
// DIUN_PROVIDERS_DOCKER_ENDPOINT = "unix:///var/run/docker.sock"
|
||||
DIUN_NOTIF_PUSHOVER_RECIPIENT = "{{ pushover_recipient }}"
|
||||
DIUN_NOTIF_PUSHOVER_TOKEN = "{{ pushover_token }}"
|
||||
DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT = "true"
|
||||
DIUN_WATCH_FIRSTCHECKNOTIF = "false"
|
||||
DIUN_WATCH_SCHEDULE = "26 */48 * * *"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "crazymax/diun:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"/var/run/docker.sock:/var/run/docker.sock"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
// resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 300 # MB
|
||||
// } // resources
|
||||
|
||||
} // task diun
|
||||
} // group
|
||||
} // job
|
||||
120
templates/nomad_jobs/grafana.hcl
Normal file
120
templates/nomad_jobs/grafana.hcl
Normal file
@@ -0,0 +1,120 @@
|
||||
job "grafana" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "grafana" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "http" {}
|
||||
}
|
||||
|
||||
|
||||
task "grafana" {
|
||||
|
||||
env {
|
||||
GF_PATHS_CONFIG = "/local/grafana.ini"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "grafana/grafana:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["http"]
|
||||
volumes = ["${meta.nfsStorageRoot}/pi-cluster/grafana:/var/lib/grafana"]
|
||||
} // docker config
|
||||
|
||||
template {
|
||||
destination = "local/grafana.ini"
|
||||
data = <<EOH
|
||||
[server]
|
||||
domain = grafana.{{ homelab_domain_name }}
|
||||
{% raw %}http_port = {{ env "NOMAD_PORT_http" }}{% endraw +%}
|
||||
[analytics]
|
||||
reporting_enabled = false
|
||||
[security]
|
||||
admin_user = {{ my_username }}
|
||||
admin_password = {{ grafana_admin_password }}
|
||||
cookie_secure = true
|
||||
[users]
|
||||
allow_sign_up = false
|
||||
allow_org_create = false
|
||||
[smtp]
|
||||
enabled = true
|
||||
host = {{ email_smtp_host }}:{{ email_smtp_port}}
|
||||
user = {{ email_smtp_account }}
|
||||
password = {{ grafana_smtp_password }}
|
||||
skip_verify = true
|
||||
from_address = {{ my_email_address }}
|
||||
from_name = Grafana
|
||||
[log.file]
|
||||
level = info
|
||||
[date_formats]
|
||||
default_timezone = America/New_York
|
||||
[auth.proxy]
|
||||
enabled = true
|
||||
header_name = Remote-User
|
||||
header_property = username
|
||||
auto_sign_up = false
|
||||
sync_ttl = 60
|
||||
EOH
|
||||
}
|
||||
|
||||
service {
|
||||
port = "http"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.middlewares.${NOMAD_JOB_NAME}_logout_redirect.redirectregex.regex=${NOMAD_JOB_NAME}\\.{{ homelab_domain_name }}/logout$",
|
||||
"traefik.http.middlewares.${NOMAD_JOB_NAME}_logout_redirect.redirectregex.replacement=authelia.{{ homelab_domain_name }}/logout",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.middlewares=authelia@file,${NOMAD_JOB_NAME}_logout_redirect"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
port = "http"
|
||||
path = "/"
|
||||
interval = "90s"
|
||||
timeout = "15s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 200 # MHz
|
||||
memory = 60 # MB
|
||||
} // resources
|
||||
|
||||
} // task grafana
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
88
templates/nomad_jobs/headless_chrome.hcl
Normal file
88
templates/nomad_jobs/headless_chrome.hcl
Normal file
@@ -0,0 +1,88 @@
|
||||
job "headless-chrome" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
constraint {
|
||||
attribute = "${attr.cpu.arch}"
|
||||
value = "amd64"
|
||||
}
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "headless-chrome" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port1" {
|
||||
static = "9222"
|
||||
to = "9222"
|
||||
}
|
||||
}
|
||||
|
||||
task "headless-chrome" {
|
||||
|
||||
// env {
|
||||
// PUID = "${meta.PUID}"
|
||||
// PGID = "${meta.PGID}"
|
||||
// }
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "alpeware/chrome-headless-trunk:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["port1"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "port1"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`chrome.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "port1"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
// resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 300 # MB
|
||||
// } // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
113
templates/nomad_jobs/influxdb.hcl
Normal file
113
templates/nomad_jobs/influxdb.hcl
Normal file
@@ -0,0 +1,113 @@
|
||||
job "influxdb" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "influxdbGroup" {
|
||||
count = 1
|
||||
network {
|
||||
port "httpAPI" {
|
||||
static = "{{ influxdb_port }}"
|
||||
to = "8086"
|
||||
}
|
||||
}
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = ["${meta.restoreCommand1}", "${meta.restoreCommand2}", "${NOMAD_JOB_NAME}", "${meta.restoreCommand3}"]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "influxdb" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "influxdb:{{ influxdb_version }}"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["httpAPI"]
|
||||
volumes = [
|
||||
"${meta.localStorageRoot}/influxdb:/var/lib/influxdb"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "httpAPI"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "httpAPI"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
|
||||
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1000 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // /task influxdb
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupAllocArg1}", "${meta.backupAllocArg2}", "${meta.backupAllocArg3}", "${meta.backupAllocArg4}", "${meta.backupAllocArg5}", "${NOMAD_JOB_NAME}", "${meta.backupAllocArg6}"]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
} // group
|
||||
} // job
|
||||
126
templates/nomad_jobs/lidarr.hcl
Normal file
126
templates/nomad_jobs/lidarr.hcl
Normal file
@@ -0,0 +1,126 @@
|
||||
job "lidarr" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "10m"
|
||||
progress_deadline = "15m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "lidarrGroup" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "10m"
|
||||
}
|
||||
|
||||
network {
|
||||
port "lidarr" {
|
||||
to = "8686"
|
||||
}
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = ["${meta.restoreCommand1}", "${meta.restoreCommand2}", "${NOMAD_JOB_NAME}", "${meta.restoreCommand3}"]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "lidarr" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
//DOCKER_MODS = "linuxserver/mods:universal-cron|linuxserver/mods:universal-mod2"
|
||||
//UMASK_SET = 022 #optional
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "linuxserver/lidarr:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["lidarr"]
|
||||
volumes = [
|
||||
"${meta.localStorageRoot}/lidarr:/config",
|
||||
"${meta.nfsStorageRoot}/media:/media"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "lidarr"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "lidarr"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "10m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 2000 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // /task lidarr main task
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupAllocArg1}", "${meta.backupAllocArg2}", "${meta.backupAllocArg3}", "${meta.backupAllocArg4}", "${meta.backupAllocArg5}", "${NOMAD_JOB_NAME}", "${meta.backupAllocArg6}"]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
157
templates/nomad_jobs/loki.hcl
Normal file
157
templates/nomad_jobs/loki.hcl
Normal file
@@ -0,0 +1,157 @@
|
||||
job "loki" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "loki" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "1m"
|
||||
}
|
||||
|
||||
network {
|
||||
port "loki_port" {
|
||||
static = "3100"
|
||||
to = "3100"
|
||||
}
|
||||
}
|
||||
|
||||
task "loki" {
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "grafana/loki:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"local/loki/local-config.yaml:/etc/loki/local-config.yaml",
|
||||
"${meta.nfsStorageRoot}/pi-cluster/loki:/loki"
|
||||
|
||||
]
|
||||
ports = ["loki_port"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "loki_port"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/metrics"
|
||||
interval = "30s"
|
||||
timeout = "10s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
template {
|
||||
destination = "local/loki/local-config.yaml"
|
||||
env = false
|
||||
change_mode = "noop"
|
||||
data = <<-EOH
|
||||
---
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
grpc_listen_port: 9096
|
||||
|
||||
ingester:
|
||||
wal:
|
||||
enabled: true
|
||||
dir: /tmp/wal
|
||||
lifecycler:
|
||||
address: 127.0.0.1
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
replication_factor: 1
|
||||
final_sleep: 0s
|
||||
chunk_idle_period: 1h # Any chunk not receiving new logs in this time will be flushed
|
||||
max_chunk_age: 1h # All chunks will be flushed when they hit this age. Def: 1h
|
||||
chunk_target_size: 1048576 # Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first
|
||||
chunk_retain_period: 30s # Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)
|
||||
max_transfer_retries: 0 # Chunk transfers disabled
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2020-10-24
|
||||
store: boltdb-shipper
|
||||
object_store: filesystem
|
||||
schema: v11
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
storage_config:
|
||||
boltdb_shipper:
|
||||
active_index_directory: /loki/boltdb-shipper-active
|
||||
cache_location: /loki/boltdb-shipper-cache
|
||||
cache_ttl: 24h # Can be increased for faster performance over longer query periods, uses more disk space
|
||||
shared_store: filesystem
|
||||
filesystem:
|
||||
directory: /loki/chunks
|
||||
|
||||
compactor:
|
||||
working_directory: /loki/boltdb-shipper-compactor
|
||||
shared_store: filesystem
|
||||
|
||||
limits_config:
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
|
||||
chunk_store_config:
|
||||
max_look_back_period: 0s
|
||||
|
||||
table_manager:
|
||||
retention_deletes_enabled: false
|
||||
retention_period: 0s
|
||||
|
||||
ruler:
|
||||
storage:
|
||||
type: local
|
||||
local:
|
||||
directory: /loki/rules
|
||||
rule_path: /loki/rules-temp
|
||||
alertmanager_url: http://localhost:9093
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
enable_api: true
|
||||
EOH
|
||||
} // template
|
||||
|
||||
// resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 300 # MB
|
||||
// } // resources
|
||||
|
||||
} // task loki
|
||||
} // group
|
||||
} // job
|
||||
93
templates/nomad_jobs/nginx.hcl
Normal file
93
templates/nomad_jobs/nginx.hcl
Normal file
@@ -0,0 +1,93 @@
|
||||
job "nginx" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
operator = "regexp"
|
||||
value = "rpi"
|
||||
}
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "nginx" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "web" {
|
||||
to = "80"
|
||||
}
|
||||
// port "websecure" {
|
||||
// to = "443"
|
||||
// }
|
||||
}
|
||||
|
||||
task "nginx" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/nginx"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"/mnt/usbDrive/nginx:/config"
|
||||
]
|
||||
ports = ["web"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "web"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "web"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 100 # MHz
|
||||
memory = 300 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
91
templates/nomad_jobs/nzbhydra.hcl
Normal file
91
templates/nomad_jobs/nzbhydra.hcl
Normal file
@@ -0,0 +1,91 @@
|
||||
job "nzbhydra" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "nzbhydra" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "hydra_port" {
|
||||
to = "5076"
|
||||
}
|
||||
}
|
||||
|
||||
task "nzbhydra" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
//DOCKER_MODS = "linuxserver/mods:universal-cron|linuxserver/mods:universal-mod2"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/nzbhydra2:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["hydra_port"]
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/nzbhydra:/config"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "hydra_port"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`hydra.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
interval = "30s"
|
||||
timeout = "10s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 600 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
94
templates/nomad_jobs/overseerr.hcl
Normal file
94
templates/nomad_jobs/overseerr.hcl
Normal file
@@ -0,0 +1,94 @@
|
||||
job "overseerr" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "overseerr" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "overseerr" {
|
||||
to = "5055"
|
||||
}
|
||||
}
|
||||
|
||||
task "overseerr" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/overseerr"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["overseerr"]
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/overseerr:/config"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "overseerr"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=overseerr",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.middlewares=authelia@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "overseerr"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1600 # MHz
|
||||
memory = 300 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
155
templates/nomad_jobs/pihole.hcl
Normal file
155
templates/nomad_jobs/pihole.hcl
Normal file
@@ -0,0 +1,155 @@
|
||||
job "pihole" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
operator = "regexp"
|
||||
value = "rpi(2|3)"
|
||||
}
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "pihole-group" {
|
||||
|
||||
network {
|
||||
port "web" {
|
||||
static = "80"
|
||||
to = "80"
|
||||
}
|
||||
port "dns" {
|
||||
static = "53"
|
||||
to = "53"
|
||||
}
|
||||
// port "dhcp" {
|
||||
// static = "67"
|
||||
// to = "67"
|
||||
// }
|
||||
}
|
||||
|
||||
task "await_filesytem" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
network_mode = "host"
|
||||
args = [
|
||||
"-c",
|
||||
"echo -n 'Waiting for /mnt/pi-cluster/pihole5 to be mounted'; until [ -f /etc/pihole/gravity.db ]; do echo '.'; sleep 2; done",
|
||||
]
|
||||
volumes = [
|
||||
"/mnt/pi-cluster/pihole5:/etc/pihole/"
|
||||
]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /await-filesystem
|
||||
|
||||
task "pihole" {
|
||||
env {
|
||||
// REV_SERVER_DOMAIN = ""
|
||||
ADMIN_EMAIL = "{{ my_email_address }}"
|
||||
DHCP_ACTIVE = "false"
|
||||
DNS_BOGUS_PRIV = "false"
|
||||
DNS_FQDN_REQUIRED = "false"
|
||||
DNSSEC = "false"
|
||||
FTLCONF_REPLY_ADDR4 = "${attr.unique.network.ip-address}"
|
||||
IPv6 = "false"
|
||||
PIHOLE_DNS_ = "10.0.30.1#53"
|
||||
QUERY_LOGGING = "true"
|
||||
REV_SERVER = "true"
|
||||
REV_SERVER_CIDR = "10.0.0.0/16"
|
||||
REV_SERVER_TARGET = "10.0.30.1"
|
||||
TEMPERATUREUNIT = "f"
|
||||
TZ = "America/New_York"
|
||||
WEBTHEME = "default-light"
|
||||
WEBUIBOXEDLAYOUT = "traditional"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "pihole/pihole:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
dns_servers = [
|
||||
"127.0.0.1",
|
||||
"1.1.1.1"
|
||||
]
|
||||
extra_hosts = [
|
||||
"laptopVPN:10.0.90.2",
|
||||
"FiddleStixPhoneVPN:10.0.90.3"
|
||||
]
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/pihole5:/etc/pihole/",
|
||||
"${meta.nfsStorageRoot}/pi-cluster/pihole5/dnsmasq.d:/etc/dnsmasq.d/"
|
||||
// "${meta.nfsStorageRoot}/pi-cluster/pihole5/logs/pihole.log:/var/log/pihole.log",
|
||||
// "${meta.nfsStorageRoot}/pi-cluster/pihole5/logs/pihole-FTL.log:/var/log/pihole-FTL.log"
|
||||
]
|
||||
ports = ["web", "dns"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 400 # MHz
|
||||
memory = 80 # MB
|
||||
}
|
||||
|
||||
service {
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
port = "web"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`p.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.middlewares.piholeRedirect.redirectregex.regex=^(https?://p\\.{{ homelab_domain_name }})/?$",
|
||||
"traefik.http.middlewares.piholeRedirect.redirectregex.replacement=$${1}/admin/",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.middlewares=authelia@file,piholeRedirect"
|
||||
]
|
||||
check {
|
||||
type = "http"
|
||||
path = "/admin/"
|
||||
port = "web"
|
||||
interval = "30s"
|
||||
timeout = "2s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "10m"
|
||||
ignore_warnings = false
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "piholeDNStcp"
|
||||
port = "dns"
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "dns"
|
||||
interval = "30s"
|
||||
timeout = "2s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "60s"
|
||||
ignore_warnings = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // group
|
||||
}
|
||||
88
templates/nomad_jobs/promtail-syslogs.hcl
Normal file
88
templates/nomad_jobs/promtail-syslogs.hcl
Normal file
@@ -0,0 +1,88 @@
|
||||
job "promtail-syslogs" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "system"
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "promtail-syslogs" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
task "promtail-syslogs" {
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "grafana/promtail"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"/var/log:/var/log"
|
||||
]
|
||||
args = [
|
||||
"-config.file",
|
||||
"/local/promtail-config.yaml",
|
||||
"-print-config-stderr"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
|
||||
template {
|
||||
destination = "local/promtail-config.yaml"
|
||||
env = false
|
||||
data = <<EOH
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
{% raw -%}
|
||||
clients:
|
||||
- url: http://{{ range service "loki" }}{{ .Address }}:{{ .Port }}{{ end }}/loki/api/v1/push
|
||||
{% endraw %}
|
||||
|
||||
scrape_configs:
|
||||
- job_name: system
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: syslog
|
||||
{% raw %}host: {{ env "node.unique.name" }}{% endraw +%}
|
||||
__path__: /var/log/syslog
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: authlog
|
||||
{% raw %}host: {{ env "node.unique.name" }}{% endraw +%}
|
||||
__path__: /var/log/auth.log
|
||||
|
||||
EOH
|
||||
} // template
|
||||
|
||||
|
||||
resources {
|
||||
cpu = 30 # MHz
|
||||
memory = 30 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
129
templates/nomad_jobs/prowlarr.hcl
Normal file
129
templates/nomad_jobs/prowlarr.hcl
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
job "prowlarr" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi4"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "prowlarrGroup" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "10m"
|
||||
}
|
||||
|
||||
network {
|
||||
port "prowlarr" {
|
||||
to = "9696"
|
||||
}
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = ["${meta.restoreCommand1}", "${meta.restoreCommand2}", "${NOMAD_JOB_NAME}", "${meta.restoreCommand3}"]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "prowlarr" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
//DOCKER_MODS = "linuxserver/mods:universal-cron|linuxserver/mods:universal-mod2"
|
||||
//UMASK_SET = 022 #optional
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/prowlarr:develop"
|
||||
force_pull = true
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["prowlarr"]
|
||||
volumes = [
|
||||
"${meta.localStorageRoot}/prowlarr:/config"
|
||||
]
|
||||
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "prowlarr"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "prowlarr"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1000 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // /task prowlarr
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupAllocArg1}", "${meta.backupAllocArg2}", "${meta.backupAllocArg3}", "${meta.backupAllocArg4}", "${meta.backupAllocArg5}", "${NOMAD_JOB_NAME}", "${meta.backupAllocArg6}"]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
123
templates/nomad_jobs/radarr.hcl
Normal file
123
templates/nomad_jobs/radarr.hcl
Normal file
@@ -0,0 +1,123 @@
|
||||
job "radarr" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "radarrGroup" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "10m"
|
||||
}
|
||||
|
||||
network {
|
||||
port "radarr" {
|
||||
to = "7878"
|
||||
}
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = ["${meta.restoreCommand1}", "${meta.restoreCommand2}", "${NOMAD_JOB_NAME}", "${meta.restoreCommand3}"]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "radarr" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
//DOCKER_MODS = "linuxserver/mods:universal-cron|linuxserver/mods:universal-mod2"
|
||||
//UMASK_SET = 022 #optional
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/radarr:develop"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
force_pull = true
|
||||
ports = ["radarr"]
|
||||
volumes = [
|
||||
"${meta.localStorageRoot}/${NOMAD_JOB_NAME}:/config",
|
||||
"${meta.nfsStorageRoot}/media:/media"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "radarr"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "radarr"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 2000 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // /task radarr
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupAllocArg1}", "${meta.backupAllocArg2}", "${meta.backupAllocArg3}", "${meta.backupAllocArg4}", "${meta.backupAllocArg5}", "${NOMAD_JOB_NAME}", "${meta.backupAllocArg6}"]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
|
||||
} // group
|
||||
} // job
|
||||
468
templates/nomad_jobs/reverse-proxy.hcl
Normal file
468
templates/nomad_jobs/reverse-proxy.hcl
Normal file
@@ -0,0 +1,468 @@
|
||||
job "reverse-proxy" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
value = "rpi1"
|
||||
}
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "reverse-proxy-group" {
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "authelia-port" {
|
||||
static = { { authelia_port } }
|
||||
to = 9091
|
||||
}
|
||||
port "whoami" {
|
||||
to = 80
|
||||
}
|
||||
port "dashboard" {
|
||||
static = 8080
|
||||
to = 8080
|
||||
}
|
||||
port "web" {
|
||||
static = 80
|
||||
to = 80
|
||||
}
|
||||
port "websecure" {
|
||||
static = 443
|
||||
to = 443
|
||||
}
|
||||
port "externalwebsecure" {
|
||||
static = 4430
|
||||
to = 4430
|
||||
}
|
||||
}
|
||||
|
||||
task "authelia" {
|
||||
|
||||
env {
|
||||
TZ = "America/New_York"
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "authelia/authelia"
|
||||
hostname = "authelia"
|
||||
ports = ["authelia-port"]
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/authelia:/config"
|
||||
]
|
||||
args = [
|
||||
"--config",
|
||||
"/local/authelia/config.yaml"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
template {
|
||||
destination = "local/authelia/config.yaml"
|
||||
env = false
|
||||
change_mode = "noop"
|
||||
perms = "644"
|
||||
data = <<-EOH
|
||||
---
|
||||
## The theme to display: light, dark, grey, auto.
|
||||
theme: auto
|
||||
|
||||
jwt_secret: {{ authelia_jwt_secret}}
|
||||
default_redirection_url: https://authelia.{{ homelab_domain_name}}
|
||||
|
||||
server:
|
||||
host: 0.0.0.0
|
||||
port: 9091
|
||||
path: ""
|
||||
read_buffer_size: 4096
|
||||
write_buffer_size: 4096
|
||||
enable_pprof: false
|
||||
enable_expvars: false
|
||||
disable_healthcheck: false
|
||||
|
||||
log:
|
||||
level: info
|
||||
format: text
|
||||
# file_path: "/config/log.txt"
|
||||
keep_stdout: false
|
||||
|
||||
totp:
|
||||
issuer: authelia.com
|
||||
|
||||
authentication_backend:
|
||||
disable_reset_password: false
|
||||
file:
|
||||
path: /config/users.yml
|
||||
password:
|
||||
algorithm: argon2id
|
||||
iterations: 1
|
||||
salt_length: 16
|
||||
parallelism: 8
|
||||
memory: 64
|
||||
|
||||
access_control:
|
||||
default_policy: deny
|
||||
networks:
|
||||
- name: internal
|
||||
networks:
|
||||
- 10.0.0.0/16
|
||||
#- 172.16.0.0/12
|
||||
#- 192.168.0.0/18
|
||||
rules:
|
||||
# Rules applied to everyone
|
||||
- domain: "*.{{ homelab_domain_name }}"
|
||||
policy: two_factor
|
||||
networks:
|
||||
- internal
|
||||
|
||||
session:
|
||||
name: authelia_session
|
||||
domain: {{ homelab_domain_name }}
|
||||
same_site: lax
|
||||
secret: {{ authelia_session_secret }}
|
||||
expiration: 1h
|
||||
inactivity: 15m
|
||||
remember_me_duration: 1w
|
||||
|
||||
regulation:
|
||||
max_retries: 5
|
||||
find_time: 10m
|
||||
ban_time: 15m
|
||||
|
||||
storage:
|
||||
encryption_key: {{ authelia_sqlite_encryption_key}}
|
||||
local:
|
||||
path: /config/db.sqlite3
|
||||
|
||||
notifier:
|
||||
smtp:
|
||||
username: {{ email_smtp_account }}
|
||||
password: {{ authelia_smtp_password }}
|
||||
host: {{ email_smtp_host }}
|
||||
port: {{ email_smtp_port }}
|
||||
sender: "Authelia <{{ my_email_address }}>"
|
||||
subject: "[Authelia] {title}"
|
||||
startup_check_address: {{ my_email_address }}
|
||||
|
||||
EOH
|
||||
}
|
||||
|
||||
service {
|
||||
port = "authelia-port"
|
||||
name = "${NOMAD_TASK_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.rule=Host(`authelia.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.service=${NOMAD_TASK_NAME}",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.middlewares.authelia-headers.headers.customResponseHeaders.Cache-Control=no-store",
|
||||
"traefik.http.middlewares.authelia-headers.headers.customResponseHeaders.Pragma=no-cache",
|
||||
"traefik.http.routers.authelia.middlewares=authelia-headers"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "authelia-port"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 200 # MHz
|
||||
memory = 110 # MB
|
||||
}
|
||||
|
||||
} // task authelia
|
||||
|
||||
task "whoami" {
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "containous/whoami:latest"
|
||||
hostname = "${NOMAD_TASK_NAME}"
|
||||
ports = ["whoami"]
|
||||
|
||||
} // /docker config
|
||||
|
||||
service {
|
||||
port = "whoami"
|
||||
name = "${NOMAD_TASK_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.rule=Host(`${NOMAD_TASK_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.service=${NOMAD_TASK_NAME}",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.middlewares=authelia@file"
|
||||
]
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
interval = "90s"
|
||||
timeout = "15s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 2
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
}
|
||||
resources {
|
||||
cpu = 25 # MHz
|
||||
memory = 10 # MB
|
||||
}
|
||||
|
||||
} // /task whoami
|
||||
|
||||
task "traefik" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
CF_API_EMAIL = "{{ my_email_address }}"
|
||||
CF_DNS_API_TOKEN = "{{ traefik_cf_api_token }}"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "traefik:{{ traefik_version }}"
|
||||
hostname = "traefik"
|
||||
ports = ["dashboard", "web", "websecure", "externalwebsecure"]
|
||||
volumes = ["${meta.nfsStorageRoot}/pi-cluster/traefik/acme:/acme"]
|
||||
args = [
|
||||
"--global.sendAnonymousUsage=false",
|
||||
"--global.checkNewVersion=false",
|
||||
"--entryPoints.web.address=:80",
|
||||
"--entryPoints.websecure.address=:443",
|
||||
"--entryPoints.externalwebsecure.address=:4430",
|
||||
"--entrypoints.web.http.redirections.entryPoint.to=websecure",
|
||||
"--entrypoints.web.http.redirections.entryPoint.scheme=https",
|
||||
"--entrypoints.web.http.redirections.entryPoint.permanent=true",
|
||||
"--providers.file.filename=/local/traefik/siteconfigs.toml",
|
||||
"--providers.file.watch=true",
|
||||
"--providers.consulcatalog=true",
|
||||
"--providers.consulcatalog.endpoint.address=http://consul.service.consul:8500",
|
||||
"--providers.consulcatalog.prefix=traefik",
|
||||
"--providers.consulcatalog.exposedbydefault=false",
|
||||
"--metrics=true",
|
||||
"--metrics.influxdb=true",
|
||||
"--metrics.influxdb.address=influxdb.service.consul:{{ influxdb_port }}",
|
||||
"--metrics.influxdb.protocol=http",
|
||||
"--metrics.influxdb.pushinterval=10s",
|
||||
"--metrics.influxdb.database=homelab",
|
||||
"--metrics.influxdb.retentionpolicy=2day",
|
||||
"--metrics.influxdb.addentrypointslabels=true",
|
||||
"--metrics.influxdb.addserviceslabels=true",
|
||||
"--accesslog=true",
|
||||
"--log=true",
|
||||
"--log.level=ERROR",
|
||||
"--api=true",
|
||||
"--api.dashboard=true",
|
||||
"--api.insecure=true",
|
||||
"--certificatesresolvers.cloudflare.acme.email={{ my_email_address }}",
|
||||
"--certificatesresolvers.cloudflare.acme.storage=/acme/acme-${node.unique.name}.json",
|
||||
"--certificatesresolvers.cloudflare.acme.dnschallenge=true",
|
||||
"--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare",
|
||||
"--certificatesresolvers.cloudflare.acme.dnschallenge.delaybeforecheck=10",
|
||||
"--certificatesresolvers.cloudflare.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
template {
|
||||
destination = "local/traefik/httpasswd"
|
||||
env = false
|
||||
change_mode = "noop"
|
||||
data = <<-EOH
|
||||
{{ my_username }}:{{ traefik_http_pass_me }}
|
||||
family:{{ traefik_http_pass_family }}
|
||||
EOH
|
||||
}
|
||||
|
||||
template {
|
||||
destination = "local/traefik/httpasswdFamily"
|
||||
env = false
|
||||
change_mode = "noop"
|
||||
data = <<-EOH
|
||||
{{ my_username }}:{{ traefik_http_pass_me }}
|
||||
family:{{ traefik_http_pass_family }}
|
||||
EOH
|
||||
}
|
||||
|
||||
template {
|
||||
destination = "local/traefik/siteconfigs.toml"
|
||||
env = false
|
||||
change_mode = "noop"
|
||||
data = <<-EOH
|
||||
[http]
|
||||
[http.middlewares]
|
||||
[http.middlewares.compress.compress]
|
||||
|
||||
[http.middlewares.localIPOnly.ipWhiteList]
|
||||
sourceRange = ["10.0.0.0/16"]
|
||||
|
||||
[http.middlewares.redirectScheme.redirectScheme]
|
||||
scheme = "https"
|
||||
permanent = true
|
||||
|
||||
[http.middlewares.authelia.forwardAuth]
|
||||
address = "http://authelia.service.consul:{{ authelia_port }}/api/verify?rd=https://authelia.{{ homelab_domain_name }}"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = ["Remote-User", "Remote-Groups", "Remote-Name", "Remote-Email"]
|
||||
|
||||
[http.middlewares.basicauth.basicauth]
|
||||
usersfile = "/local/traefik/httpasswd"
|
||||
removeHeader = true
|
||||
|
||||
[http.middlewares.basicauth-family.basicauth]
|
||||
usersfile = "/local/traefik/httpasswdFamily"
|
||||
removeHeader = true
|
||||
|
||||
[http.middlewares.allowFrame.headers]
|
||||
customFrameOptionsValue = "allow-from https://home.{{ homelab_domain_name }}"
|
||||
|
||||
[http.routers]
|
||||
|
||||
[http.routers.consul]
|
||||
rule = "Host(`consul.{{ homelab_domain_name }}`)"
|
||||
service = "consul"
|
||||
entrypoints = ["web","websecure"]
|
||||
[http.routers.consul.tls]
|
||||
certResolver = "cloudflare" # From static configuration
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.consul]
|
||||
[http.services.consul.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.consul.loadBalancer.servers]]
|
||||
url = "http://consul.service.consul:8500"
|
||||
EOH
|
||||
}
|
||||
|
||||
service {
|
||||
port = "dashboard"
|
||||
name = "${NOMAD_TASK_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.rule=Host(`${NOMAD_TASK_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.service=${NOMAD_TASK_NAME}",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.middlewares=authelia@file,redirectScheme@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "dashboard"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
//cpu = 40 # MHz
|
||||
memory = 64 # MB
|
||||
} // resources
|
||||
|
||||
} // task traefik
|
||||
|
||||
// task "promtail-traefik" {
|
||||
|
||||
// driver = "docker"
|
||||
// config {
|
||||
// image = "grafana/promtail"
|
||||
// hostname = "promtail-traefik"
|
||||
// volumes = [
|
||||
// "/mnt/pi-cluster/logs:/traefik"
|
||||
// ]
|
||||
// args = [
|
||||
// "-config.file",
|
||||
// "/local/promtail-config.yaml",
|
||||
// "-print-config-stderr",
|
||||
// ]
|
||||
// } // docker config
|
||||
|
||||
// template {
|
||||
// destination = "local/promtail-config.yaml"
|
||||
// env = false
|
||||
// data = <<-EOH
|
||||
// server:
|
||||
// http_listen_port: 9080
|
||||
// grpc_listen_port: 0
|
||||
|
||||
// positions:
|
||||
// filename: /alloc/positions.yaml
|
||||
|
||||
// {% raw -%}
|
||||
// clients:
|
||||
// - url: http://{{ range service "loki" }}{{ .Address }}:{{ .Port }}{{ end }}/loki/api/v1/push
|
||||
// {% endraw %}
|
||||
|
||||
// scrape_configs:
|
||||
// - job_name: traefik
|
||||
// static_configs:
|
||||
// - targets:
|
||||
// - localhost
|
||||
// labels:
|
||||
// job: traefik_access
|
||||
// {% raw %}host: {{ env "node.unique.name" }}{% endraw +%}
|
||||
// __path__: "/alloc/logs/traefik.std*.0"
|
||||
// pipeline_stages:
|
||||
// - regex:
|
||||
// expression: '^(?P<remote_addr>[\w\.]+) - (?P<remote_user>[^ ]*) \[(?P<time_local>.*)\] "(?P<method>[^ ]*) (?P<request>[^ ]*) (?P<protocol>[^ ]*)" (?P<status>[\d]+) (?P<body_bytes_sent>[\d]+) "(?P<http_referer>[^"]*)" "(?P<http_user_agent>[^"]*)" (?P<request_number>[^ ]+) "(?P<router>[^ ]+)" "(?P<server_URL>[^ ]+)" (?P<response_time_ms>[^ ]+)ms$'
|
||||
// - labels:
|
||||
// method:
|
||||
// status:
|
||||
// router:
|
||||
// response_time_ms:
|
||||
|
||||
// EOH
|
||||
// } // template
|
||||
|
||||
// lifecycle {
|
||||
// hook = "poststart"
|
||||
// sidecar = true
|
||||
// }
|
||||
|
||||
// resources {
|
||||
// cpu = 30 # MHz
|
||||
// memory = 30 # MB
|
||||
// } // resources
|
||||
|
||||
// } // promtail sidecar task
|
||||
|
||||
} // reverse-proxy-group
|
||||
}
|
||||
139
templates/nomad_jobs/sonarr.hcl
Normal file
139
templates/nomad_jobs/sonarr.hcl
Normal file
@@ -0,0 +1,139 @@
|
||||
job "sonarr" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "macmini"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "sonarrGroup" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "10m"
|
||||
}
|
||||
|
||||
network {
|
||||
port "sonarr" {
|
||||
to = "8989"
|
||||
}
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = [
|
||||
"${meta.restoreCommand1}",
|
||||
"${meta.restoreCommand2}",
|
||||
"${NOMAD_JOB_NAME}",
|
||||
"${meta.restoreCommand3}"
|
||||
]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "sonarr" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
//DOCKER_MODS = "linuxserver/mods:universal-cron|linuxserver/mods:universal-mod2"
|
||||
//UMASK_SET = 022 #optional
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "linuxserver/sonarr:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["sonarr"]
|
||||
volumes = [
|
||||
"${meta.localStorageRoot}/${NOMAD_JOB_NAME}:/config",
|
||||
"${meta.nfsStorageRoot}/media:/media"
|
||||
]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "sonarr"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=sonarr",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "sonarr"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1000 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // /task sonarr
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = [
|
||||
"${meta.backupAllocArg1}",
|
||||
"${meta.backupAllocArg2}",
|
||||
"${meta.backupAllocArg3}",
|
||||
"${meta.backupAllocArg4}",
|
||||
"${meta.backupAllocArg5}",
|
||||
"${NOMAD_JOB_NAME}",
|
||||
"${meta.backupAllocArg6}"
|
||||
]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
103
templates/nomad_jobs/stash.hcl
Normal file
103
templates/nomad_jobs/stash.hcl
Normal file
@@ -0,0 +1,103 @@
|
||||
job "stash" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
operator = "regexp"
|
||||
value = "macmini"
|
||||
}
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "stashGroup" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port1" {
|
||||
to = "9999"
|
||||
}
|
||||
}
|
||||
|
||||
task "stash" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
STASH_STASH = "/data/"
|
||||
STASH_GENERATED = "/generated/"
|
||||
STASH_METADATA = "/metadata/"
|
||||
STASH_CACHE = "/cache/"
|
||||
STASH_PORT = "9999"
|
||||
STASH_EXTERNAL_HOST = "https://${NOMAD_JOB_NAME}.{{ homelab_domain_name }}"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "stashapp/stash:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/nate/.stash/cache:/cache",
|
||||
"${meta.nfsStorageRoot}/nate/.stash/config:/root/.stash",
|
||||
"${meta.nfsStorageRoot}/nate/.stash/generated:/generated",
|
||||
"${meta.nfsStorageRoot}/nate/.stash/media:/data",
|
||||
"${meta.nfsStorageRoot}/nate/.stash/metadata:/metadata",
|
||||
"/etc/timezone:/etc/timezone:ro"
|
||||
]
|
||||
ports = ["port1"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "port1"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.middlewares=authelia@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "port1"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 4500 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
100
templates/nomad_jobs/syncthing.hcl
Normal file
100
templates/nomad_jobs/syncthing.hcl
Normal file
@@ -0,0 +1,100 @@
|
||||
job "syncthing" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "syncthing" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "webGUI" {
|
||||
to = "8384"
|
||||
}
|
||||
port "listen_tcp_udp" {
|
||||
static = "22000"
|
||||
to = "22000"
|
||||
}
|
||||
port "udp_proto_discovery" {
|
||||
static = "21027"
|
||||
to = "21027"
|
||||
}
|
||||
}
|
||||
|
||||
task "syncthing" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/syncthing"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/${NOMAD_JOB_NAME}:/config",
|
||||
"${meta.nfsStorageRoot}/${NOMAD_JOB_NAME}:/Sync"
|
||||
]
|
||||
ports = ["webGUI","listen_tcp_udp","udp_proto_discovery"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "webGUI"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=syncthing",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.middlewares=authelia@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "webGUI"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1200 # MHz
|
||||
memory = 300 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
191
templates/nomad_jobs/template-groups.hcl
Normal file
191
templates/nomad_jobs/template-groups.hcl
Normal file
@@ -0,0 +1,191 @@
|
||||
job "TEMPLATE" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "TEMPLATE-db-group" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port1" {
|
||||
static = "80"
|
||||
to = "80"
|
||||
}
|
||||
}
|
||||
|
||||
task "TEMPLATE-db" {
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
env {
|
||||
// PUID = "${meta.PUID}"
|
||||
// PGID = "${meta.PGID}"
|
||||
// TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = ""
|
||||
hostname = "${NOMAD_JOB_NAME}1"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/${NOMAD_JOB_NAME}1:/data",
|
||||
"/etc/timezone:/etc/timezone:ro",
|
||||
"/etc/localtime:/etc/localtime:ro"
|
||||
]
|
||||
ports = ["port1"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "port1"
|
||||
name = "${NOMAD_JOB_NAME}1"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}1.rule=Host(`${NOMAD_JOB_NAME}1.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}1.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}1.service=${NOMAD_JOB_NAME}1",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}1.tls=true",,
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}1.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}1.middlewares=authelia@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "port1"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
// resources {
|
||||
// cpu = 40 # MHz
|
||||
// memory = 10 # MB
|
||||
// }
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
group "TEMPLATE-app-group" {
|
||||
|
||||
restart {
|
||||
attempts = 1
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port2" {
|
||||
static = "443"
|
||||
to = "443"
|
||||
}
|
||||
}
|
||||
|
||||
task "await-TEMPLATEdb" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
args = ["-c", "echo -n 'Waiting for service'; until nslookup ${NOMAD_JOB_NAME}1.service.consul 2>&1 >/dev/null; do echo '.'; sleep 2; done"]
|
||||
network_mode = "host"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 200
|
||||
memory = 128
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task
|
||||
|
||||
task "TEMPLATE" {
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
// env {
|
||||
// PUID = "${meta.PUID}"
|
||||
// PGID = "${meta.PGID}"
|
||||
// TZ = "America/New_York"
|
||||
// }
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = ""
|
||||
hostname = "${NOMAD_TASK_NAME}"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/${NOMAD_TASK_NAME}:/data",
|
||||
"/etc/timezone:/etc/timezone:ro",
|
||||
"/etc/localtime:/etc/localtime:ro"
|
||||
]
|
||||
ports = ["port2"]
|
||||
}
|
||||
|
||||
service {
|
||||
name = "${NOMAD_TASK_NAME}"
|
||||
port = "port2"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.rule=Host(`${NOMAD_TASK_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.service=${NOMAD_TASK_NAME}",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls=true",,
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.middlewares=authelia@file"
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.priority=1"
|
||||
]
|
||||
check {
|
||||
type = "http"
|
||||
port = "port2"
|
||||
path = "/"
|
||||
interval = "5m"
|
||||
timeout = "1m"
|
||||
}
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
// resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 300 # MB
|
||||
// }
|
||||
} // TASK
|
||||
} // close group
|
||||
} // job
|
||||
95
templates/nomad_jobs/template-simple.hcl
Normal file
95
templates/nomad_jobs/template-simple.hcl
Normal file
@@ -0,0 +1,95 @@
|
||||
job "TEMPLATE" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "TEMPLATE" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port1" {
|
||||
static = "80"
|
||||
to = "80"
|
||||
}
|
||||
}
|
||||
|
||||
task "TEMPLATE" {
|
||||
|
||||
// env {
|
||||
// PUID = "${meta.PUID}"
|
||||
// PGID = "${meta.PGID}"
|
||||
// }
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = ""
|
||||
hostname = "${NOMAD_TASK_NAME}"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/${NOMAD_TASK_NAME}:/etc/TEMPLATE/",
|
||||
"/etc/timezone:/etc/timezone:ro",
|
||||
"/etc/localtime:/etc/localtime:ro"
|
||||
]
|
||||
ports = ["port1"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "port1"
|
||||
name = "${NOMAD_TASK_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.service=${NOMAD_TASK_NAME}",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.middlewares=authelia@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "port1"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
// resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 300 # MB
|
||||
// } // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
128
templates/nomad_jobs/template_localfs.hcl
Normal file
128
templates/nomad_jobs/template_localfs.hcl
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
job "TEMPLATE" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi4"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "TEMPLATE-group" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "10m"
|
||||
}
|
||||
|
||||
network {
|
||||
port "port1" {
|
||||
static = ""
|
||||
to = ""
|
||||
}
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = ["${meta.restoreCommand1}", "${meta.restoreCommand2}", "${NOMAD_JOB_NAME}", "${meta.restoreCommand3}"]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "TEMPLATE" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = ""
|
||||
hostname = "${NOMAD_TASK_NAME}"
|
||||
ports = ["port1"]
|
||||
volumes = [
|
||||
"${meta.localStorageRoot}/${NOMAD_TASK_NAME}:/config"
|
||||
]
|
||||
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "port1"
|
||||
name = "${NOMAD_TASK_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.service=${NOMAD_TASK_NAME}",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.tls.certresolver=cloudflare",
|
||||
"traefik.http.routers.${NOMAD_TASK_NAME}.middlewares=authelia@file"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "port1"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 1000 # MHz
|
||||
memory = 400 # MB
|
||||
} // resources
|
||||
|
||||
} // /task ${NOMAD_JOB_NAME}
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupAllocArg1}", "${meta.backupAllocArg2}", "${meta.backupAllocArg3}", "${meta.backupAllocArg4}", "${meta.backupAllocArg5}", "${NOMAD_JOB_NAME}", "${meta.backupAllocArg6}"]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
27
templates/nomad_jobs/testing/execTest.hcl
Normal file
27
templates/nomad_jobs/testing/execTest.hcl
Normal file
@@ -0,0 +1,27 @@
|
||||
job "execTest" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "batch"
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
operator = "regexp"
|
||||
value = "rpi3"
|
||||
}
|
||||
|
||||
group "testing" {
|
||||
|
||||
task "execTest" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
command = "/usr/local/bin/backup_configs"
|
||||
args = ["--verbose","--job","sonarr"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 500
|
||||
memory = 256
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
templates/nomad_jobs/uptimekuma.hcl
Normal file
110
templates/nomad_jobs/uptimekuma.hcl
Normal file
@@ -0,0 +1,110 @@
|
||||
job "uptimekuma" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "uptimekumaGroup" {
|
||||
|
||||
count = 1
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "web" {
|
||||
to = "3001"
|
||||
}
|
||||
}
|
||||
|
||||
task "create_filesystem" {
|
||||
// Copy the most recent backup into place on the local computer. sonarr will not work with
|
||||
// its database in an NFS share
|
||||
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.restoreCommand}"
|
||||
args = ["${meta.restoreCommand1}", "${meta.restoreCommand2}", "${NOMAD_JOB_NAME}", "${meta.restoreCommand3}"]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
} // /task create_filesystem
|
||||
|
||||
task "uptimekuma" {
|
||||
|
||||
// env {
|
||||
// PUID = "${meta.PUID}"
|
||||
// PGID = "${meta.PGID}"
|
||||
// }
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "louislam/uptime-kuma:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
volumes = [ "${meta.localStorageRoot}/uptimekuma:/app/data" ]
|
||||
ports = ["web"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "web"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`uptime.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "web"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
resources {
|
||||
cpu = 400 # MHz
|
||||
memory = 100 # MB
|
||||
} // resources
|
||||
|
||||
} // task
|
||||
|
||||
task "save_configuration" {
|
||||
driver = "raw_exec"
|
||||
config {
|
||||
# When running a binary that exists on the host, the path must be absolute
|
||||
command = "${meta.backupCommand}"
|
||||
args = ["${meta.backupAllocArg1}", "${meta.backupAllocArg2}", "${meta.backupAllocArg3}", "${meta.backupAllocArg4}", "${meta.backupAllocArg5}", "${NOMAD_JOB_NAME}", "${meta.backupAllocArg6}"]
|
||||
}
|
||||
lifecycle {
|
||||
hook = "poststop"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task save_configuration
|
||||
} // group
|
||||
} // job
|
||||
95
templates/nomad_jobs/whoogle.hcl
Normal file
95
templates/nomad_jobs/whoogle.hcl
Normal file
@@ -0,0 +1,95 @@
|
||||
job "whoogle" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
// constraint {
|
||||
// attribute = "${node.unique.name}"
|
||||
// operator = "regexp"
|
||||
// value = "rpi(1|2|3)"
|
||||
// }
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "whoogle" {
|
||||
|
||||
restart {
|
||||
attempts = 0
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "whoogle" {
|
||||
to = "5000"
|
||||
}
|
||||
}
|
||||
|
||||
task "whoogle" {
|
||||
|
||||
env {
|
||||
WHOOGLE_CONFIG_BLOCK = "pinterest.com"
|
||||
WHOOGLE_CONFIG_DISABLE = "1"
|
||||
WHOOGLE_CONFIG_GET_ONLY = "1"
|
||||
WHOOGLE_CONFIG_LANGUAGE = "lang_en"
|
||||
WHOOGLE_CONFIG_NEW_TAB = "0"
|
||||
WHOOGLE_CONFIG_SEARCH_LANGUAGE = "lang_en"
|
||||
WHOOGLE_CONFIG_THEME = "light"
|
||||
WHOOGLE_CONFIG_URL = "https://${NOMAD_JOB_NAME}.{{ homelab_domain_name }}"
|
||||
WHOOGLE_CONFIG_VIEW_IMAGE = "1"
|
||||
WHOOGLE_RESULTS_PER_PAGE = "20"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "benbusby/whoogle-search:latest"
|
||||
hostname = "${NOMAD_JOB_NAME}"
|
||||
ports = ["whoogle"]
|
||||
} // docker config
|
||||
|
||||
service {
|
||||
port = "whoogle"
|
||||
name = "${NOMAD_JOB_NAME}"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.rule=Host(`${NOMAD_JOB_NAME}.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.entryPoints=web,websecure",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.service=${NOMAD_JOB_NAME}",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls=true",
|
||||
"traefik.http.routers.${NOMAD_JOB_NAME}.tls.certresolver=cloudflare"
|
||||
]
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
|
||||
check_restart {
|
||||
limit = 0
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // service
|
||||
|
||||
// resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 300 # MB
|
||||
// } // resources
|
||||
|
||||
} // task
|
||||
|
||||
|
||||
} // group
|
||||
|
||||
|
||||
} // job
|
||||
257
templates/nomad_jobs/wikijs.hcl
Normal file
257
templates/nomad_jobs/wikijs.hcl
Normal file
@@ -0,0 +1,257 @@
|
||||
job "wikijs" {
|
||||
region = "global"
|
||||
datacenters = ["{{ datacenter_name }}"]
|
||||
type = "service"
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
health_check = "checks"
|
||||
min_healthy_time = "10s"
|
||||
healthy_deadline = "5m"
|
||||
progress_deadline = "10m"
|
||||
auto_revert = true
|
||||
canary = 0
|
||||
stagger = "30s"
|
||||
}
|
||||
|
||||
group "wikijs_db_group" {
|
||||
|
||||
restart {
|
||||
attempts = 1
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "db" {
|
||||
static = "5434"
|
||||
to = "5432"
|
||||
}
|
||||
}
|
||||
|
||||
task "await_db_filesytem" {
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
value = "macmini"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
args = [
|
||||
"-c",
|
||||
"echo -n 'Waiting for /etc/postgresql/postgresql.conf to be available'; until [ -f /etc/postgresql/my-postgres.conf ]; do echo '.'; sleep 2; done",
|
||||
]
|
||||
network_mode = "host"
|
||||
volumes = [
|
||||
"/Users/{{ my_username }}/cluster/wikidb:/etc/postgresql"
|
||||
]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task
|
||||
|
||||
task "await_backup_filesytem" {
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
value = "macmini"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
args = [
|
||||
"-c",
|
||||
"echo -n 'Waiting for /backups to be available'; until [ -f /backups/dbBackup.log ]; do echo '.'; sleep 2; done",
|
||||
]
|
||||
network_mode = "host"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/backups/wikijsdb:/backups"
|
||||
]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task
|
||||
|
||||
task "wikijs_db" {
|
||||
|
||||
constraint {
|
||||
attribute = "${node.unique.name}"
|
||||
value = "macmini"
|
||||
}
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
POSTGRES_USER = "wikijs"
|
||||
POSTGRES_PASSWORD = "wikijs"
|
||||
POSTGRES_DB = "wikijs"
|
||||
PGDATA = "/var/lib/postgresql/data/pgdata"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "postgres:9.6.17"
|
||||
hostname = "wikijs_db"
|
||||
volumes = [
|
||||
"/Users/{{ my_username }}/cluster/wikidb/pgdata:/var/lib/postgresql/data",
|
||||
"/Users/{{ my_username }}/cluster/wikidb/my-postgres.conf:/etc/postgresql/postgresql.conf",
|
||||
"/Users/{{ my_username }}/cluster/wikidb/entrypoint:/docker-entrypoint-initdb.d",
|
||||
"${meta.nfsStorageRoot}/pi-cluster/backups/wikijsdb:/backups"
|
||||
]
|
||||
ports = ["db"]
|
||||
}
|
||||
|
||||
artifact {
|
||||
source = "git::https://github.com/{{ my_username }}/db_scripts.git"
|
||||
destination = "local/scripts"
|
||||
}
|
||||
|
||||
service {
|
||||
port = "db"
|
||||
name = "wikijsdb"
|
||||
check {
|
||||
type = "tcp"
|
||||
port = "db"
|
||||
interval = "30s"
|
||||
timeout = "4s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 2
|
||||
grace = "1m"
|
||||
ignore_warnings = true
|
||||
}
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 55 # MHz
|
||||
memory = 60 # MB
|
||||
}
|
||||
|
||||
} // /task
|
||||
} // /group
|
||||
|
||||
group "wikijs_app_group" {
|
||||
|
||||
restart {
|
||||
attempts = 1
|
||||
delay = "30s"
|
||||
}
|
||||
|
||||
network {
|
||||
port "http" {
|
||||
to = "3000"
|
||||
}
|
||||
}
|
||||
|
||||
task "await_database" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
args = [
|
||||
"-c",
|
||||
"echo -n 'Waiting for wikijsdb.service.consul to come alive'; until nslookup wikijsdb.service.consul 2>&1 >/dev/null; do echo '.'; sleep 2; done"
|
||||
]
|
||||
network_mode = "host"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 200
|
||||
memory = 128
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task
|
||||
|
||||
task "await_filesytem" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox:latest"
|
||||
command = "sh"
|
||||
args = [
|
||||
"-c",
|
||||
"echo -n 'Waiting for ${meta.nfsStorageRoot}/pi-cluster/wikijs/ to be mounted'; until less -E /wiki/config.yml | grep 'wikijsdb.service.consul' 2>&1 >/dev/null; do echo '.'; sleep 2; done",
|
||||
]
|
||||
network_mode = "host"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/wikijs/config/config.yml:/wiki/config.yml"
|
||||
]
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
} // /task
|
||||
|
||||
task "wikijs_app" {
|
||||
|
||||
env {
|
||||
PUID = "${meta.PUID}"
|
||||
PGID = "${meta.PGID}"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
|
||||
driver = "docker"
|
||||
config {
|
||||
image = "linuxserver/wikijs:version-2.5.170"
|
||||
hostname = "wikijs-app"
|
||||
volumes = [
|
||||
"${meta.nfsStorageRoot}/pi-cluster/wikijs/config/config.yml:/wiki/config.yml",
|
||||
"${meta.nfsStorageRoot}/pi-cluster/wikijs/config:/config",
|
||||
"${meta.nfsStorageRoot}/pi-cluster/wikijs/data/:/data"
|
||||
]
|
||||
ports = ["http"]
|
||||
} // /config
|
||||
|
||||
service {
|
||||
port = "http"
|
||||
name = "wikijs"
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.wikijs.rule=Host(`wiki.{{ homelab_domain_name }}`)",
|
||||
"traefik.http.routers.wikijs.entryPoints=web,websecure",
|
||||
"traefik.http.routers.wikijs.service=wikijs",
|
||||
"traefik.http.routers.wikijs.tls=true"
|
||||
]
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
interval = "90s"
|
||||
timeout = "15s"
|
||||
}
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "30s"
|
||||
ignore_warnings = true
|
||||
}
|
||||
} // /service
|
||||
|
||||
resources {
|
||||
// cpu = 100 # MHz
|
||||
// memory = 60 # MB
|
||||
}
|
||||
|
||||
|
||||
} // /task
|
||||
} // /group
|
||||
|
||||
} // job
|
||||
1233
templates/scripts/service_backups.sh.j2
Executable file
1233
templates/scripts/service_backups.sh.j2
Executable file
File diff suppressed because it is too large
Load Diff
948
templates/scripts/service_restore.sh.j2
Normal file
948
templates/scripts/service_restore.sh.j2
Normal file
@@ -0,0 +1,948 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_mainScript_() {
|
||||
|
||||
_setPATH_ "/bin" "/usr/bin" "/usr/local/bin"
|
||||
|
||||
debug "whoami: $(whoami)"
|
||||
|
||||
if ! _rootAvailable_; then fatal "This script must be run as root"; fi
|
||||
|
||||
if [ -z ${JOB:-} ]; then
|
||||
error "Service name is not set"
|
||||
_safeExit_ 1
|
||||
fi
|
||||
|
||||
JOB_DIR="{{ interpolated_localfs_service_storage }}/${JOB}"
|
||||
debug "JOB_DIR: ${JOB_DIR}" ${LINENO}
|
||||
|
||||
if [ -z ${JOB:-} ] || [ ! -d "${JOB_DIR}" ]; then
|
||||
error "Can not find job directory: ${JOB_DIR}" "${LINENO}"
|
||||
_safeExit_ 1
|
||||
fi
|
||||
|
||||
if [ ! -d "${BACKUP_DIR}" ]; then
|
||||
error "Can not find backup directory: ${BACKUP_DIR}" "${LINENO}"
|
||||
_safeExit_ 1
|
||||
fi
|
||||
|
||||
# Identify the latest backup
|
||||
# shellcheck disable=SC2010
|
||||
MOST_RECENT_BACKUP="$(ls "${BACKUP_DIR}" | grep --color=never "${JOB}" | sort -n -t _ -k 2 | tail -1)"
|
||||
|
||||
if [ -f "${BACKUP_DIR}/${MOST_RECENT_BACKUP}" ]; then
|
||||
debug "Most recent backup: ${MOST_RECENT_BACKUP}"
|
||||
else
|
||||
error "Most recent backup does not exist" "${LINENO}"
|
||||
fi
|
||||
|
||||
# Don't run as root on macOS
|
||||
if [[ $(_detectOS_) == mac ]]; then
|
||||
# Ensure destination directory is clean
|
||||
_execute_ "command rm -rf \"${JOB_DIR:?}\""
|
||||
_execute_ "mkdir \"${JOB_DIR:?}\""
|
||||
|
||||
# Extract the backup
|
||||
if [ ${DRYRUN} == true ]; then
|
||||
dryrun "tar zxvf \"${BACKUP_DIR}/${MOST_RECENT_BACKUP}\" -C \"${JOB_DIR}\""
|
||||
elif tar zxvf "${BACKUP_DIR}/${MOST_RECENT_BACKUP}" -C "${JOB_DIR}"; then
|
||||
info "Restore successful"
|
||||
else
|
||||
error "Restore failed"
|
||||
_safeExit_ 1
|
||||
fi
|
||||
|
||||
# Ensure permissions are correct
|
||||
_execute_ "chown -R {{ ansible_user_uid }}:{{ ansible_user_gid }} \"${JOB_DIR}\""
|
||||
else
|
||||
# Ensure destination directory is clean
|
||||
_execute_ "_runAsRoot_ command rm -rf \"${JOB_DIR:?}\""
|
||||
_execute_ "_runAsRoot_ mkdir \"${JOB_DIR:?}\""
|
||||
|
||||
# Extract the backup
|
||||
if [ ${DRYRUN} == true ]; then
|
||||
dryrun "_runAsRoot_ tar zxvf \"${BACKUP_DIR}/${MOST_RECENT_BACKUP}\" -C \"${JOB_DIR}\""
|
||||
elif _runAsRoot_ tar zxvf "${BACKUP_DIR}/${MOST_RECENT_BACKUP}" -C "${JOB_DIR}"; then
|
||||
info "Restore successful"
|
||||
else
|
||||
error "Restore failed"
|
||||
_safeExit_ 1
|
||||
fi
|
||||
|
||||
# Ensure permissions are correct
|
||||
_execute_ "_runAsRoot_ chown -R {{ ansible_user_uid }}:{{ ansible_user_gid }} \"${JOB_DIR}\""
|
||||
fi
|
||||
|
||||
notice "Restored: ${MOST_RECENT_BACKUP}"
|
||||
}
|
||||
# end _mainScript_
|
||||
|
||||
# ################################## Flags and defaults
|
||||
# Required variables
|
||||
QUIET=false
|
||||
LOGLEVEL=NOTICE
|
||||
VERBOSE=false
|
||||
FORCE=false
|
||||
DRYRUN=false
|
||||
declare -a ARGS=()
|
||||
|
||||
# Script specific
|
||||
MULTIHOST=false
|
||||
BACKUP_DIR="{{ interpolated_nfs_service_storage }}/pi-cluster/backups/config_backups"
|
||||
LOGFILE="{{ interpolated_nfs_service_storage }}/pi-cluster/logs/$(basename "$0").log"
|
||||
|
||||
# ################################## Custom utility functions (Pasted from repository)
|
||||
_execute_() {
|
||||
# DESC:
|
||||
# Executes commands while respecting global DRYRUN, VERBOSE, LOGGING, and QUIET flags
|
||||
# ARGS:
|
||||
# $1 (Required) - The command to be executed. Quotation marks MUST be escaped.
|
||||
# $2 (Optional) - String to display after command is executed
|
||||
# OPTS:
|
||||
# -v Always print output from the execute function to STDOUT
|
||||
# -n Use NOTICE level alerting (default is INFO)
|
||||
# -p Pass a failed command with 'return 0'. This effectively bypasses set -e.
|
||||
# -e Bypass _alert_ functions and use 'echo RESULT'
|
||||
# -s Use '_alert_ success' for successful output. (default is 'info')
|
||||
# -q Do not print output (QUIET mode)
|
||||
# OUTS:
|
||||
# stdout: Configurable output
|
||||
# USE :
|
||||
# _execute_ "cp -R \"~/dir/somefile.txt\" \"someNewFile.txt\"" "Optional message"
|
||||
# _execute_ -sv "mkdir \"some/dir\""
|
||||
# NOTE:
|
||||
# If $DRYRUN=true, no commands are executed and the command that would have been executed
|
||||
# is printed to STDOUT using dryrun level alerting
|
||||
# If $VERBOSE=true, the command's native output is printed to stdout. This can be forced
|
||||
# with '_execute_ -v'
|
||||
|
||||
local _localVerbose=false
|
||||
local _passFailures=false
|
||||
local _echoResult=false
|
||||
local _echoSuccessResult=false
|
||||
local _quietMode=false
|
||||
local _echoNoticeResult=false
|
||||
local opt
|
||||
|
||||
local OPTIND=1
|
||||
while getopts ":vVpPeEsSqQnN" opt; do
|
||||
case $opt in
|
||||
v | V) _localVerbose=true ;;
|
||||
p | P) _passFailures=true ;;
|
||||
e | E) _echoResult=true ;;
|
||||
s | S) _echoSuccessResult=true ;;
|
||||
q | Q) _quietMode=true ;;
|
||||
n | N) _echoNoticeResult=true ;;
|
||||
*)
|
||||
{
|
||||
error "Unrecognized option '$1' passed to _execute_. Exiting."
|
||||
_safeExit_
|
||||
}
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||
|
||||
local _command="${1}"
|
||||
local _executeMessage="${2:-$1}"
|
||||
|
||||
local _saveVerbose=${VERBOSE}
|
||||
if "${_localVerbose}"; then
|
||||
VERBOSE=true
|
||||
fi
|
||||
|
||||
if "${DRYRUN}"; then
|
||||
if "${_quietMode}"; then
|
||||
VERBOSE=${_saveVerbose}
|
||||
return 0
|
||||
fi
|
||||
if [ -n "${2:-}" ]; then
|
||||
dryrun "${1} (${2})" "$(caller)"
|
||||
else
|
||||
dryrun "${1}" "$(caller)"
|
||||
fi
|
||||
elif ${VERBOSE}; then
|
||||
if eval "${_command}"; then
|
||||
if "${_quietMode}"; then
|
||||
VERBOSE=${_saveVerbose}
|
||||
elif "${_echoResult}"; then
|
||||
printf "%s\n" "${_executeMessage}"
|
||||
elif "${_echoSuccessResult}"; then
|
||||
success "${_executeMessage}"
|
||||
elif "${_echoNoticeResult}"; then
|
||||
notice "${_executeMessage}"
|
||||
else
|
||||
info "${_executeMessage}"
|
||||
fi
|
||||
else
|
||||
if "${_quietMode}"; then
|
||||
VERBOSE=${_saveVerbose}
|
||||
elif "${_echoResult}"; then
|
||||
printf "%s\n" "warning: ${_executeMessage}"
|
||||
else
|
||||
warning "${_executeMessage}"
|
||||
fi
|
||||
VERBOSE=${_saveVerbose}
|
||||
"${_passFailures}" && return 0 || return 1
|
||||
fi
|
||||
else
|
||||
if eval "${_command}" >/dev/null 2>&1; then
|
||||
if "${_quietMode}"; then
|
||||
VERBOSE=${_saveVerbose}
|
||||
elif "${_echoResult}"; then
|
||||
printf "%s\n" "${_executeMessage}"
|
||||
elif "${_echoSuccessResult}"; then
|
||||
success "${_executeMessage}"
|
||||
elif "${_echoNoticeResult}"; then
|
||||
notice "${_executeMessage}"
|
||||
else
|
||||
info "${_executeMessage}"
|
||||
fi
|
||||
else
|
||||
if "${_quietMode}"; then
|
||||
VERBOSE=$_saveVerbose
|
||||
elif "${_echoResult}"; then
|
||||
printf "%s\n" "error: ${_executeMessage}"
|
||||
else
|
||||
warning "${_executeMessage}"
|
||||
fi
|
||||
VERBOSE=${_saveVerbose}
|
||||
"${_passFailures}" && return 0 || return 1
|
||||
fi
|
||||
fi
|
||||
VERBOSE=${_saveVerbose}
|
||||
return 0
|
||||
}
|
||||
|
||||
_runAsRoot_() {
|
||||
# DESC:
|
||||
# Run the requested command as root (via sudo if requested)
|
||||
# ARGS:
|
||||
# $1 (optional): Set to zero to not attempt execution via sudo
|
||||
# $@ (required): Passed through for execution as root user
|
||||
# OUTS:
|
||||
# Runs the requested command as root
|
||||
# CREDIT:
|
||||
# https://github.com/ralish/bash-script-template
|
||||
|
||||
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||
|
||||
local _skip_sudo=false
|
||||
|
||||
if [[ ${1} =~ ^0$ ]]; then
|
||||
_skip_sudo=true
|
||||
shift
|
||||
fi
|
||||
|
||||
if [[ ${EUID} -eq 0 ]]; then
|
||||
"$@"
|
||||
elif [[ -z ${_skip_sudo} ]]; then
|
||||
sudo -H -- "$@"
|
||||
else
|
||||
fatal "Unable to run requested command as root: $*"
|
||||
fi
|
||||
}
|
||||
|
||||
_rootAvailable_() {
|
||||
# DESC:
|
||||
# Validate we have superuser access as root (via sudo if requested)
|
||||
# ARGS:
|
||||
# $1 (optional): Set to any value to not attempt root access via sudo
|
||||
# OUTS:
|
||||
# 0 if true
|
||||
# 1 if false
|
||||
# CREDIT:
|
||||
# https://github.com/ralish/bash-script-template
|
||||
|
||||
local _superuser
|
||||
local _testEUID
|
||||
if [[ ${EUID} -eq 0 ]]; then
|
||||
_superuser=true
|
||||
elif [[ -z ${1:-} ]]; then
|
||||
debug 'Sudo: Updating cached credentials ...'
|
||||
if sudo -v; then
|
||||
if [[ $(sudo -H -- "$BASH" -c 'printf "%s" "$EUID"') -eq 0 ]]; then
|
||||
_superuser=true
|
||||
else
|
||||
_superuser=false
|
||||
fi
|
||||
else
|
||||
_superuser=false
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${_superuser} == true ]]; then
|
||||
debug 'Successfully acquired superuser credentials.'
|
||||
return 0
|
||||
else
|
||||
debug 'Unable to acquire superuser credentials.'
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_detectOS_() {
|
||||
# DESC:
|
||||
# Identify the OS the script is run on
|
||||
# ARGS:
|
||||
# None
|
||||
# OUTS:
|
||||
# 0 - Success
|
||||
# 1 - Failed to detect OS
|
||||
# stdout: One of 'mac', 'linux', 'windows'
|
||||
# USAGE:
|
||||
# _detectOS_
|
||||
# CREDIT:
|
||||
# https://github.com/labbots/bash-utility
|
||||
|
||||
local _uname
|
||||
local _os
|
||||
if _uname=$(command -v uname); then
|
||||
case $("${_uname}" | tr '[:upper:]' '[:lower:]') in
|
||||
linux*)
|
||||
_os="linux"
|
||||
;;
|
||||
darwin*)
|
||||
_os="mac"
|
||||
;;
|
||||
msys* | cygwin* | mingw* | nt | win*)
|
||||
# or possible 'bash on windows'
|
||||
_os="windows"
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
printf "%s" "${_os}"
|
||||
|
||||
}
|
||||
# ################################## Functions required for this template to work
|
||||
|
||||
# Functions for providing alerts to the user and printing them to the log
|
||||
|
||||
_setColors_() {
|
||||
# DESC:
|
||||
# Sets colors use for alerts.
|
||||
# ARGS:
|
||||
# None
|
||||
# OUTS:
|
||||
# None
|
||||
# USAGE:
|
||||
# echo "${blue}Some text${reset}"
|
||||
|
||||
if tput setaf 1 >/dev/null 2>&1; then
|
||||
bold=$(tput bold)
|
||||
underline=$(tput smul)
|
||||
reverse=$(tput rev)
|
||||
reset=$(tput sgr0)
|
||||
|
||||
if [[ $(tput colors) -ge 256 ]] >/dev/null 2>&1; then
|
||||
white=$(tput setaf 231)
|
||||
blue=$(tput setaf 38)
|
||||
yellow=$(tput setaf 11)
|
||||
tan=$(tput setaf 3)
|
||||
green=$(tput setaf 82)
|
||||
red=$(tput setaf 1)
|
||||
purple=$(tput setaf 171)
|
||||
gray=$(tput setaf 250)
|
||||
else
|
||||
white=$(tput setaf 7)
|
||||
blue=$(tput setaf 38)
|
||||
yellow=$(tput setaf 3)
|
||||
tan=$(tput setaf 3)
|
||||
green=$(tput setaf 2)
|
||||
red=$(tput setaf 1)
|
||||
purple=$(tput setaf 13)
|
||||
gray=$(tput setaf 7)
|
||||
fi
|
||||
else
|
||||
bold="\033[4;37m"
|
||||
reset="\033[0m"
|
||||
underline="\033[4;37m"
|
||||
reverse=""
|
||||
white="\033[0;37m"
|
||||
blue="\033[0;34m"
|
||||
yellow="\033[0;33m"
|
||||
tan="\033[0;33m"
|
||||
green="\033[1;32m"
|
||||
red="\033[0;31m"
|
||||
purple="\033[0;35m"
|
||||
gray="\033[0;37m"
|
||||
fi
|
||||
}
|
||||
|
||||
_alert_() {
|
||||
# DESC:
|
||||
# Controls all printing of messages to log files and stdout.
|
||||
# ARGS:
|
||||
# $1 (required) - The type of alert to print
|
||||
# (success, header, notice, dryrun, debug, warning, error,
|
||||
# fatal, info, input)
|
||||
# $2 (required) - The message to be printed to stdout and/or a log file
|
||||
# $3 (optional) - Pass '${LINENO}' to print the line number where the _alert_ was triggered
|
||||
# OUTS:
|
||||
# stdout: The message is printed to stdout
|
||||
# log file: The message is printed to a log file
|
||||
# USAGE:
|
||||
# [_alertType] "[MESSAGE]" "${LINENO}"
|
||||
# NOTES:
|
||||
# - The colors of each alert type are set in this function
|
||||
# - For specified alert types, the funcstac will be printed
|
||||
|
||||
local _color
|
||||
local _alertType="${1}"
|
||||
local _message="${2}"
|
||||
local _line="${3:-}" # Optional line number
|
||||
|
||||
[[ $# -lt 2 ]] && fatal 'Missing required argument to _alert_'
|
||||
|
||||
if [[ -n ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||
_message="${_message} ${gray}(line: ${_line}) $(_printFuncStack_)"
|
||||
elif [[ -n ${_line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||
_message="${_message} ${gray}(line: ${_line})"
|
||||
elif [[ -z ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||
_message="${_message} ${gray}$(_printFuncStack_)"
|
||||
fi
|
||||
|
||||
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||
_color="${bold}${red}"
|
||||
elif [ "${_alertType}" == "info" ]; then
|
||||
_color="${gray}"
|
||||
elif [ "${_alertType}" == "warning" ]; then
|
||||
_color="${red}"
|
||||
elif [ "${_alertType}" == "success" ]; then
|
||||
_color="${green}"
|
||||
elif [ "${_alertType}" == "debug" ]; then
|
||||
_color="${purple}"
|
||||
elif [ "${_alertType}" == "header" ]; then
|
||||
_color="${bold}${white}${underline}"
|
||||
elif [ ${_alertType} == "notice" ]; then
|
||||
_color="${bold}"
|
||||
elif [ ${_alertType} == "input" ]; then
|
||||
_color="${bold}${underline}"
|
||||
elif [ "${_alertType}" = "dryrun" ]; then
|
||||
_color="${blue}"
|
||||
else
|
||||
_color=""
|
||||
fi
|
||||
|
||||
_writeToScreen_() {
|
||||
("${QUIET}") && return 0 # Print to console when script is not 'quiet'
|
||||
[[ ${VERBOSE} == false && ${_alertType} =~ ^(debug|verbose) ]] && return 0
|
||||
|
||||
if ! [[ -t 1 || -z ${TERM:-} ]]; then # Don't use colors on non-recognized terminals
|
||||
_color=""
|
||||
reset=""
|
||||
fi
|
||||
|
||||
if [[ ${_alertType} == header ]]; then
|
||||
printf "${_color}%s${reset}\n" "${_message}"
|
||||
else
|
||||
printf "${_color}[%7s] %s${reset}\n" "${_alertType}" "${_message}"
|
||||
fi
|
||||
}
|
||||
_writeToScreen_
|
||||
|
||||
_writeToLog_() {
|
||||
[[ ${_alertType} == "input" ]] && return 0
|
||||
[[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0
|
||||
if [ -z "${LOGFILE:-}" ]; then
|
||||
LOGFILE="$(pwd)/$(basename "$0").log"
|
||||
fi
|
||||
[ ! -d "$(dirname "${LOGFILE}")" ] && mkdir -p "$(dirname "${LOGFILE}")"
|
||||
[[ ! -f ${LOGFILE} ]] && touch "${LOGFILE}"
|
||||
|
||||
# Don't use colors in logs
|
||||
local cleanmessage="$(echo "${_message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
|
||||
# Print message to log file
|
||||
printf "%s [%7s] %s %s\n" "$(date +"%b %d %R:%S")" "${_alertType}" "[$(/bin/hostname)]" "${cleanmessage}" >>"${LOGFILE}"
|
||||
}
|
||||
|
||||
# Write specified log level data to logfile
|
||||
case "${LOGLEVEL:-ERROR}" in
|
||||
ALL | all | All)
|
||||
_writeToLog_
|
||||
;;
|
||||
DEBUG | debug | Debug)
|
||||
_writeToLog_
|
||||
;;
|
||||
INFO | info | Info)
|
||||
if [[ ${_alertType} =~ ^(error|fatal|warning|info|notice|success) ]]; then
|
||||
_writeToLog_
|
||||
fi
|
||||
;;
|
||||
NOTICE | notice | Notice)
|
||||
if [[ ${_alertType} =~ ^(error|fatal|warning|notice|success) ]]; then
|
||||
_writeToLog_
|
||||
fi
|
||||
;;
|
||||
WARN | warn | Warn)
|
||||
if [[ ${_alertType} =~ ^(error|fatal|warning) ]]; then
|
||||
_writeToLog_
|
||||
fi
|
||||
;;
|
||||
ERROR | error | Error)
|
||||
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||
_writeToLog_
|
||||
fi
|
||||
;;
|
||||
FATAL | fatal | Fatal)
|
||||
if [[ ${_alertType} =~ ^fatal ]]; then
|
||||
_writeToLog_
|
||||
fi
|
||||
;;
|
||||
OFF | off)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||
_writeToLog_
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
} # /_alert_
|
||||
|
||||
error() { _alert_ error "${1}" "${2:-}"; }
|
||||
warning() { _alert_ warning "${1}" "${2:-}"; }
|
||||
notice() { _alert_ notice "${1}" "${2:-}"; }
|
||||
info() { _alert_ info "${1}" "${2:-}"; }
|
||||
success() { _alert_ success "${1}" "${2:-}"; }
|
||||
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
||||
input() { _alert_ input "${1}" "${2:-}"; }
|
||||
header() { _alert_ header "${1}" "${2:-}"; }
|
||||
debug() { _alert_ debug "${1}" "${2:-}"; }
|
||||
fatal() {
|
||||
_alert_ fatal "${1}" "${2:-}"
|
||||
_safeExit_ "1"
|
||||
}
|
||||
|
||||
# shellcheck disable=SC1009,SC1054,SC1056,SC1072,SC1073,SC1083
|
||||
{% raw %}
|
||||
_printFuncStack_() {
|
||||
# DESC:
|
||||
# Prints the function stack in use. Used for debugging, and error reporting.
|
||||
# ARGS:
|
||||
# None
|
||||
# OUTS:
|
||||
# stdout: Prints [function]:[file]:[line]
|
||||
# NOTE:
|
||||
# Does not print functions from the alert class
|
||||
local _i
|
||||
_funcStackResponse=()
|
||||
for ((_i = 1; _i < ${#BASH_SOURCE[@]}; _i++)); do
|
||||
case "${FUNCNAME[$_i]}" in "_alert_" | "_trapCleanup_" | fatal | error | warning | notice | info | debug | dryrun | header | success) continue ;; esac
|
||||
_funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
|
||||
done
|
||||
printf "( "
|
||||
printf %s "${_funcStackResponse[0]}"
|
||||
printf ' < %s' "${_funcStackResponse[@]:1}"
|
||||
printf ' )\n'
|
||||
}
|
||||
{% endraw %}
|
||||
|
||||
_safeExit_() {
|
||||
# DESC:
|
||||
# Cleanup and exit from a script
|
||||
# ARGS:
|
||||
# $1 (optional) - Exit code (defaults to 0)
|
||||
# OUTS:
|
||||
# None
|
||||
|
||||
if [[ -d ${SCRIPT_LOCK:-} ]]; then
|
||||
if command rm -rf "${SCRIPT_LOCK}"; then
|
||||
debug "Removing script lock"
|
||||
else
|
||||
warning "Script lock could not be removed. Try manually deleting ${tan}'${LOCK_DIR}'"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
|
||||
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
||||
command rm -r "${TMP_DIR}"
|
||||
else
|
||||
command rm -r "${TMP_DIR}"
|
||||
debug "Removing temp directory"
|
||||
fi
|
||||
fi
|
||||
|
||||
trap - INT TERM EXIT
|
||||
exit ${1:-0}
|
||||
}
|
||||
|
||||
_trapCleanup_() {
|
||||
# DESC:
|
||||
# Log errors and cleanup from script when an error is trapped. Called by 'trap'
|
||||
# ARGS:
|
||||
# $1: Line number where error was trapped
|
||||
# $2: Line number in function
|
||||
# $3: Command executing at the time of the trap
|
||||
# $4: Names of all shell functions currently in the execution call stack
|
||||
# $5: Scriptname
|
||||
# $6: $BASH_SOURCE
|
||||
# USAGE:
|
||||
# trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM
|
||||
# OUTS:
|
||||
# Exits script with error code 1
|
||||
|
||||
local _line=${1:-} # LINENO
|
||||
local _linecallfunc=${2:-}
|
||||
local _command="${3:-}"
|
||||
local _funcstack="${4:-}"
|
||||
local _script="${5:-}"
|
||||
local _sourced="${6:-}"
|
||||
|
||||
if [[ "$(declare -f "fatal")" && "$(declare -f "_printFuncStack_")" ]]; then
|
||||
_funcstack="'$(echo "${_funcstack}" | sed -E 's/ / < /g')'"
|
||||
if [[ ${_script##*/} == "${_sourced##*/}" ]]; then
|
||||
fatal "${7:-} command: '${_command}' (line: ${_line}) [func: $(_printFuncStack_)]"
|
||||
else
|
||||
fatal "${7:-} command: '${_command}' (func: ${_funcstack} called at line ${_linecallfunc} of '${_script##*/}') (line: ${_line} of '${_sourced##*/}') "
|
||||
fi
|
||||
else
|
||||
printf "%s\n" "Fatal error trapped. Exiting..."
|
||||
fi
|
||||
|
||||
if [ "$(declare -f "_safeExit_")" ]; then
|
||||
_safeExit_ 1
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
_makeTempDir_() {
|
||||
# DESC:
|
||||
# Creates a temp directory to house temporary files
|
||||
# ARGS:
|
||||
# $1 (Optional) - First characters/word of directory name
|
||||
# OUTS:
|
||||
# Sets $TMP_DIR variable to the path of the temp directory
|
||||
# USAGE:
|
||||
# _makeTempDir_ "$(basename "$0")"
|
||||
|
||||
[ -d "${TMP_DIR:-}" ] && return 0
|
||||
|
||||
if [ -n "${1:-}" ]; then
|
||||
TMP_DIR="${TMPDIR:-/tmp/}${1}.${RANDOM}.${RANDOM}.$$"
|
||||
else
|
||||
TMP_DIR="${TMPDIR:-/tmp/}$(basename "$0").${RANDOM}.${RANDOM}.${RANDOM}.$$"
|
||||
fi
|
||||
(umask 077 && mkdir "${TMP_DIR}") || {
|
||||
fatal "Could not create temporary directory! Exiting."
|
||||
}
|
||||
debug "\$TMP_DIR=${TMP_DIR}"
|
||||
}
|
||||
|
||||
_acquireScriptLock_() {
|
||||
# DESC:
|
||||
# Acquire script lock to prevent running the same script a second time before the
|
||||
# first instance exits
|
||||
# ARGS:
|
||||
# $1 (optional) - Scope of script execution lock (system or user)
|
||||
# OUTS:
|
||||
# exports $SCRIPT_LOCK - Path to the directory indicating we have the script lock
|
||||
# Exits script if lock cannot be acquired
|
||||
# NOTE:
|
||||
# If the lock was acquired it's automatically released in _safeExit_()
|
||||
|
||||
local _lockDir
|
||||
if [[ ${1:-} == 'system' ]]; then
|
||||
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
|
||||
else
|
||||
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
|
||||
fi
|
||||
|
||||
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
|
||||
readonly SCRIPT_LOCK="${_lockDir}"
|
||||
debug "Acquired script lock: ${yellow}${SCRIPT_LOCK}${purple}"
|
||||
else
|
||||
if [ "$(declare -f "_safeExit_")" ]; then
|
||||
error "Unable to acquire script lock: ${tan}${LOCK_DIR}${red}"
|
||||
fatal "If you trust the script isn't running, delete the lock dir"
|
||||
else
|
||||
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${LOCK_DIR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
_setPATH_() {
|
||||
# DESC:
|
||||
# Add directories to $PATH so script can find executables
|
||||
# ARGS:
|
||||
# $@ - One or more paths
|
||||
# OUTS: Adds items to $PATH
|
||||
# USAGE:
|
||||
# _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)"
|
||||
|
||||
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||
|
||||
local _newPath
|
||||
|
||||
for _newPath in "$@"; do
|
||||
if [ -d "${_newPath}" ]; then
|
||||
if ! echo "${PATH}" | grep -Eq "(^|:)${_newPath}($|:)"; then
|
||||
if PATH="${_newPath}:${PATH}"; then
|
||||
debug "Added '${_newPath}' to PATH"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
debug "_setPATH_: '${_newPath}' already exists in PATH"
|
||||
fi
|
||||
else
|
||||
debug "_setPATH_: can not find: ${_newPath}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
_useGNUutils_() {
|
||||
# DESC:
|
||||
# Add GNU utilities to PATH to allow consistent use of sed/grep/tar/etc. on MacOS
|
||||
# ARGS:
|
||||
# None
|
||||
# OUTS:
|
||||
# 0 if successful
|
||||
# 1 if unsuccessful
|
||||
# PATH: Adds GNU utilities to the path
|
||||
# USAGE:
|
||||
# # if ! _useGNUUtils_; then exit 1; fi
|
||||
# NOTES:
|
||||
# GNU utilities can be added to MacOS using Homebrew
|
||||
|
||||
! declare -f "_setPATH_" &>/dev/null && fatal "${FUNCNAME[0]} needs function _setPATH_"
|
||||
|
||||
if _setPATH_ \
|
||||
"/usr/local/opt/gnu-tar/libexec/gnubin" \
|
||||
"/usr/local/opt/coreutils/libexec/gnubin" \
|
||||
"/usr/local/opt/gnu-sed/libexec/gnubin" \
|
||||
"/usr/local/opt/grep/libexec/gnubin" \
|
||||
"/usr/local/opt/findutils/libexec/gnubin" \
|
||||
"/opt/homebrew/opt/findutils/libexec/gnubin" \
|
||||
"/opt/homebrew/opt/gnu-sed/libexec/gnubin" \
|
||||
"/opt/homebrew/opt/grep/libexec/gnubin" \
|
||||
"/opt/homebrew/opt/coreutils/libexec/gnubin" \
|
||||
"/opt/homebrew/opt/gnu-tar/libexec/gnubin"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
_homebrewPath_() {
|
||||
# DESC:
|
||||
# Add homebrew bin dir to PATH
|
||||
# ARGS:
|
||||
# None
|
||||
# OUTS:
|
||||
# 0 if successful
|
||||
# 1 if unsuccessful
|
||||
# PATH: Adds homebrew bin directory to PATH
|
||||
# USAGE:
|
||||
# # if ! _homebrewPath_; then exit 1; fi
|
||||
|
||||
! declare -f "_setPATH_" &>/dev/null && fatal "${FUNCNAME[0]} needs function _setPATH_"
|
||||
|
||||
if _uname=$(command -v uname); then
|
||||
if "${_uname}" | tr '[:upper:]' '[:lower:]' | grep -q 'darwin'; then
|
||||
if _setPATH_ "/usr/local/bin" "/opt/homebrew/bin"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if _setPATH_ "/usr/local/bin" "/opt/homebrew/bin"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
{% raw %}
|
||||
_parseOptions_() {
|
||||
# DESC:
|
||||
# Iterates through options passed to script and sets variables. Will break -ab into -a -b
|
||||
# when needed and --foo=bar into --foo bar
|
||||
# ARGS:
|
||||
# $@ from command line
|
||||
# OUTS:
|
||||
# Sets array 'ARGS' containing all arguments passed to script that were not parsed as options
|
||||
# USAGE:
|
||||
# _parseOptions_ "$@"
|
||||
|
||||
# Iterate over options
|
||||
local _optstring=h
|
||||
declare -a _options
|
||||
local _c
|
||||
local i
|
||||
while (($#)); do
|
||||
case $1 in
|
||||
# If option is of type -ab
|
||||
-[!-]?*)
|
||||
# Loop over each character starting with the second
|
||||
for ((i = 1; i < ${#1}; i++)); do
|
||||
_c=${1:i:1}
|
||||
_options+=("-${_c}") # Add current char to options
|
||||
# If option takes a required argument, and it's not the last char make
|
||||
# the rest of the string its argument
|
||||
if [[ ${_optstring} == *"${_c}:"* && ${1:i+1} ]]; then
|
||||
_options+=("${1:i+1}")
|
||||
break
|
||||
fi
|
||||
done
|
||||
;;
|
||||
# If option is of type --foo=bar
|
||||
--?*=*) _options+=("${1%%=*}" "${1#*=}") ;;
|
||||
# add --endopts for --
|
||||
--) _options+=(--endopts) ;;
|
||||
# Otherwise, nothing special
|
||||
*) _options+=("$1") ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
set -- "${_options[@]:-}"
|
||||
unset _options
|
||||
|
||||
# Read the options and set stuff
|
||||
while [[ ${1:-} == -?* ]]; do
|
||||
case $1 in
|
||||
# Custom options
|
||||
--job)
|
||||
shift
|
||||
JOB="$1"
|
||||
;;
|
||||
|
||||
# Common options
|
||||
-h | --help)
|
||||
_usage_
|
||||
_safeExit_
|
||||
;;
|
||||
--loglevel)
|
||||
shift
|
||||
LOGLEVEL=${1}
|
||||
;;
|
||||
--logfile)
|
||||
shift
|
||||
LOGFILE="${1}"
|
||||
;;
|
||||
-n | --dryrun) DRYRUN=true ;;
|
||||
-v | --verbose) VERBOSE=true ;;
|
||||
-q | --quiet) QUIET=true ;;
|
||||
--force) FORCE=true ;;
|
||||
--endopts)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
if [ "$(declare -f "_safeExit_")" ]; then
|
||||
fatal "invalid option: $1"
|
||||
else
|
||||
printf "%s\n" "Invalid option: $1"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ -z ${*} || ${*} == null ]]; then
|
||||
ARGS=()
|
||||
else
|
||||
ARGS+=("$@") # Store the remaining user input as arguments.
|
||||
fi
|
||||
}
|
||||
{% endraw %}
|
||||
|
||||
_usage_() {
|
||||
cat <<USAGE_TEXT
|
||||
|
||||
Restores the most recent backup of a service to a target directory on the host. It is assumed
|
||||
that the destination directory is already mounted on the host and available at: {{ interpolated_nfs_service_storage }}/[service name]
|
||||
|
||||
${bold}Options:${reset}
|
||||
--job [service name] Name of the service to restore
|
||||
|
||||
-h, --help Display this help and exit
|
||||
--loglevel [LEVEL] One of: FATAL, ERROR, WARN, INFO, NOTICE, DEBUG, ALL, OFF
|
||||
(Default is 'ERROR')
|
||||
--logfile [FILE] Full PATH to logfile. (Default is '${HOME}/logs/$(basename "$0").log')
|
||||
-n, --dryrun Non-destructive. Makes no permanent changes.
|
||||
-q, --quiet Quiet (no output)
|
||||
-v, --verbose Output more information. (Items echoed to 'verbose')
|
||||
--force Skip all user interaction. Implied 'Yes' to all actions.
|
||||
|
||||
${bold}Example Usage:${reset}
|
||||
|
||||
${gray}# Run the script and specify log level and log file.${reset}
|
||||
$(basename "$0") -vn --logfile "/path/to/file.log" --loglevel 'WARN'
|
||||
USAGE_TEXT
|
||||
}
|
||||
|
||||
# ################################## INITIALIZE AND RUN THE SCRIPT
|
||||
# (Comment or uncomment the lines below to customize script behavior)
|
||||
|
||||
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM
|
||||
|
||||
# Trap errors in subshells and functions
|
||||
set -o errtrace
|
||||
|
||||
# Exit on error. Append '||true' if you expect an error
|
||||
set -o errexit
|
||||
|
||||
# Use last non-zero exit code in a pipeline
|
||||
set -o pipefail
|
||||
|
||||
# Confirm we have BASH greater than v4
|
||||
[ "${BASH_VERSINFO:-0}" -ge 4 ] || {
|
||||
printf "%s\n" "ERROR: BASH_VERSINFO is '${BASH_VERSINFO:-0}'. This script requires BASH v4 or greater."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Make `for f in *.txt` work when `*.txt` matches zero files
|
||||
shopt -s nullglob globstar
|
||||
|
||||
# Set IFS to preferred implementation
|
||||
IFS=$' \n\t'
|
||||
|
||||
# Run in debug mode
|
||||
# set -o xtrace
|
||||
|
||||
# Initialize color constants
|
||||
_setColors_
|
||||
|
||||
# Disallow expansion of unset variables
|
||||
set -o nounset
|
||||
|
||||
# Force arguments when invoking the script
|
||||
# [[ $# -eq 0 ]] && _parseOptions_ "-h"
|
||||
|
||||
# Parse arguments passed to script
|
||||
_parseOptions_ "$@"
|
||||
|
||||
# Create a temp directory '$TMP_DIR'
|
||||
# _makeTempDir_ "$(basename "$0")"
|
||||
|
||||
# Acquire script lock
|
||||
# _acquireScriptLock_
|
||||
|
||||
# Add Homebrew bin directory to PATH (MacOS)
|
||||
_homebrewPath_
|
||||
|
||||
# Source GNU utilities from Homebrew (MacOS)
|
||||
_useGNUutils_
|
||||
|
||||
# Run the main logic script
|
||||
_mainScript_
|
||||
|
||||
# Exit cleanly
|
||||
_safeExit_
|
||||
96
templates/telegraf/base_config.conf.j2
Normal file
96
templates/telegraf/base_config.conf.j2
Normal file
@@ -0,0 +1,96 @@
|
||||
# Telegraf Configuration
|
||||
#
|
||||
# Telegraf is entirely plugin driven. All metrics are gathered from the
|
||||
# declared inputs, and sent to the declared outputs.
|
||||
#
|
||||
# Plugins must be declared in here to be active.
|
||||
# To deactivate a plugin, comment out the name and any variables.
|
||||
#
|
||||
# Use 'telegraf -config telegraf.conf -test' to see what metrics a config
|
||||
# file would generate.
|
||||
#
|
||||
# Environment variables can be used anywhere in this config file, simply surround
|
||||
# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"),
|
||||
# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})
|
||||
|
||||
|
||||
# Global tags can be specified here in key="value" format.
|
||||
[global_tags]
|
||||
dc = "{{ datacenter_name }}"
|
||||
ip = "{{ ansible_host }}"
|
||||
|
||||
# Configuration for telegraf agent
|
||||
[agent]
|
||||
|
||||
interval = "10s" ## Default data collection interval for all inputs
|
||||
round_interval = true ## ie, if interval="10s" then always collect on :00, :10, :20, etc.
|
||||
metric_batch_size = 1000 ## Controls the size of writes that Telegraf sends to output plugins
|
||||
metric_buffer_limit = 10000 ## Maximum number of unwritten metrics per output.
|
||||
collection_jitter = "5s" ## Jitter the collection by a random amount.
|
||||
flush_interval = "10s" ## Default flushing interval for all outputs.
|
||||
flush_jitter = "5s" ## Jitter the flush interval by a random amount
|
||||
precision = ""
|
||||
debug = false ## Log at debug level.
|
||||
# quiet = false ## Log only error level messages.
|
||||
{% if 'pis' in group_names %}
|
||||
logtarget = "file" ## destination logs can be one of "file" or "stderr"
|
||||
logfile = "/var/log/telegraf/telegraf.log"
|
||||
logfile_rotation_interval = "1d"
|
||||
# logfile_rotation_max_size = "0MB"
|
||||
logfile_rotation_max_archives = 2
|
||||
{% elif 'macs' in group_names %}
|
||||
logtarget = "stderr" ## destination logs can be one of "file" or "stderr"
|
||||
{% endif %}
|
||||
|
||||
hostname = "{{ inventory_hostname }}" ## Override default hostname, if empty use os.Hostname()
|
||||
omit_hostname = false ## If set to true, do no set the "host" tag in the telegraf agent.
|
||||
|
||||
###############################################################################
|
||||
# OUTPUT PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[outputs.influxdb]]
|
||||
urls = ["http://influxdb.service.consul:{{ influxdb_port }}"]
|
||||
database = "homelab"
|
||||
retention_policy = "2day"
|
||||
timeout = "5s"
|
||||
|
||||
###############################################################################
|
||||
# INPUT PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[inputs.cpu]] # Read metrics about cpu usage
|
||||
percpu = true ## Whether to report per-cpu stats or not
|
||||
totalcpu = true ## Whether to report total system cpu stats or not
|
||||
collect_cpu_time = false ## If true, collect raw CPU time metrics.
|
||||
report_active = false ## If true, compute and report the sum of all non-idle CPU states.
|
||||
[[inputs.disk]] # Read metrics about disk usage by mount point
|
||||
#mount_points = ["/mnt/usbDrive","/boot"] # Restrict the stats to only the specified mount points.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs", "nfsd", "nfs4", "smbfs"]
|
||||
[[inputs.diskio]] # Read metrics about disk IO by device
|
||||
[[inputs.internal]] # Collect telegraf memory stats.
|
||||
collect_memstats = true
|
||||
[[inputs.mem]] # Read metrics about memory usage
|
||||
[[inputs.processes]] # Get the number of processes and group them by status
|
||||
[[inputs.swap]] # Read metrics about swap memory usage
|
||||
[[inputs.system]] # Read metrics about system load & uptime
|
||||
[[inputs.net]] # Gather metrics about network interfaces
|
||||
#[[inputs.netstat]] # Collect TCP connections state and UDP socket counts
|
||||
|
||||
|
||||
{% if 'macs' not in group_names %}
|
||||
[[inputs.nstat]] # Collects network metrics
|
||||
{% endif %}
|
||||
|
||||
{% if 'pis' in group_names%}
|
||||
[[inputs.ntpq]]
|
||||
dns_lookup = false ## If false, add -n for ntpq command. Can reduce metric gather times.
|
||||
{% endif %}
|
||||
|
||||
{% if 'opnsense' in group_names %}
|
||||
[[inputs.ntpq]]
|
||||
dns_lookup = false ## If false, add -n for ntpq command. Can reduce metric gather times.
|
||||
[[inputs.wireguard]]
|
||||
devices = ["wg0","wg1"]
|
||||
[[inputs.pf]]
|
||||
{% endif %}
|
||||
156
templates/telegraf/docker.conf.j2
Normal file
156
templates/telegraf/docker.conf.j2
Normal file
@@ -0,0 +1,156 @@
|
||||
##############################################################################
|
||||
# PROCESSOR PLUGINS #
|
||||
##############################################################################
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_mem"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_net"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_cpu"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_blkio"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_health"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_status"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
###############################################################################
|
||||
# INPUT PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[inputs.docker]]
|
||||
## Docker Endpoint
|
||||
## To use TCP, set endpoint = "tcp://[ip]:[port]"
|
||||
## To use environment variables (ie, docker-machine), set endpoint = "ENV"
|
||||
endpoint = "unix:///var/run/docker.sock"
|
||||
|
||||
## Set to true to collect Swarm metrics(desired_replicas, running_replicas)
|
||||
## Note: configure this in one of the manager nodes in a Swarm cluster.
|
||||
## configuring in multiple Swarm managers results in duplication of metrics.
|
||||
gather_services = false
|
||||
|
||||
## Only collect metrics for these containers. Values will be appended to
|
||||
## container_name_include.
|
||||
## Deprecated (1.4.0), use container_name_include
|
||||
container_names = []
|
||||
|
||||
## Set the source tag for the metrics to the container ID hostname, eg first 12 chars
|
||||
source_tag = false
|
||||
|
||||
## Containers to include and exclude. Collect all if empty. Globs accepted.
|
||||
container_name_include = []
|
||||
container_name_exclude = []
|
||||
|
||||
## Container states to include and exclude. Globs accepted.
|
||||
## When empty only containers in the "running" state will be captured.
|
||||
## example: container_state_include = ["created", "restarting", "running", "removing", "paused", "exited", "dead"]
|
||||
## example: container_state_exclude = ["created", "restarting", "running", "removing", "paused", "exited", "dead"]
|
||||
# container_state_include = []
|
||||
# container_state_exclude = []
|
||||
|
||||
## Timeout for docker list, info, and stats commands
|
||||
timeout = "5s"
|
||||
|
||||
## Whether to report for each container per-device blkio (8:0, 8:1...),
|
||||
## network (eth0, eth1, ...) and cpu (cpu0, cpu1, ...) stats or not.
|
||||
## Usage of this setting is discouraged since it will be deprecated in favor of 'perdevice_include'.
|
||||
## Default value is 'true' for backwards compatibility, please set it to 'false' so that 'perdevice_include' setting
|
||||
## is honored.
|
||||
perdevice = true
|
||||
|
||||
## Specifies for which classes a per-device metric should be issued
|
||||
## Possible values are 'cpu' (cpu0, cpu1, ...), 'blkio' (8:0, 8:1, ...) and 'network' (eth0, eth1, ...)
|
||||
## Please note that this setting has no effect if 'perdevice' is set to 'true'
|
||||
# perdevice_include = ["cpu"]
|
||||
|
||||
## Whether to report for each container total blkio and network stats or not.
|
||||
## Usage of this setting is discouraged since it will be deprecated in favor of 'total_include'.
|
||||
## Default value is 'false' for backwards compatibility, please set it to 'true' so that 'total_include' setting
|
||||
## is honored.
|
||||
total = false
|
||||
|
||||
## Specifies for which classes a total metric should be issued. Total is an aggregated of the 'perdevice' values.
|
||||
## Possible values are 'cpu', 'blkio' and 'network'
|
||||
## Total 'cpu' is reported directly by Docker daemon, and 'network' and 'blkio' totals are aggregated by this plugin.
|
||||
## Please note that this setting has no effect if 'total' is set to 'false'
|
||||
# total_include = ["cpu", "blkio", "network"]
|
||||
|
||||
## docker labels to include and exclude as tags. Globs accepted.
|
||||
## Note that an empty array for both will include all labels as tags
|
||||
docker_label_include = []
|
||||
docker_label_exclude = ["traefik.*"] # Do not report on Traefik tags
|
||||
|
||||
## Which environment variables should we use as a tag
|
||||
tag_env = ["JAVA_HOME", "HEAP_SIZE"]
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = false
|
||||
22
templates/telegraf/leader.conf.j2
Normal file
22
templates/telegraf/leader.conf.j2
Normal file
@@ -0,0 +1,22 @@
|
||||
[[processors.regex]]
|
||||
namepass = ["consul_health_checks"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "check_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^service: \\W(\\w+)\\W check$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[inputs.consul]]
|
||||
address = "consul.service.consul:8500"
|
||||
scheme = "http"
|
||||
insecure_skip_verify = true
|
||||
metric_version = 2
|
||||
namedrop = ["traefik.http*","traefik.enable*","traefik.tcp*"]
|
||||
tagexclude = ["traefik.http*","traefik.enable*", "traefik.tcp*"]
|
||||
[inputs.consul.tagdrop]
|
||||
check_name = [ "Nomad Client*", "Nomad Server*", "Serf Health Status" ]
|
||||
15
templates/telegraf/nomad.conf.j2
Normal file
15
templates/telegraf/nomad.conf.j2
Normal file
@@ -0,0 +1,15 @@
|
||||
[[inputs.statsd]]
|
||||
protocol = "udp" # Protocol, must be "tcp", "udp4", "udp6" or "udp" (default=udp)
|
||||
service_address = "127.0.0.1:8125" # Address and port to host UDP listener on
|
||||
delete_gauges = true # Reset gauges every interval (default=true)
|
||||
delete_counters = true # Reset counters every interval (default=true)
|
||||
delete_sets = true # Reset sets every interval (default=true)
|
||||
delete_timings = true # Reset timings & histograms every interval (default=true)
|
||||
percentiles = [90.0] # Percentiles to calculate for timing & histogram stats
|
||||
metric_separator = "_"
|
||||
datadog_extensions = true # Parses tags in the datadog statsd format
|
||||
allowed_pending_messages = 10000
|
||||
percentile_limit = 1000
|
||||
[inputs.statsd.tagdrop]
|
||||
task = [ "await-*","run-*","await_*","run_*","create_*","create-*" ]
|
||||
task_group = [ "await-*","run-*","await_*","run_*","create_*","create-*" ]
|
||||
88
templates/telegraf/pingHosts.conf.j2
Normal file
88
templates/telegraf/pingHosts.conf.j2
Normal file
@@ -0,0 +1,88 @@
|
||||
{# Ping internal servers #}
|
||||
[[processors.enum]]
|
||||
[[processors.enum.mapping]]
|
||||
## Name of the field to map
|
||||
#field = "url"
|
||||
|
||||
## Name of the tag to map
|
||||
tag = "url"
|
||||
|
||||
## Destination tag or field to be used for the mapped value. By default the
|
||||
## source tag or field is used, overwriting the original value.
|
||||
dest = "host"
|
||||
|
||||
## Default value to be used for all values not contained in the mapping
|
||||
## table. When unset and no match is found, the original field will remain
|
||||
## unmodified and the destination tag or field will not be created.
|
||||
# default = 0
|
||||
|
||||
## Table of mappings
|
||||
[processors.enum.mapping.value_mappings]
|
||||
"10.0.30.6" = "synology"
|
||||
{% for i in groups['pis'] %}
|
||||
"{{ hostvars[i].ansible_host }}" = "{{ hostvars[i].inventory_hostname }}"
|
||||
{% endfor %}
|
||||
|
||||
[[inputs.ping]]
|
||||
## Hosts to send ping packets to.
|
||||
# https://github.com/influxdata/telegraf/blob/release-1.13/plugins/inputs/ping/README.md
|
||||
urls = [{% for i in groups['pis'] %}'{{ hostvars[i].ansible_host }}'{% if not loop.last %}, {% endif %}{% endfor %},
|
||||
'10.0.30.6',
|
||||
'core1.bos1.he.net',
|
||||
'core1.lax1.he.net',
|
||||
'core1.nyc4.he.net',
|
||||
'core1.oma1.he.net',
|
||||
'core1.chi1.he.net',
|
||||
'core1.dal1.he.net',
|
||||
'core1.den1.he.net',
|
||||
'core1.mia1.he.net',
|
||||
'core1.bna1.he.net',
|
||||
'core1.phx1.he.net',
|
||||
'core1.sea1.he.net',
|
||||
'core1.blp1.he.net',
|
||||
'core1.ams1.he.net',
|
||||
'core1.dxb1.he.net',
|
||||
'core1.jnb1.he.net',
|
||||
'core1.man1.he.net',
|
||||
'core1.rom1.he.net',
|
||||
'core1.tyo1.he.net',
|
||||
'core1.zrh3.he.net',
|
||||
'core2.sao1.he.net',
|
||||
'core1.sin1.he.net',
|
||||
'core1.kpb1.he.net',
|
||||
'core1.nbo1.he.net',
|
||||
'core1.tpe1.he.net',
|
||||
'core1.sto1.he.net',
|
||||
'core1.ymq1.he.net',
|
||||
'core2.syd1.he.net'
|
||||
]
|
||||
|
||||
## Method used for sending pings, can be either "exec" or "native". When set
|
||||
## to "exec" the systems ping command will be executed. When set to "native"
|
||||
## the plugin will send pings directly.
|
||||
##
|
||||
## While the default is "exec" for backwards compatibility, new deployments
|
||||
## are encouraged to use the "native" method for improved compatibility and
|
||||
## performance.
|
||||
method = "exec"
|
||||
|
||||
## Number of ping packets to send per interval. Corresponds to the "-c"
|
||||
## option of the ping command.
|
||||
count = 1
|
||||
|
||||
## Time to wait between sending ping packets in seconds. Operates like the
|
||||
## "-i" option of the ping command.
|
||||
ping_interval = 1.0
|
||||
|
||||
fielddrop = ["packets_received", "packets_transmitted", "ttl", "standard_deviation_ms"]
|
||||
|
||||
interval = "1m" ## Interval to send pings
|
||||
|
||||
## Specify the ping executable binary.
|
||||
{% if 'pis' in group_names %}
|
||||
binary = "/usr/bin/ping"
|
||||
{% elif 'macs' in group_names %}
|
||||
binary = "/sbin/ping"
|
||||
{% else %}
|
||||
binary = "/bin/ping"
|
||||
{% endif %}
|
||||
234
templates/telegraf/synology.conf.j2
Normal file
234
templates/telegraf/synology.conf.j2
Normal file
@@ -0,0 +1,234 @@
|
||||
# Telegraf Configuration
|
||||
#
|
||||
# Telegraf is entirely plugin driven. All metrics are gathered from the
|
||||
# declared inputs, and sent to the declared outputs.
|
||||
#
|
||||
# Plugins must be declared in here to be active.
|
||||
# To deactivate a plugin, comment out the name and any variables.
|
||||
#
|
||||
# Use 'telegraf -config telegraf.conf -test' to see what metrics a config
|
||||
# file would generate.
|
||||
#
|
||||
# Environment variables can be used anywhere in this config file, simply surround
|
||||
# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"),
|
||||
# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})
|
||||
|
||||
|
||||
# Global tags can be specified here in key="value" format.
|
||||
[global_tags]
|
||||
dc = "{{ datacenter_name }}"
|
||||
ip = "{{ ansible_host }}"
|
||||
|
||||
# Configuration for telegraf agent
|
||||
[agent]
|
||||
|
||||
interval = "10s" ## Default data collection interval for all inputs
|
||||
round_interval = true ## ie, if interval="10s" then always collect on :00, :10, :20, etc.
|
||||
metric_batch_size = 1000 ## Controls the size of writes that Telegraf sends to output plugins
|
||||
metric_buffer_limit = 10000 ## Maximum number of unwritten metrics per output.
|
||||
collection_jitter = "5s" ## Jitter the collection by a random amount.
|
||||
flush_interval = "10s" ## Default flushing interval for all outputs.
|
||||
flush_jitter = "5s" ## Jitter the flush interval by a random amount
|
||||
precision = ""
|
||||
debug = false ## Log at debug level.
|
||||
# quiet = false ## Log only error level messages.
|
||||
{% if 'pis' in group_names %}
|
||||
logtarget = "file" ## destination logs can be one of "file" or "stderr"
|
||||
logfile = "/var/log/telegraf/telegraf.log"
|
||||
logfile_rotation_interval = "1d"
|
||||
# logfile_rotation_max_size = "0MB"
|
||||
logfile_rotation_max_archives = 2
|
||||
{% elif 'macs' in group_names %}
|
||||
logtarget = "stderr" ## destination logs can be one of "file" or "stderr"
|
||||
{% endif %}
|
||||
|
||||
hostname = "{{ inventory_hostname }}" ## Override default hostname, if empty use os.Hostname()
|
||||
omit_hostname = false ## If set to true, do no set the "host" tag in the telegraf agent.
|
||||
|
||||
###############################################################################
|
||||
# OUTPUT PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[outputs.influxdb]]
|
||||
urls = ["http://influxdb.service.consul:{{ influxdb_port }}"]
|
||||
database = "homelab"
|
||||
retention_policy = "2day"
|
||||
timeout = "5s"
|
||||
|
||||
###############################################################################
|
||||
# INPUT PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[inputs.cpu]] # Read metrics about cpu usage
|
||||
percpu = true ## Whether to report per-cpu stats or not
|
||||
totalcpu = true ## Whether to report total system cpu stats or not
|
||||
collect_cpu_time = false ## If true, collect raw CPU time metrics.
|
||||
report_active = false ## If true, compute and report the sum of all non-idle CPU states.
|
||||
[[inputs.disk]] # Read metrics about disk usage by mount point
|
||||
#mount_points = ["/mnt/usbDrive","/boot"] # Restrict the stats to only the specified mount points.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs", "nfsd", "nfs4", "smbfs"]
|
||||
[[inputs.diskio]] # Read metrics about disk IO by device
|
||||
[[inputs.internal]] # Collect telegraf memory stats.
|
||||
collect_memstats = true
|
||||
[[inputs.mem]] # Read metrics about memory usage
|
||||
[[inputs.processes]] # Get the number of processes and group them by status
|
||||
[[inputs.swap]] # Read metrics about swap memory usage
|
||||
[[inputs.system]] # Read metrics about system load & uptime
|
||||
[[inputs.net]] # Gather metrics about network interfaces
|
||||
|
||||
###############################################################################
|
||||
# PROCESSOR PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_mem"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_net"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_cpu"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_blkio"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_health"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
[[processors.regex]]
|
||||
namepass = ["docker_container_status"]
|
||||
|
||||
# Tag and field conversions defined in a separate sub-tables
|
||||
[[processors.regex.tags]]
|
||||
## Tag to change
|
||||
key = "container_name"
|
||||
## Regular expression to match on a tag value
|
||||
pattern = "^([a-zA-Z0-9_]+)-\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$"
|
||||
## Matches of the pattern will be replaced with this string. Use ${1}
|
||||
## notation to use the text of the first submatch.
|
||||
replacement = "${1}"
|
||||
|
||||
###############################################################################
|
||||
# INPUT PLUGINS #
|
||||
###############################################################################
|
||||
|
||||
[[inputs.docker]]
|
||||
## Docker Endpoint
|
||||
## To use TCP, set endpoint = "tcp://[ip]:[port]"
|
||||
## To use environment variables (ie, docker-machine), set endpoint = "ENV"
|
||||
endpoint = "unix:///var/run/docker.sock"
|
||||
|
||||
## Set to true to collect Swarm metrics(desired_replicas, running_replicas)
|
||||
## Note: configure this in one of the manager nodes in a Swarm cluster.
|
||||
## configuring in multiple Swarm managers results in duplication of metrics.
|
||||
gather_services = false
|
||||
|
||||
## Only collect metrics for these containers. Values will be appended to
|
||||
## container_name_include.
|
||||
## Deprecated (1.4.0), use container_name_include
|
||||
container_names = []
|
||||
|
||||
## Set the source tag for the metrics to the container ID hostname, eg first 12 chars
|
||||
source_tag = false
|
||||
|
||||
## Containers to include and exclude. Collect all if empty. Globs accepted.
|
||||
container_name_include = []
|
||||
container_name_exclude = []
|
||||
|
||||
## Container states to include and exclude. Globs accepted.
|
||||
## When empty only containers in the "running" state will be captured.
|
||||
## example: container_state_include = ["created", "restarting", "running", "removing", "paused", "exited", "dead"]
|
||||
## example: container_state_exclude = ["created", "restarting", "running", "removing", "paused", "exited", "dead"]
|
||||
# container_state_include = []
|
||||
# container_state_exclude = []
|
||||
|
||||
## Timeout for docker list, info, and stats commands
|
||||
timeout = "5s"
|
||||
|
||||
## Whether to report for each container per-device blkio (8:0, 8:1...),
|
||||
## network (eth0, eth1, ...) and cpu (cpu0, cpu1, ...) stats or not.
|
||||
## Usage of this setting is discouraged since it will be deprecated in favor of 'perdevice_include'.
|
||||
## Default value is 'true' for backwards compatibility, please set it to 'false' so that 'perdevice_include' setting
|
||||
## is honored.
|
||||
perdevice = true
|
||||
|
||||
## Specifies for which classes a per-device metric should be issued
|
||||
## Possible values are 'cpu' (cpu0, cpu1, ...), 'blkio' (8:0, 8:1, ...) and 'network' (eth0, eth1, ...)
|
||||
## Please note that this setting has no effect if 'perdevice' is set to 'true'
|
||||
# perdevice_include = ["cpu"]
|
||||
|
||||
## Whether to report for each container total blkio and network stats or not.
|
||||
## Usage of this setting is discouraged since it will be deprecated in favor of 'total_include'.
|
||||
## Default value is 'false' for backwards compatibility, please set it to 'true' so that 'total_include' setting
|
||||
## is honored.
|
||||
total = false
|
||||
|
||||
## Specifies for which classes a total metric should be issued. Total is an aggregated of the 'perdevice' values.
|
||||
## Possible values are 'cpu', 'blkio' and 'network'
|
||||
## Total 'cpu' is reported directly by Docker daemon, and 'network' and 'blkio' totals are aggregated by this plugin.
|
||||
## Please note that this setting has no effect if 'total' is set to 'false'
|
||||
# total_include = ["cpu", "blkio", "network"]
|
||||
|
||||
## docker labels to include and exclude as tags. Globs accepted.
|
||||
## Note that an empty array for both will include all labels as tags
|
||||
docker_label_include = []
|
||||
docker_label_exclude = ["traefik.*"] # Do not report on Traefik tags
|
||||
|
||||
## Which environment variables should we use as a tag
|
||||
tag_env = ["JAVA_HOME", "HEAP_SIZE"]
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = false
|
||||
10
templates/telegraf/temperature.conf.j2
Normal file
10
templates/telegraf/temperature.conf.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
[[inputs.exec]]
|
||||
{% if 'pis' in group_names %}
|
||||
commands = ["cat /sys/class/thermal/thermal_zone0/temp"]
|
||||
{% elif 'macs' in group_names %}
|
||||
commands = ["${HOME}/dotfiles-private/config/telegraf/cputemp.sh"]
|
||||
{% endif %}
|
||||
timeout = "5s"
|
||||
name_suffix = "_cpu_temp"
|
||||
data_format = "value"
|
||||
data_type = "integer"
|
||||
Reference in New Issue
Block a user