Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
076a52cdda
|
||
|
|
eff0edf247
|
||
|
|
3e80a4ec64
|
||
|
|
744dce7b46
|
||
|
|
b34ee24490
|
||
|
|
eb444f1191
|
||
|
|
eae40fd55b
|
||
|
|
413f02d9c1
|
||
|
|
2bd6da0064
|
||
|
|
2042339174
|
||
|
|
6b967c9ac1
|
||
|
|
0224a99fdb
|
||
|
|
f6f0d5b22d
|
||
|
|
1cb6040a21
|
||
|
|
451903f663
|
||
|
|
7345eaceb1
|
||
|
|
db7e9b7014
|
||
|
|
098dcd4e32
|
||
|
|
bd0e0dc810
|
||
|
|
4971bbfd1a
|
||
|
|
7e55a1f1d1
|
||
|
|
2abd33aba7
|
||
|
|
67877f1880
|
||
|
|
d0804bd7dc
|
||
|
|
24e4498f75
|
||
|
|
71a27eb3ca
|
||
|
|
63d6b1eb9c
|
||
|
|
de2c4f27fe
|
||
|
|
956a58a310
|
||
|
|
f453a3004d
|
||
|
|
da969e7709
|
||
|
|
73ef2cb575
|
||
|
|
4fe2f34557
|
||
|
|
4b74dcdf07
|
||
|
|
777efbca4c
|
||
|
|
a8294f25ab
|
||
|
|
f5cd38c457
|
||
|
|
c74d2f1025
|
||
|
|
bdb04e374f
|
||
|
|
051c497054
|
||
|
|
64e1639c06
|
||
|
|
fae8f57298
|
||
|
|
8d0c6bc301
|
||
|
|
80766f2473
|
||
|
|
d9a59e064e
|
||
|
|
16cb333991
|
||
|
|
7386de86d7
|
||
|
|
5ff6046169
|
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "redis-4",
|
||||
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3Zdzfao+n3PdtlJlViJ\nnpVDcL8ofw2rb2/VK7ivpWMKaL7mOq8HIQ+R+ghvllX/vPmN6co3+aUxOvvQ6KGC\nmAcnc7StqOpYUK0g6QZFROESO0vz1hy078AL9D2dEwOj7XS8leWCQyGgA1Z89T9n\naatXqEF1zGuvnVLA340prYkJk5S1X6KHq1WIi9H23hYehvGZlpkJ87wv8sKIo4Y3\nzIVA5hio0t0q+JyStOGr+xRl3mM43b25XcIh2ibrzKp3YoRWSCvMfhAdMKm1WEEI\njM/3fQRtkI1OQSb0o/wUoAmpUEEOTIvbWU2SuFVY7HYRuPwEilvbrGZKgrvbp8R+\nZQIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "rsk-mainnet-3",
|
||||
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwdrYfy0Spmt8VETCdUgW\nHbxV3uYA3kn2swvOdIjIR29gNO+t6wWv6FHnV/pfefIweIPaNlr9VMoUejUKX809\ngzdsiVWh1T6s4Yzbbt+O8mF3my5RXiSvizda8c6U65vofBSL2WVzE1AW9v7lXRHX\nJ4auKrpgKWkNLU52QLIP9/X5YLUHQtpTnplO31eb+jSD185aN1qoIxugunxnWSgm\n2NgUPlVbNCFrhv0PVv4Ts10eX6smRX3LKyNBtRRXM3GIrQHlAYRohIpy3lt8tKm4\nE/v9qpXQHvqEmX9FH1/Sonea849cWX3LuxUYLT2XFpaNwUxJK56Ef0HsgZESaxL+\n3QIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||
}
|
||||
@@ -81,7 +81,7 @@
|
||||
"garage-",
|
||||
"lq-",
|
||||
"rsk-",
|
||||
"postgres-6"
|
||||
"postgres-11"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -127,7 +127,8 @@
|
||||
"description": "Members-only nostr relay for kosmos.org users",
|
||||
"pubkey": "b3e1b7c0ef48294bd856203bfd460625de95d3afb894e5f09b14cd1f0e7097cf",
|
||||
"contact": "ops@kosmos.org",
|
||||
"icon": "https://assets.kosmos.org/img/app-icon-256px.png"
|
||||
"icon": "https://assets.kosmos.org/img/app-icon-256px.png",
|
||||
"privacy": "https://accounts.kosmos.org/privacy"
|
||||
},
|
||||
"write_policy": {
|
||||
"plugin": "/opt/strfry/strfry-policy.ts"
|
||||
|
||||
+1
-1
Submodule nodes updated: 503f8ec5ff...2b6479d2de
Executable
+199
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env bash
|
||||
# Manually record an incoming Lightning payment to credit a lndhub.go user account.
|
||||
#
|
||||
# Mirrors the canonical incoming-settlement path in lib/service/invoicesubscription.go
|
||||
# (ProcessInvoiceUpdate): inserts a settled `invoices` row plus a `transaction_entries`
|
||||
# row crediting the user's `current` account and debiting their `incoming` account
|
||||
# (which is exempt from the non-negative check_balance() trigger, so it may go negative).
|
||||
#
|
||||
# Usage:
|
||||
# ./gitno/credit-account.sh --env-file <path/to/.env> \
|
||||
# --login <login> --sats <N> [--memo "manual credit"]
|
||||
#
|
||||
# The --env-file is the lndhub.go .env file (the same one loaded by godotenv in
|
||||
# cmd/server/main.go). Only DATABASE_URI is read from it; the value from the file
|
||||
# ALWAYS takes precedence over any DATABASE_URI already present in the environment.
|
||||
#
|
||||
# Requires: psql. The whole operation runs in one transaction; ON_ERROR_STOP=1
|
||||
# aborts on any error so the tx is rolled back and psql exits non-zero.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: credit-account.sh --env-file <path/to/.env> --login <login> --sats <N> [--memo "..."]
|
||||
|
||||
Options:
|
||||
--env-file Path to the lndhub.go .env file (required). Only DATABASE_URI is
|
||||
read from it; the file value always wins over the environment.
|
||||
--login User login (required)
|
||||
--sats Amount in satoshis to credit (required, positive integer)
|
||||
--memo Memo for the recorded invoice (default: "manual credit")
|
||||
-h, --help
|
||||
EOF
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
env_file=""
|
||||
login=""
|
||||
sats=""
|
||||
memo="manual credit"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--env-file) env_file="$2"; shift 2 ;;
|
||||
--login) login="$2"; shift 2 ;;
|
||||
--sats) sats="$2"; shift 2 ;;
|
||||
--memo) memo="$2"; shift 2 ;;
|
||||
-h|--help) usage 0 ;;
|
||||
*) echo "Unknown argument: $1" >&2; usage 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -n "$env_file" ]] || { echo "Error: --env-file is required" >&2; usage 1; }
|
||||
[[ -n "$login" ]] || { echo "Error: --login is required" >&2; usage 1; }
|
||||
[[ -n "$sats" ]] || { echo "Error: --sats is required" >&2; usage 1; }
|
||||
[[ "$sats" =~ ^[1-9][0-9]*$ ]] || { echo "Error: --sats must be a positive integer" >&2; usage 1; }
|
||||
|
||||
# Sanity-check psql is available.
|
||||
command -v psql >/dev/null || { echo "Error: psql not found in PATH" >&2; exit 1; }
|
||||
|
||||
# Extract a single KEY=VALUE entry from a .env file, matching godotenv semantics:
|
||||
# - skips blank lines and lines whose first non-whitespace char is '#'
|
||||
# - tolerates an optional leading 'export '
|
||||
# - case-insensitive key match
|
||||
# - strips one pair of surrounding matching quotes (" or ') from the value
|
||||
# Writes the result to stdout; empty output means "not found".
|
||||
extract_env_key() {
|
||||
local file="$1" key="$2" line k v
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
# Trim leading whitespace; skip blanks and comments
|
||||
line="${line#"${line%%[![:space:]]*}"}"
|
||||
[[ -z "$line" || "${line:0:1}" == "#" ]] && continue
|
||||
# Strip optional 'export ' prefix
|
||||
[[ "$line" == export\ * ]] && line="${line#export }"
|
||||
# Split on the first '='
|
||||
[[ "$line" != *=* ]] && continue
|
||||
k="${line%%=*}"
|
||||
v="${line#*=}"
|
||||
# Case-insensitive key compare
|
||||
if [[ "${k,,}" == "${key,,}" ]]; then
|
||||
# Strip one pair of surrounding matching single or double quotes
|
||||
if [[ ${#v} -ge 2 ]]; then
|
||||
if [[ "${v:0:1}" == '"' && "${v: -1}" == '"' ]]; then v="${v:1:-1}";
|
||||
elif [[ "${v:0:1}" == "'" && "${v: -1}" == "'" ]]; then v="${v:1:-1}"; fi
|
||||
fi
|
||||
printf '%s\n' "$v"
|
||||
return 0
|
||||
fi
|
||||
done < "$file"
|
||||
return 1
|
||||
}
|
||||
|
||||
[[ -r "$env_file" ]] || { echo "Error: --env-file not readable: $env_file" >&2; exit 1; }
|
||||
|
||||
# DATABASE_URI is sourced exclusively from --env-file; the file value always wins
|
||||
# over any DATABASE_URI already present in the environment.
|
||||
if ! DATABASE_URI="$(extract_env_key "$env_file" DATABASE_URI)"; then
|
||||
echo "Error: DATABASE_URI not found in $env_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ -n "$DATABASE_URI" ]] || { echo "Error: DATABASE_URI is empty in $env_file" >&2; exit 1; }
|
||||
|
||||
case "$DATABASE_URI" in
|
||||
postgres://*|postgresql://*) ;;
|
||||
*) echo "Error: DATABASE_URI must start with postgres:// or postgresql:// (got: $DATABASE_URI)" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
psql "$DATABASE_URI" \
|
||||
-v ON_ERROR_STOP=1 \
|
||||
-v login="$login" \
|
||||
-v sats="$sats" \
|
||||
-v memo="$memo" \
|
||||
<<'SQL'
|
||||
\set ON_ERROR_STOP on
|
||||
\echo Resolving user, accounts, and recording the credit in one transaction...
|
||||
|
||||
-- Pass the CLI args into server-side GUCs so the DO block (dollar-quoted, where
|
||||
-- psql :var substitution does NOT happen) can read them via current_setting().
|
||||
-- These SETs run outside any dollar-quote, so :'login'/:sats/:'memo' are substituted
|
||||
-- by psql as a properly-quoted SQL literal / bare token here.
|
||||
SET app.lndhub_login = :'login';
|
||||
SET app.lndhub_sats = :sats;
|
||||
SET app.lndhub_memo = :'memo';
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- Look up user + accounts, validate, and insert the invoice + ledger entry.
|
||||
-- Raises an exception (aborting the tx, psql exits non-zero via ON_ERROR_STOP)
|
||||
-- with a helpful message if the user or either account is missing.
|
||||
DO $$
|
||||
DECLARE
|
||||
v_uid bigint;
|
||||
v_curr bigint;
|
||||
v_inc bigint;
|
||||
v_inv_id bigint;
|
||||
v_login text := current_setting('app.lndhub_login');
|
||||
v_sats bigint := current_setting('app.lndhub_sats')::bigint;
|
||||
v_memo text := current_setting('app.lndhub_memo');
|
||||
BEGIN
|
||||
SELECT id INTO v_uid FROM users WHERE login = v_login;
|
||||
IF NOT FOUND THEN
|
||||
RAISE EXCEPTION 'no user found with login = %', v_login;
|
||||
END IF;
|
||||
|
||||
SELECT id INTO v_curr FROM accounts WHERE user_id = v_uid AND type = 'current';
|
||||
IF NOT FOUND THEN
|
||||
RAISE EXCEPTION 'user % has no current account', v_uid;
|
||||
END IF;
|
||||
|
||||
SELECT id INTO v_inc FROM accounts WHERE user_id = v_uid AND type = 'incoming';
|
||||
IF NOT FOUND THEN
|
||||
RAISE EXCEPTION 'user % has no incoming account', v_uid;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'user_id=% current_acct=% incoming_acct=% amount=% sats',
|
||||
v_uid, v_curr, v_inc, v_sats;
|
||||
|
||||
-- Settled incoming invoice. Constraints honored:
|
||||
-- * destination_pubkey_hex NOT NULL -> 66-hex dummy
|
||||
-- * settled => preimage NOT NULL (check_primage_exists)
|
||||
-- * fresh r_hash/preimage per run keeps rows distinct
|
||||
-- * uses gen_random_uuid() (built-in core since PG13, no pgcrypto needed);
|
||||
-- 32 hex chars is sufficient for a dummy identifier
|
||||
INSERT INTO invoices
|
||||
(type, user_id, amount, memo, destination_pubkey_hex, r_hash, preimage,
|
||||
state, settled_at, created_at, internal)
|
||||
VALUES
|
||||
('incoming', v_uid, v_sats, v_memo,
|
||||
'000000000000000000000000000000000000000000000000000000000000000000',
|
||||
replace(gen_random_uuid()::text, '-', ''),
|
||||
replace(gen_random_uuid()::text, '-', ''),
|
||||
'settled', now(), now(), false)
|
||||
RETURNING id INTO v_inv_id;
|
||||
|
||||
RAISE NOTICE 'invoice_id=%', v_inv_id;
|
||||
|
||||
-- Ledger entry: credit current (+amount), debit incoming (-amount).
|
||||
-- * debit_account_id != credit_account_id (current != incoming) -> check_not_same_account ok
|
||||
-- * debit on `incoming` is exempt from check_balance() -> may go negative
|
||||
-- * fresh invoice_id keeps unique_tx_entry_tuple satisfied
|
||||
INSERT INTO transaction_entries
|
||||
(user_id, invoice_id, credit_account_id, debit_account_id, amount, entry_type, created_at)
|
||||
VALUES
|
||||
(v_uid, v_inv_id, v_curr, v_inc, v_sats, 'incoming', now());
|
||||
|
||||
RAISE NOTICE 'credited % sats to user % (login=%)', v_sats, v_uid, v_login;
|
||||
END $$;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- Resulting current-account balance (same query as CurrentUserBalance in
|
||||
-- lib/service/user.go: sum over account_ledgers for the user's current account).
|
||||
SELECT
|
||||
(SELECT sum(al.amount)
|
||||
FROM account_ledgers al
|
||||
JOIN accounts a ON a.id = al.account_id
|
||||
WHERE a.user_id = (SELECT id FROM users WHERE login = current_setting('app.lndhub_login'))
|
||||
AND a.type = 'current') AS new_balance_sat;
|
||||
SQL
|
||||
@@ -8,7 +8,7 @@ version '0.3.0'
|
||||
chef_version '>= 18.0'
|
||||
|
||||
depends 'kosmos_openresty'
|
||||
depends "kosmos-nodejs"
|
||||
depends "ark"
|
||||
depends "postgresql"
|
||||
depends "kosmos_postgresql"
|
||||
depends "backup"
|
||||
|
||||
@@ -27,12 +27,24 @@ end
|
||||
|
||||
package "libpq-dev"
|
||||
package "libvips"
|
||||
package "unzip"
|
||||
|
||||
node.override["kosmos_nodejs"]["version"] = "22.23.1"
|
||||
include_recipe 'kosmos-nodejs'
|
||||
npm_package "bun"
|
||||
bun_version = "1.3.14"
|
||||
bun_checksum = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f"
|
||||
|
||||
ruby_version = "3.3.8"
|
||||
ark "bun" do
|
||||
url "https://github.com/oven-sh/bun/releases/download/bun-v#{bun_version}/bun-linux-x64.zip"
|
||||
checksum bun_checksum
|
||||
creates "bun"
|
||||
path "/usr/local/bun/#{bun_version}/bin"
|
||||
action :cherry_pick
|
||||
end
|
||||
|
||||
link "/usr/local/bin/bun" do
|
||||
to "/usr/local/bun/#{bun_version}/bin/bun"
|
||||
end
|
||||
|
||||
ruby_version = "3.3.12"
|
||||
ruby_path = "/opt/ruby_build/builds/#{ruby_version}"
|
||||
bundle_path = "#{ruby_path}/bin/bundle"
|
||||
rails_env = node.chef_environment == "development" ? "development" : "production"
|
||||
@@ -234,7 +246,7 @@ systemd_unit "akkounts.service" do
|
||||
ExecStart: "#{bundle_path} exec puma -C config/puma.rb --pidfile #{deploy_path}/tmp/puma.pid",
|
||||
ExecReload: "#{bundle_path} exec pumactl -F config/puma.rb --pidfile #{deploy_path}/tmp/puma.pid phased-restart",
|
||||
PIDFile: "#{deploy_path}/tmp/puma.pid",
|
||||
TimeoutSec: "10",
|
||||
TimeoutSec: "30",
|
||||
Restart: "always",
|
||||
},
|
||||
Install: {
|
||||
|
||||
@@ -87,7 +87,7 @@ node.default['lndhub-go']['branding'] = {
|
||||
}
|
||||
|
||||
node.default['nbxplorer']['repo'] = 'https://github.com/dgarage/NBXplorer'
|
||||
node.default['nbxplorer']['revision'] = 'v2.5.26'
|
||||
node.default['nbxplorer']['revision'] = 'v2.6.10'
|
||||
node.default['nbxplorer']['source_dir'] = '/opt/nbxplorer'
|
||||
node.default['nbxplorer']['config_path'] = "/home/#{node['bitcoin']['username']}/.nbxplorer/Main/settings.config"
|
||||
node.default['nbxplorer']['port'] = '24445'
|
||||
@@ -95,7 +95,7 @@ node.default['nbxplorer']['postgres']['database'] = 'nbxplorer'
|
||||
node.default['nbxplorer']['postgres']['user'] = 'nbxplorer'
|
||||
|
||||
node.default['btcpay']['repo'] = 'https://github.com/btcpayserver/btcpayserver'
|
||||
node.default['btcpay']['revision'] = 'v2.3.7'
|
||||
node.default['btcpay']['revision'] = 'v2.4.3'
|
||||
node.default['btcpay']['source_dir'] = '/opt/btcpay'
|
||||
node.default['btcpay']['config_path'] = "/home/#{node['bitcoin']['username']}/.btcpayserver/Main/settings.config"
|
||||
node.default['btcpay']['log_path'] = "/home/#{node['bitcoin']['username']}/.btcpayserver/debug.log"
|
||||
|
||||
@@ -21,7 +21,7 @@ bash 'build_btcpay' do
|
||||
systemctl stop btcpayserver.service
|
||||
./build.sh
|
||||
EOH
|
||||
environment "DOTNET_CLI_TELEMETRY_OPTOUT" => 1
|
||||
environment "DOTNET_CLI_TELEMETRY_OPTOUT" => "1"
|
||||
action :nothing
|
||||
notifies :restart, "service[btcpayserver]", :delayed
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Recipe:: rtl
|
||||
#
|
||||
|
||||
node.override["kosmos_nodejs"]["version"] = "18.20.8"
|
||||
node.override["kosmos_nodejs"]["version"] = "22.23.1"
|
||||
include_recipe 'kosmos-nodejs'
|
||||
|
||||
app_name = "rtl"
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
# No attributes here, use the blossom cookbook's attributes
|
||||
|
||||
node.default['blossom']['nginx_cache_max_size'] = '1g'
|
||||
|
||||
@@ -23,6 +23,7 @@ openresty_site domain do
|
||||
upstream_host: blossom_node['knife_zero']['host'],
|
||||
upstream_port: node['blossom']['port'],
|
||||
max_size_mb: node['blossom']['max_size'] / 1024 / 1024,
|
||||
cache_max_size: node['blossom']['nginx_cache_max_size'],
|
||||
ssl_cert: "/etc/letsencrypt/live/#{domain}/fullchain.pem",
|
||||
ssl_key: "/etc/letsencrypt/live/#{domain}/privkey.pem"
|
||||
end
|
||||
|
||||
@@ -2,12 +2,16 @@ upstream _blossom {
|
||||
server <%= @upstream_host %>:<%= @upstream_port %>;
|
||||
}
|
||||
|
||||
proxy_cache_path <%= node['openresty']['cache_dir'] %>/blossom
|
||||
keys_zone=blossom_cache:10m
|
||||
max_size=<%= @cache_max_size %> inactive=100y use_temp_path=off;
|
||||
|
||||
server {
|
||||
server_name <%= @domain %>;
|
||||
listen <%= "#{node['openresty']['listen_ip']}:" if node['openresty']['listen_ip'] %>443 ssl http2;
|
||||
listen <%= "[#{node['openresty']['listen_ipv6']}]" %>:443 ssl http2;
|
||||
|
||||
access_log "/var/log/nginx/<%= @domain %>.access.log";
|
||||
access_log "/var/log/nginx/<%= @domain %>.access.log" json;
|
||||
error_log "/var/log/nginx/<%= @domain %>.error.log";
|
||||
|
||||
client_max_body_size <%= @max_size_mb %>M;
|
||||
@@ -15,6 +19,27 @@ server {
|
||||
ssl_certificate <%= @ssl_cert %>;
|
||||
ssl_certificate_key <%= @ssl_key %>;
|
||||
|
||||
location ~ "^/(?<sha256>[a-f0-9]{64})(\.[a-zA-Z0-9]+)?$" {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://_blossom;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_cache blossom_cache;
|
||||
proxy_cache_key $sha256;
|
||||
proxy_cache_valid 200 1y;
|
||||
proxy_cache_lock on;
|
||||
proxy_cache_use_stale error timeout updating;
|
||||
|
||||
log_by_lua_block {
|
||||
if ngx.var.request_method == "DELETE" and ngx.status >= 200 and ngx.status < 300 then
|
||||
os.remove("<%= node['openresty']['cache_dir'] %>/blossom/" .. ngx.md5(ngx.var.sha256))
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
require ["fileinto", "mailbox"];
|
||||
|
||||
if header :contains "X-Spam-Flag" "YES" {
|
||||
fileinto :create "Junk";
|
||||
stop;
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
dovecot-ldap
|
||||
dovecot-lmtpd
|
||||
dovecot-pop3d
|
||||
dovecot-sieve
|
||||
dovecot-managesieved
|
||||
].each do |pkg|
|
||||
apt_package pkg
|
||||
end
|
||||
@@ -26,8 +28,8 @@ credentials = Chef::EncryptedDataBagItem.load('credentials', 'email')
|
||||
template "/etc/dovecot/dovecot.conf" do
|
||||
source "dovecot.conf.erb"
|
||||
mode 0644
|
||||
# TODO variables protocols: "imap pop3 lmtp"
|
||||
variables protocols: "imap lmtp",
|
||||
# TODO variables protocols: "imap pop3 lmtp sieve"
|
||||
variables protocols: "imap lmtp sieve",
|
||||
# TODO find by email_proxy role
|
||||
haproxy_trusted_networks: "10.1.1.167/32"
|
||||
notifies :restart, "service[dovecot]", :delayed
|
||||
@@ -85,6 +87,40 @@ template "/etc/dovecot/conf.d/15-mailboxes.conf" do
|
||||
notifies :restart, "service[dovecot]", :delayed
|
||||
end
|
||||
|
||||
template "/etc/dovecot/conf.d/20-lmtp.conf" do
|
||||
source "dovecot_20-lmtp.conf.erb"
|
||||
mode 0644
|
||||
notifies :restart, "service[dovecot]", :delayed
|
||||
end
|
||||
|
||||
template "/etc/dovecot/conf.d/90-sieve.conf" do
|
||||
source "dovecot_90-sieve.conf.erb"
|
||||
mode 0644
|
||||
notifies :restart, "service[dovecot]", :delayed
|
||||
end
|
||||
|
||||
# Directory for global Sieve scripts (applied after user scripts)
|
||||
directory "/var/lib/dovecot/sieve" do
|
||||
owner "dovecot"
|
||||
group "dovecot"
|
||||
mode 0755
|
||||
end
|
||||
|
||||
# Global Sieve script run after every user script (sieve_after).
|
||||
# Files spam flagged by SpamAssassin (X-Spam-Flag: YES) into the Junk folder.
|
||||
cookbook_file "/var/lib/dovecot/sieve/after.sieve" do
|
||||
source "after.sieve"
|
||||
owner "dovecot"
|
||||
group "dovecot"
|
||||
mode 0644
|
||||
notifies :run, "execute[compile after.sieve]", :immediately
|
||||
end
|
||||
|
||||
execute "compile after.sieve" do
|
||||
command "sievec /var/lib/dovecot/sieve/after.sieve"
|
||||
action :nothing
|
||||
end
|
||||
|
||||
service "dovecot" do
|
||||
action [:enable, :start]
|
||||
end
|
||||
|
||||
@@ -32,3 +32,9 @@ firewall_rule "IMAPS" do
|
||||
port 993
|
||||
protocol :tcp
|
||||
end
|
||||
|
||||
firewall_rule "ManageSieve" do
|
||||
command :allow
|
||||
port 4190
|
||||
protocol :tcp
|
||||
end
|
||||
|
||||
@@ -29,6 +29,12 @@ template "/etc/spamassassin/local.cf" do
|
||||
notifies :restart, "service[spamassassin]", :delayed
|
||||
end
|
||||
|
||||
template "/etc/spamassassin/kosmos.cf" do
|
||||
source "spamassassin_kosmos.cf.erb"
|
||||
mode 0644
|
||||
notifies :restart, "service[spamassassin]", :delayed
|
||||
end
|
||||
|
||||
service "spamassassin" do
|
||||
action [:enable, :start]
|
||||
end
|
||||
|
||||
@@ -60,6 +60,18 @@ service submission-login {
|
||||
}
|
||||
}
|
||||
|
||||
service managesieve-login {
|
||||
inet_listener sieve {
|
||||
port = 4190
|
||||
ssl = yes
|
||||
}
|
||||
inet_listener sieve_haproxy {
|
||||
port = 14190
|
||||
ssl = yes
|
||||
haproxy = yes
|
||||
}
|
||||
}
|
||||
|
||||
service lmtp {
|
||||
unix_listener /var/spool/postfix/private/dovecot-lmtp {
|
||||
mode = 0600
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
##
|
||||
## LMTP specific settings
|
||||
##
|
||||
|
||||
# Enable the Sieve plugin for LMTP delivery so that Sieve scripts are
|
||||
# executed for incoming mail handed over by Postfix.
|
||||
protocol lmtp {
|
||||
mail_plugins = $mail_plugins sieve
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
##
|
||||
## Plugin settings (Sieve)
|
||||
##
|
||||
|
||||
plugin {
|
||||
# Per-user Sieve script storage. The "~" expands to mail_home
|
||||
# (/var/vmail/%d/%n) set in 10-mail.conf, so scripts for LDAP virtual
|
||||
# users are stored under ~/sieve/ with the active script symlinked at
|
||||
# ~/.dovecot.sieve.
|
||||
sieve = file:~/sieve;active=~/.dovecot.sieve
|
||||
|
||||
# Global Sieve script executed AFTER user scripts. Used to enforce
|
||||
# server-side spam filing regardless of per-user rules.
|
||||
sieve_after = /var/lib/dovecot/sieve/after.sieve
|
||||
}
|
||||
@@ -30,4 +30,4 @@ PIDFILE="/var/run/spamd.pid"
|
||||
# Cronjob
|
||||
# Set to anything but 0 to enable the cron job to automatically update
|
||||
# spamassassin's rules on a nightly basis
|
||||
CRON=0
|
||||
CRON=1
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
###########################################################################
|
||||
# Kosmos custom SpamAssassin rules
|
||||
#
|
||||
# The rules below are designed to be individually weak but combine via meta
|
||||
# rules into strong, low-FP signals.
|
||||
###########################################################################
|
||||
|
||||
# --- Individual signals --------------------------------------------------
|
||||
|
||||
# URLs of the form https://////////////... (3+ slashes after the scheme).
|
||||
# Legitimate mailers never produce this; it is an obfuscation artefact.
|
||||
rawbody KOSMOS_MULTI_SLASH_URL /https?:\/{3,}/
|
||||
describe KOSMOS_MULTI_SLASH_URL URL with three or more consecutive slashes
|
||||
|
||||
# Authoring-tool fingerprint left in the HTML by the spam toolchain.
|
||||
body KOSMOS_MSHTML_11_9600 /MSHTML 11\.00\.9600\.17037/
|
||||
describe KOSMOS_MSHTML_11_9600 HTML generated by MSHTML 11.00.9600.17037
|
||||
|
||||
# Display name pattern used by the campaign.
|
||||
header KOSMOS_FROM_LUXURY_GOODS From:name =~ /Luxury (Watches|Bags|Handbags|Timepieces)\b/i
|
||||
describe KOSMOS_FROM_LUXURY_GOODS From display name advertises luxury goods
|
||||
|
||||
# Base64-encoded unsubscribe links: return.php?p=<long base64>
|
||||
uri KOSMOS_RETURN_PHP_B64 /return\.php\?p=[A-Za-z0-9+\/=%]{20,}/
|
||||
describe KOSMOS_RETURN_PHP_B64 Base64-encoded return.php unsubscribe link
|
||||
|
||||
# Fabricated "security" headers injected to evade heuristic filters.
|
||||
# No legitimate MTA or mailing-list manager emits these.
|
||||
header KOSMOS_FAKE_HDR_PHISHSIM exists:X-PhishSimulator-Mode
|
||||
header KOSMOS_FAKE_HDR_DECEPTION exists:X-Deception-Asset-Type
|
||||
header KOSMOS_FAKE_HDR_OBFUSCATION exists:X-Obfuscation-Trace-ID
|
||||
header KOSMOS_FAKE_HDR_QUARANTINE exists:X-Quarantine-Reason-Code
|
||||
header KOSMOS_FAKE_HDR_TRUST exists:X-Behavioral-Trust-Index
|
||||
|
||||
# --- Scores for individual signals --------------------------------------
|
||||
score KOSMOS_MULTI_SLASH_URL 2.0
|
||||
score KOSMOS_MSHTML_11_9600 1.2
|
||||
score KOSMOS_FROM_LUXURY_GOODS 0.5
|
||||
score KOSMOS_RETURN_PHP_B64 1.5
|
||||
score KOSMOS_FAKE_HDR_PHISHSIM 1.0
|
||||
score KOSMOS_FAKE_HDR_DECEPTION 1.0
|
||||
score KOSMOS_FAKE_HDR_OBFUSCATION 1.0
|
||||
score KOSMOS_FAKE_HDR_QUARANTINE 1.0
|
||||
score KOSMOS_FAKE_HDR_TRUST 1.0
|
||||
|
||||
# --- Meta rules ----------------------------------------------------------
|
||||
|
||||
# Core campaign signature: luxury-goods From name + MSHTML fingerprint +
|
||||
# HTML-only body. Covers the bulk of the campaign corpus.
|
||||
meta KOSMOS_LUXURY_SPAM_CAMPAIGN (KOSMOS_FROM_LUXURY_GOODS && KOSMOS_MSHTML_11_9600 && MIME_HTML_ONLY)
|
||||
describe KOSMOS_LUXURY_SPAM_CAMPAIGN Luxury-goods From + MSHTML 11.00.9600 + HTML-only
|
||||
score KOSMOS_LUXURY_SPAM_CAMPAIGN 3.5
|
||||
|
||||
# Luxury-goods From name combined with a suspicious URI signal or a
|
||||
# Spamhaus-listed relay.
|
||||
meta KOSMOS_LUXURY_SPAM_URI (KOSMOS_FROM_LUXURY_GOODS && (KOSMOS_MULTI_SLASH_URL || KOSMOS_RETURN_PHP_B64 || RCVD_IN_SBL_CSS))
|
||||
describe KOSMOS_LUXURY_SPAM_URI Luxury-goods From + suspicious URI or SBL relay
|
||||
score KOSMOS_LUXURY_SPAM_URI 2.5
|
||||
|
||||
# Two or more fabricated "security" headers. Genuine mail never carries
|
||||
# these; their presence indicates a header-injection evasion kit.
|
||||
meta KOSMOS_FAKE_SECURITY_HEADERS (KOSMOS_FAKE_HDR_PHISHSIM + KOSMOS_FAKE_HDR_DECEPTION + KOSMOS_FAKE_HDR_OBFUSCATION + KOSMOS_FAKE_HDR_QUARANTINE + KOSMOS_FAKE_HDR_TRUST >= 2)
|
||||
describe KOSMOS_FAKE_SECURITY_HEADERS Two or more fabricated security headers
|
||||
score KOSMOS_FAKE_SECURITY_HEADERS 4.0
|
||||
@@ -16,6 +16,37 @@ whitelist_auth <%= @whitelist_auth %>
|
||||
# _CONTACTADDRESS_ in the report template)
|
||||
report_contact <%= @report_contact %>
|
||||
|
||||
###########################################################################
|
||||
# Kosmos custom score overrides
|
||||
#
|
||||
# The Validity (Return Path / SenderScore) "certified sender" whitelists
|
||||
# (RCVD_IN_VALIDITY_CERTIFIED, RCVD_IN_VALIDITY_SAFE) hand out up to -5.0
|
||||
# of credit to sending IPs. These lists are commercially gamed and
|
||||
# routinely award -5.0 to IPs that are simultaneously listed on Spamhaus
|
||||
# SBL-CSS, SpamCop, MSPIKE and Validity's own RPBL. Neutralise them.
|
||||
###########################################################################
|
||||
score RCVD_IN_VALIDITY_CERTIFIED 0
|
||||
score RCVD_IN_VALIDITY_SAFE 0
|
||||
|
||||
###########################################################################
|
||||
# Bayes hardening
|
||||
###########################################################################
|
||||
use_bayes 1
|
||||
bayes_auto_learn 1
|
||||
|
||||
# Do not let Bayes learn from SpamAssassin's own result headers or from
|
||||
# Authentication-Results, which leak signal about prior scoring runs.
|
||||
bayes_ignore_header X-Spam-Flag
|
||||
bayes_ignore_header X-Spam-Status
|
||||
bayes_ignore_header X-Spam-Level
|
||||
bayes_ignore_header X-Spam-Checker-Version
|
||||
bayes_ignore_header Authentication-Results
|
||||
|
||||
# Only learn ham when the message is clearly clean, and only learn spam
|
||||
# when it is clearly spam. The defaults (0.1 / 6.0) let marginally-spam
|
||||
# or marginally-ham messages poison the database.
|
||||
bayes_auto_learn_threshold_nonspam -1.0
|
||||
bayes_auto_learn_threshold_spam 8.0
|
||||
|
||||
# Add *****SPAM***** to the Subject header of spam e-mails
|
||||
#
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
This file is used to list changes made in each version of the kosmos_gitea cookbook.
|
||||
|
||||
# 0.2.2
|
||||
|
||||
- Add `config.yaml` for the gitea actions runner, enabling the built-in cache
|
||||
server (listening on the Docker bridge gateway `172.17.0.1`) and bumping
|
||||
`runner.capacity` to 2 for concurrent job execution. Each runner gets a unique
|
||||
cache port derived from `cache_base_port` (8088) + its index in the runners
|
||||
data bag.
|
||||
- Set `container.network` to a user-defined Docker bridge network
|
||||
(`gitea-actions`, subnet `172.20.0.0/16`) so job containers get DNS resolution
|
||||
for service containers (e.g. `redis`) while keeping the cache server reachable
|
||||
at the network gateway `172.20.0.1`.
|
||||
- Open the cache port in the firewall for Docker bridge traffic
|
||||
(`172.20.0.0/16`), fixing `Request timeout` errors from `actions/cache`.
|
||||
|
||||
# 0.1.0
|
||||
|
||||
Initial release.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
node.default["gitea"]["version"] = "1.26.4"
|
||||
node.default["gitea"]["checksum"] = "0faa36d151918f8f7d6e0f3ae67597d1c338583d695add146ac393109d0fc44a"
|
||||
node.default["gitea"]["version"] = "1.27.1"
|
||||
node.default["gitea"]["checksum"] = "86a7ac26e7f9c9cca0f56c4fac07fff205d5fc3bca0e54af23a204f07b833bc9"
|
||||
node.default["gitea"]["repo"] = nil
|
||||
node.default["gitea"]["revision"] = nil
|
||||
node.default["gitea"]["working_directory"] = "/var/lib/gitea"
|
||||
@@ -25,3 +25,17 @@ node.default["gitea"]["config"] = {
|
||||
|
||||
node.default["gitea"]["runner"]["version"] = "2.0.0"
|
||||
node.default["gitea"]["runner"]["checksum"] = "447156b33407ee045409f5552bd4a188a315cdd4085b4b498d8d4a9ad26c9f73"
|
||||
node.default["gitea"]["runner"]["cache_base_port"] = 8088
|
||||
node.default["gitea"]["runner"]["config"] = {
|
||||
"runner" => {
|
||||
"capacity" => 2
|
||||
},
|
||||
"container" => {
|
||||
"network" => "gitea-actions" # User-defined bridge network: provides DNS for service containers
|
||||
},
|
||||
"cache" => {
|
||||
"enabled" => true,
|
||||
"host" => "172.20.0.1" # Gateway of the gitea-actions network, reachable from job containers
|
||||
# Port is set per-runner (cache_base_port + index) in the runner recipe
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Increase if you have very long User-Agent strings
|
||||
map_hash_bucket_size 256;
|
||||
|
||||
# Bot user agents
|
||||
map $http_user_agent $bot_name {
|
||||
default "";
|
||||
~*ClaudeBot "claude";
|
||||
~*Sogou "sogou";
|
||||
~*meta-externalagent "meta-externalagent";
|
||||
# add more as needed
|
||||
}
|
||||
|
||||
# Decide the rate-limit key (per-IP for each bot in this example)
|
||||
map $bot_name $bot_limit_key {
|
||||
default "";
|
||||
"claude" $binary_remote_addr;
|
||||
"sogou" $binary_remote_addr;
|
||||
"meta-externalagent" $binary_remote_addr;
|
||||
}
|
||||
|
||||
# Shared memory zone – only non-empty keys are counted
|
||||
limit_req_zone $bot_limit_key zone=bots:20m rate=240r/m; # 4r/s per IP+bot
|
||||
|
||||
# Status code returned when the limit is exceeded
|
||||
limit_req_status 429;
|
||||
@@ -4,7 +4,7 @@ maintainer_email 'ops@kosmos.org'
|
||||
license 'MIT'
|
||||
description 'Installs/configures Gitea'
|
||||
long_description 'Installs/configures Gitea'
|
||||
version '0.2.0'
|
||||
version '0.2.2'
|
||||
chef_version '>= 14.0'
|
||||
|
||||
depends "firewall"
|
||||
|
||||
@@ -17,6 +17,14 @@ tls_cert_for domain do
|
||||
action :create
|
||||
end
|
||||
|
||||
# Slow down requests from bots
|
||||
cookbook_file "#{node["openresty"]["dir"]}/conf.d/rate_limits.conf" do
|
||||
source "rate_limits.conf"
|
||||
owner "root"
|
||||
group "root"
|
||||
mode "0644"
|
||||
end
|
||||
|
||||
openresty_site domain do
|
||||
template "nginx_conf_web.erb"
|
||||
variables server_name: domain,
|
||||
|
||||
@@ -35,14 +35,39 @@ directory "#{working_directory}/runners" do
|
||||
mode "0700"
|
||||
end
|
||||
|
||||
runners.each do |runner|
|
||||
execute "create_gitea_actions_network" do
|
||||
command "docker network create --subnet 172.20.0.0/16 gitea-actions"
|
||||
not_if "docker network inspect gitea-actions"
|
||||
end
|
||||
|
||||
runners.each_with_index do |runner, index|
|
||||
runner_name = "gitea-runner-#{runner["org"]}"
|
||||
runner_dir = "#{working_directory}/runners/#{runner["org"]}"
|
||||
cache_port = node["gitea"]["runner"]["cache_base_port"] + index
|
||||
|
||||
directory runner_dir do
|
||||
mode "0700"
|
||||
end
|
||||
|
||||
runner_config = node["gitea"]["runner"]["config"].to_hash
|
||||
runner_config["cache"] = runner_config["cache"].merge("port" => cache_port)
|
||||
|
||||
firewall_rule "runner_cache_#{runner["org"]}" do
|
||||
command :allow
|
||||
port cache_port
|
||||
protocol :tcp
|
||||
source "172.20.0.0/16"
|
||||
end
|
||||
|
||||
template "#{runner_dir}/config.yaml" do
|
||||
source "runner.config.yaml.erb"
|
||||
mode "0640"
|
||||
owner "root"
|
||||
group "root"
|
||||
variables(config: runner_config)
|
||||
notifies :restart, "service[#{runner_name}]", :delayed
|
||||
end
|
||||
|
||||
bash "register_#{runner["org"]}_runner" do
|
||||
cwd runner_dir
|
||||
code <<-EOF
|
||||
@@ -67,7 +92,7 @@ gitea_runner register \
|
||||
Type: "simple",
|
||||
WorkingDirectory: runner_dir,
|
||||
Environment: "HOME=/root",
|
||||
ExecStart: "/usr/local/bin/gitea_runner daemon",
|
||||
ExecStart: "/usr/local/bin/gitea_runner daemon --config #{runner_dir}/config.yaml",
|
||||
ExecStartPre: "/bin/sleep 3", # Wait for Gitea's API to be up when restarting at the same time
|
||||
Restart: "always",
|
||||
},
|
||||
|
||||
@@ -62,6 +62,9 @@ FROM = <%= @email %>
|
||||
INTERNAL_TOKEN = <%= @internal_token %>
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = <%= @secret_key %>
|
||||
<% if c = @config["webhook"] %>
|
||||
<% if c["allowed_host_list"] %>ALLOWED_HOST_LIST = <%= c["allowed_host_list"] %><% end %>
|
||||
<% end %>
|
||||
|
||||
[service]
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
@@ -101,11 +104,6 @@ RUN_AT_START = false
|
||||
NOTICE_ON_SUCCESS = false
|
||||
SCHEDULE = @every 15m
|
||||
|
||||
<% if c = @config["webhook"] %>
|
||||
[webhook]
|
||||
<% if c["allowed_host_list"] %>ALLOWED_HOST_LIST = <%= c["allowed_host_list"] %><% end %>
|
||||
<% end %>
|
||||
|
||||
<% if c = @config["storage"] %>
|
||||
[storage]
|
||||
<% if c["type"] == "minio" %>
|
||||
|
||||
@@ -20,6 +20,9 @@ server {
|
||||
|
||||
proxy_intercept_errors on;
|
||||
|
||||
# Rate limit for bots. Defined in /etc/openresty/conf.d/rate_limits.conf
|
||||
limit_req zone=bots burst=10; # allow a larger spike for asset bursts
|
||||
|
||||
location ~ ^/(avatars|repo-avatars)/.*$ {
|
||||
proxy_buffers 1024 8k;
|
||||
proxy_pass http://_gitea_web;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<%= @config.to_yaml.sub(/^---\n/, '') %>
|
||||
@@ -1,9 +1,9 @@
|
||||
release = "20260321"
|
||||
release = "20260801"
|
||||
img_filename = "ubuntu-24.04-server-cloudimg-amd64"
|
||||
|
||||
node.default["kosmos_kvm"]["host"]["qemu_base_image"] = {
|
||||
"url" => "https://cloud-images.ubuntu.com/releases/noble/release-#{release}/#{img_filename}.img",
|
||||
"checksum" => "5c3ddb00f60bc455dac0862fabe9d8bacec46c33ac1751143c5c3683404b110d",
|
||||
"checksum" => "0533b0655c32e68b31d792ecd6ccfca95abdbc536c4446874fe0513bd4140ffe",
|
||||
"path" => "/var/lib/libvirt/images/base/#{img_filename}-#{release}.qcow2"
|
||||
}
|
||||
|
||||
@@ -11,3 +11,10 @@ node.default["kosmos_kvm"]["host"]["qemu_base_image"] = {
|
||||
node.default["kosmos_kvm"]["backup"]["schedule"] = "0/3:00"
|
||||
# Node/VM names excluded from backups
|
||||
node.default["kosmos_kvm"]["backup"]["nodes_excluded"] = []
|
||||
|
||||
node.default["kosmos_kvm"]["guest"]["swap"] = {
|
||||
"enabled" => true, # set to false to disable swap on a guest
|
||||
"size_mb" => nil, # nil => auto (half of RAM); integer => fixed MB; 0 => disabled
|
||||
"path" => "/swapfile",
|
||||
"swappiness" => nil # nil => leave kernel default; e.g. 10 to tune
|
||||
}
|
||||
|
||||
@@ -8,3 +8,20 @@ package %w(qemu-guest-agent)
|
||||
service "qemu-guest-agent" do
|
||||
action [:enable, :start]
|
||||
end
|
||||
|
||||
swap_cfg = node["kosmos_kvm"]["guest"]["swap"]
|
||||
|
||||
if swap_cfg["enabled"] && swap_cfg["size_mb"] != 0
|
||||
size = swap_cfg["size_mb"] ||
|
||||
(node["memory"]["total"].to_i / 2 / 1024) # kB -> MB, half RAM
|
||||
|
||||
# The resource only creates/activates the swapfile if it is not already
|
||||
# active; an existing active swapfile is left untouched (size is NOT
|
||||
# reconciled to current RAM).
|
||||
swap_file swap_cfg["path"] do
|
||||
size size
|
||||
persist true
|
||||
swappiness swap_cfg["swappiness"] if swap_cfg["swappiness"]
|
||||
action :create
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
package %w(virtinst libvirt-daemon-system libvirt-clients)
|
||||
|
||||
# Required on legacy hosts (Ubuntu 20.04) to build the NoCloud seed ISO
|
||||
# via cloud-localds. Modern virt-install (>= 4.0.0, Ubuntu >= 22.04)
|
||||
# handles cloud-init natively via --cloud-init and does not need it.
|
||||
package "cloud-image-utils" if node["platform_version"].to_f < 22.04
|
||||
|
||||
directory "/var/lib/libvirt/images/base" do
|
||||
recursive true
|
||||
owner "libvirt-qemu"
|
||||
@@ -24,7 +29,10 @@ end
|
||||
template "/usr/local/sbin/create_vm" do
|
||||
source "create_vm.erb"
|
||||
mode "0750"
|
||||
variables base_image_path: node["kosmos_kvm"]["host"]["qemu_base_image"]["path"]
|
||||
variables(
|
||||
base_image_path: node["kosmos_kvm"]["host"]["qemu_base_image"]["path"],
|
||||
modern_virt_install: node["platform_version"].to_f >= 22.04
|
||||
)
|
||||
end
|
||||
|
||||
firewall_rule 'ssh-alt-port' do
|
||||
|
||||
@@ -64,6 +64,7 @@ EOS
|
||||
popd
|
||||
fi
|
||||
|
||||
<% if @modern_virt_install -%>
|
||||
virt-install \
|
||||
--name "$VMNAME" \
|
||||
--ram "$RAM" \
|
||||
@@ -83,3 +84,30 @@ virt-install \
|
||||
--autostart \
|
||||
--import \
|
||||
--cloud-init root-password-generate=off,disable=on,meta-data=$CIDATA_PATH/meta-data,user-data=$CIDATA_PATH/user-data
|
||||
<% else -%>
|
||||
# Legacy path for hosts running virt-install < 4.0.0 (e.g. Ubuntu 20.04,
|
||||
# virt-install 2.2.x). These versions predate the --osinfo/--cloud-init
|
||||
# options, so we build a NoCloud seed ISO from the same user-data and
|
||||
# meta-data files and attach it as a cdrom. The guest receives the
|
||||
# exact same cloud-init configuration as on modern hosts.
|
||||
cloud-localds "$CIDATA_PATH/seed.iso" "$CIDATA_PATH/user-data" "$CIDATA_PATH/meta-data"
|
||||
|
||||
virt-install \
|
||||
--name "$VMNAME" \
|
||||
--ram "$RAM" \
|
||||
--vcpus "$CPUS" \
|
||||
--cpu host \
|
||||
--arch x86_64 \
|
||||
--hvm \
|
||||
--virt-type kvm \
|
||||
--disk "$IMAGE_PATH" \
|
||||
--disk "$CIDATA_PATH/seed.iso,device=cdrom" \
|
||||
--boot hd \
|
||||
--network=bridge=virbr0,model=virtio \
|
||||
--graphics none \
|
||||
--serial pty \
|
||||
--console pty \
|
||||
--channel unix,mode=bind,path=/var/lib/libvirt/qemu/$VMNAME.guest_agent.0,target_type=virtio,name=org.qemu.guest_agent.0 \
|
||||
--autostart \
|
||||
--import
|
||||
<% end -%>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Recipe:: default
|
||||
#
|
||||
|
||||
node.normal['openresty']['log_formats']['json'] = '{"ip":"$remote_addr","time":"$time_local","host":"$host","method":"$request_method","uri":"$uri","status":$status,"size":$body_bytes_sent,"referer":"$http_referer","upstream_addr":"$upstream_addr","upstream_response_time":"$upstream_response_time","ua":"$http_user_agent"}'
|
||||
node.normal['openresty']['log_formats']['json'] = '{"ip":"$remote_addr","time":"$time_local","host":"$host","method":"$request_method","uri":"$uri","status":$status,"size":$body_bytes_sent,"referer":"$http_referer","upstream_addr":"$upstream_addr","upstream_response_time":"$upstream_response_time","upstream_cache_status":"$upstream_cache_status","ua":"$http_user_agent"}'
|
||||
|
||||
# Install openresty from official packages
|
||||
include_recipe 'openresty::apt_package'
|
||||
|
||||
@@ -11,23 +11,41 @@ groups:
|
||||
|
||||
- alert: NodeFilesystemAlmostOutOfSpace
|
||||
expr: |
|
||||
(node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*"}
|
||||
/ node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*"}) * 100 < 10
|
||||
(node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*",vm_host=~".+"}
|
||||
/ node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*",vm_host=~".+"}) * 100 < 10
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Filesystem has < 10% free space"
|
||||
summary: "VM filesystem has < 10% free space"
|
||||
|
||||
- alert: NodeFilesystemAlmostOutOfSpace
|
||||
expr: |
|
||||
(node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*"}
|
||||
/ node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*"}) * 100 < 5
|
||||
(node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*",vm_host=~".+"}
|
||||
/ node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*",vm_host=~".+"}) * 100 < 5
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Filesystem has < 5% free space"
|
||||
summary: "VM filesystem has < 5% free space"
|
||||
|
||||
- alert: NodeFilesystemAlmostOutOfSpace
|
||||
expr: |
|
||||
node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*",vm_host!~".+"} < 53687091200
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Host filesystem has < 50GB free space"
|
||||
|
||||
- alert: NodeFilesystemAlmostOutOfSpace
|
||||
expr: |
|
||||
node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs|overlay|squashfs|ramfs",mountpoint!~"/run.*|/var/lib/docker/.*",vm_host!~".+"} < 21474836480
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Host filesystem has < 20GB free space"
|
||||
|
||||
- alert: NodeFilesystemAlmostOutOfInodes
|
||||
expr: (node_filesystem_files_free / node_filesystem_files) * 100 < 10
|
||||
|
||||
@@ -89,6 +89,11 @@ jobs = node["kosmos_prometheus"]["jobs"].merge(
|
||||
"query" => "role:garage_node",
|
||||
"port" => 3903
|
||||
},
|
||||
# strfry relay metrics
|
||||
"strfry" => {
|
||||
"query" => "role:strfry",
|
||||
"port" => 7777
|
||||
},
|
||||
}.transform_values do |config|
|
||||
{
|
||||
"targets" => search(:node, config["query"]).map do |n|
|
||||
|
||||
@@ -31,6 +31,10 @@ server {
|
||||
proxy_pass http://_substr;
|
||||
}
|
||||
|
||||
location /metrics {
|
||||
return 404;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
+1
-1
Submodule site-cookbooks/strfry updated: 2c6e64d231...9c04b393ec
Reference in New Issue
Block a user