7 Commits

Author SHA1 Message Date
01cdd000cb Update nodes 2026-03-27 14:30:46 +04:00
ea8e2de70a Merge pull request 'Use Ubuntu 22.04 for new VMs' (#521) from jammy_jellyfish into master
Reviewed-on: #521
2026-03-27 10:28:22 +00:00
8ad3674c4d Install libvirt CLI on KVM hosts 2026-03-27 14:27:28 +04:00
Râu Cao
25192ad3ce Use Ubuntu 22.04 for new VMs
Also, remove the custom config image generation and replace it with
`--cloud-init` options.
2026-03-26 20:35:30 +04:00
55b6e24f1e Merge pull request 'Configure Gitea commit signing with SSH key' (#623) from feature/237-gitea_ssh_signing into master
Reviewed-on: #623
Reviewed-by: Greg <greg@kosmos.org>
2026-03-19 13:27:55 +00:00
a23c7d536a Merge pull request 'Improve BTC price tracking script' (#624) from feature/btc_price_tracker into master
Reviewed-on: #624
2026-03-07 06:21:51 +00:00
d492cd18cc Improve BTC price tracking script
1. Robust API helper: Add make_request with retry logic for both
   GET (price data) and PUT (upload) requests
2. Arithmetic precision: Switch to awk for floating-point average
   calculation
3. Correct error handling: Updated get_price_data to return status
   codes and the main script to exit on failure
4. Safer JSON: Use jq to construct valid JSON payloads
5. Safety Flags: Add set -e/-o to fail fast on any command errors
2026-03-06 23:20:12 +04:00
10 changed files with 203 additions and 42 deletions

View File

@@ -1,4 +1,4 @@
{
"name": "garage-14",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqNY8AuaM4byhaTZacfRJ\nv/qyHxcDJOMX/ElF1H908spdbB2ZiLXHOH1Ucw1d+NV6/QUtWk+ikKFPpasnatD7\nmjE57noH+H47Rll0nD7oT+in+fOBDHF9R0P6/qyRSdJbJkHOh0iC0MG4LcUfv0AY\nnVBW5iLZSe/PC3+PvhCv7yrx3ikSs0mg1ZWppw0ka5Ek3ZCZp5FB4L6++GYWpM+1\n6YI0CjMoRcXsaEQsJWhxHXT8/KDhW0BR8woZUGm0/Yn4teLYJzioxRfBep3lbygx\nOIsDN9IJzo2zVTGPDZQLXhVemIhzaepqTC77ibH7F0gN/1vsQBc/qf7UhbwaF4rR\ndQIDAQAB\n-----END PUBLIC KEY-----\n"
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAypINv1zTZ7+pyT0iRhik\n0W70ASYADo7qK7QyE9/3nu2sUrP1IjoNFsv/ceKwicH7Fw2Ei1o+yKZlKn7zJzY7\n93YRZndF04VH2bmqy0uOWK0Bdat7gCld5bvS6FmRflg7g64LFb33/64QIVsVGHGL\nYF2TO//x79t9JKcQDa4h5MOWzJNTFuEcUGa0gJjMYpWGVHEJSgRuIgyhXmyIJJgY\nguj6ymTm5+3VS7NzoNy2fbTt1LRpHb5UWrCR15oiLZiDSMLMx0CcGOCmrhvODi4k\n0umw+2NPd1G50s9z7KVbTqybuQ65se2amRnkVcNfaBIU5qk9bVqcmhZlEozmBZCd\ndwIDAQAB\n-----END PUBLIC KEY-----\n"
}

4
clients/garage-15.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "garage-15",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy14sTt5gxVZi9C3KIEBu\nDyUgbb6jc3/GR22fNPTqV6uDHhxzhE2UsYwY/7yuA1RasdwHEOBWZaoC0Om5/Zmi\n8gn6//v1ILyLNaAcw+SQcxZkCN8Sk/0atRS9HYk1agE8Mvh72Fe2z3l+92VMefy7\nJwJUNNBTbnV2WVCchChoWnfhI7bkSLSHp0M2MO2pI+lkpSdmfkJSa5z9zihgxKO8\nXfvhryDCZNvfRVHhwc+ffpap0gLF0H9riGKE4FwLy4YqbuW1Tgm6bObb9bpOIw6Q\nVfH3kC/KMK5FlnxGmYtDkhRJ/wjGInRBk9WK/QOmjyd2FVxipEQmA4RdjlznRC9I\nrwIDAQAB\n-----END PUBLIC KEY-----\n"
}

4
clients/leo.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "leo",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFfQsJnREjbXTtpT6BVt\naBaUzRmCQi8Du0TzeUG0ENrY0p5Exqleye2rC6bJlB3PER1xr5zdtuXLgbcVumIb\nzroU5JPtFbQk7r/pj0atT+UEYzl16iuEpprQ/bug+f0nE514USr6YG4G+tlZ/jBI\nSHsCQF1P8ufXFLW0ewC7rdvBkgA+DwK14naRxS4jO5MSl4wmNTjs/jymTg508mQq\nf5tG52t8qFdgn9pRdBXmyTpPtwK7I4rZ+1Qn+1E5m4oQUZsxh8Ba1bGbKotVO7Ua\nYL1yCGx7zRRUvLLIdSMvlRXTJBUSQtQ8P4QUDWTY1Na2w3t9sulKg2Lwsw8tktvC\nCwIDAQAB\n-----END PUBLIC KEY-----\n"
}

View File

@@ -3,15 +3,15 @@
"chef_environment": "production",
"normal": {
"knife_zero": {
"host": "10.1.1.157"
"host": "10.1.1.151"
}
},
"automatic": {
"fqdn": "garage-14",
"os": "linux",
"os_version": "5.15.0-1059-kvm",
"os_version": "5.15.0-1095-kvm",
"hostname": "garage-14",
"ipaddress": "192.168.122.251",
"ipaddress": "192.168.122.36",
"roles": [
"base",
"kvm_guest",
@@ -30,6 +30,7 @@
"timezone_iii::debian",
"ntp::default",
"ntp::apparmor",
"kosmos-base::journald_conf",
"kosmos-base::systemd_emails",
"apt::unattended-upgrades",
"kosmos-base::firewall",
@@ -46,13 +47,13 @@
"cloud": null,
"chef_packages": {
"chef": {
"version": "18.8.54",
"chef_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/chef-18.8.54/lib",
"version": "18.10.17",
"chef_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/chef-18.10.17/lib",
"chef_effortless": null
},
"ohai": {
"version": "18.2.8",
"ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.2.8/lib/ohai"
"version": "18.2.13",
"ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.2.13/lib/ohai"
}
}
},

65
nodes/garage-15.json Normal file
View File

@@ -0,0 +1,65 @@
{
"name": "garage-15",
"chef_environment": "production",
"normal": {
"knife_zero": {
"host": "10.1.1.82"
}
},
"automatic": {
"fqdn": "garage-15",
"os": "linux",
"os_version": "5.15.0-1095-kvm",
"hostname": "garage-15",
"ipaddress": "192.168.122.57",
"roles": [
"base",
"kvm_guest",
"garage_node"
],
"recipes": [
"kosmos-base",
"kosmos-base::default",
"kosmos_kvm::guest",
"kosmos_garage",
"kosmos_garage::default",
"kosmos_garage::firewall_rpc",
"kosmos_garage::firewall_apis",
"apt::default",
"timezone_iii::default",
"timezone_iii::debian",
"ntp::default",
"ntp::apparmor",
"kosmos-base::journald_conf",
"kosmos-base::systemd_emails",
"apt::unattended-upgrades",
"kosmos-base::firewall",
"kosmos-postfix::default",
"postfix::default",
"postfix::_common",
"postfix::_attributes",
"postfix::sasl_auth",
"hostname::default",
"firewall::default"
],
"platform": "ubuntu",
"platform_version": "22.04",
"cloud": null,
"chef_packages": {
"chef": {
"version": "18.10.17",
"chef_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/chef-18.10.17/lib",
"chef_effortless": null
},
"ohai": {
"version": "18.2.13",
"ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.2.13/lib/ohai"
}
}
},
"run_list": [
"role[base]",
"role[kvm_guest]",
"role[garage_node]"
]
}

56
nodes/leo.json Normal file
View File

@@ -0,0 +1,56 @@
{
"name": "leo",
"normal": {
"knife_zero": {
"host": "leo.kosmos.org"
}
},
"automatic": {
"fqdn": "leo",
"os": "linux",
"os_version": "5.15.0-164-generic",
"hostname": "leo",
"ipaddress": "5.9.81.116",
"roles": [
"base"
],
"recipes": [
"kosmos-base",
"kosmos-base::default",
"kosmos_kvm::host",
"apt::default",
"timezone_iii::default",
"timezone_iii::debian",
"ntp::default",
"ntp::apparmor",
"kosmos-base::journald_conf",
"kosmos-base::systemd_emails",
"apt::unattended-upgrades",
"kosmos-base::firewall",
"kosmos-postfix::default",
"postfix::default",
"postfix::_common",
"postfix::_attributes",
"postfix::sasl_auth",
"hostname::default"
],
"platform": "ubuntu",
"platform_version": "22.04",
"cloud": null,
"chef_packages": {
"chef": {
"version": "18.10.17",
"chef_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/chef-18.10.17/lib",
"chef_effortless": null
},
"ohai": {
"version": "18.2.13",
"ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.2.13/lib/ohai"
}
}
},
"run_list": [
"role[base]",
"recipe[kosmos_kvm::host]"
]
}

View File

@@ -1,49 +1,86 @@
#!/bin/bash
set -e
set -o pipefail
# Calculate yesterday's date in YYYY-MM-DD format
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
echo "Starting price tracking for $YESTERDAY" >&2
# Helper function to perform HTTP requests with retries
# Usage: make_request <retries> <method> <url> [data] [header1] [header2] ...
make_request() {
local retries=$1
local method=$2
local url=$3
local data=$4
shift 4
local headers=("$@")
local count=0
local wait_time=3
local response
while [ "$count" -lt "$retries" ]; do
local curl_opts=(-s -S -f -X "$method")
if [ -n "$data" ]; then
curl_opts+=(-d "$data")
fi
for h in "${headers[@]}"; do
curl_opts+=(-H "$h")
done
if response=$(curl "${curl_opts[@]}" "$url"); then
echo "$response"
return 0
fi
echo "Request to $url failed (Attempt $((count+1))/$retries). Retrying in ${wait_time}s..." >&2
sleep "$wait_time"
count=$((count + 1))
done
echo "ERROR: Request to $url failed after $retries attempts" >&2
return 1
}
# Fetch and process rates for a fiat currency
get_price_data() {
local currency=$1
local data avg open24 last
data=$(curl -s "https://www.bitstamp.net/api/v2/ticker/btc${currency,,}/")
if [ $? -eq 0 ] && [ ! -z "$data" ]; then
if data=$(make_request 3 "GET" "https://www.bitstamp.net/api/v2/ticker/btc${currency,,}/" ""); then
echo "Successfully retrieved ${currency} price data" >&2
open24=$(echo "$data" | jq -r '.open_24')
last=$(echo "$data" | jq -r '.last')
avg=$(( (${open24%.*} + ${last%.*}) / 2 ))
avg=$(echo "$open24 $last" | awk '{printf "%.0f", ($1 + $2) / 2}')
echo $avg
else
echo "ERROR: Failed to retrieve ${currency} price data" >&2
exit 1
return 1
fi
}
# Get price data for each currency
usd_avg=$(get_price_data "USD")
eur_avg=$(get_price_data "EUR")
gbp_avg=$(get_price_data "GBP")
usd_avg=$(get_price_data "USD") || exit 1
eur_avg=$(get_price_data "EUR") || exit 1
gbp_avg=$(get_price_data "GBP") || exit 1
# Create JSON
json="{\"EUR\":$eur_avg,\"USD\":$usd_avg,\"GBP\":$gbp_avg}"
json=$(jq -n \
--argjson eur "$eur_avg" \
--argjson usd "$usd_avg" \
--argjson gbp "$gbp_avg" \
'{"EUR": $eur, "USD": $usd, "GBP": $gbp}')
echo "Rates: $json" >&2
# PUT in remote storage
response=$(curl -X PUT \
-H "Authorization: Bearer $RS_AUTH" \
-H "Content-Type: application/json" \
-d "$json" \
-w "%{http_code}" \
-s \
-o /dev/null \
"<%= @rs_base_url %>/$YESTERDAY")
if [ "$response" -eq 200 ] || [ "$response" -eq 201 ]; then
if make_request 3 "PUT" "<%= @rs_base_url %>/$YESTERDAY" "$json" \
"Authorization: Bearer $RS_AUTH" \
"Content-Type: application/json" > /dev/null; then
echo "Successfully uploaded price data" >&2
else
echo "ERROR: Failed to upload price data. HTTP status: $response" >&2
echo "ERROR: Failed to upload price data" >&2
exit 1
fi

View File

@@ -1,9 +1,9 @@
release = "20240514"
release = "20260320"
img_filename = "ubuntu-22.04-server-cloudimg-amd64-disk-kvm"
node.default["kosmos_kvm"]["host"]["qemu_base_image"] = {
"url" => "https://cloud-images.ubuntu.com/releases/jammy/release-#{release}/#{img_filename}.img",
"checksum" => "2e7698b3ebd7caead06b08bd3ece241e6ce294a6db01f92ea12bcb56d6972c3f",
"checksum" => "f7173eb7137b4f0ebeaea8fffe68ecdab1e3c787bde1fd8dfdf27103554332b3",
"path" => "/var/lib/libvirt/images/base/#{img_filename}-#{release}.qcow2"
}

View File

@@ -3,7 +3,7 @@
# Recipe:: host
#
package %w(virtinst libvirt-daemon-system)
package %w(virtinst libvirt-daemon-system libvirt-clients)
directory "/var/lib/libvirt/images/base" do
recursive true

View File

@@ -17,7 +17,7 @@ DISKSIZE=${4:-10} # 10GB default
# Directory where image files will be stored
IMAGE_DIR=/var/lib/libvirt/images
IMAGE_PATH=$IMAGE_DIR/${VMNAME}.qcow2
CIDATA_PATH=${IMAGE_DIR}/cidata-${VMNAME}.iso
CIDATA_PATH=${IMAGE_DIR}/${VMNAME}-cloudinit
BASE_FILE=<%= @base_image_path %>
# Create the VM image if it does not already exist
@@ -38,9 +38,8 @@ qemu-img info "$IMAGE_PATH"
# Check if the cloud-init metadata file exists
# if not, generate it
if [ ! -r $CIDATA_PATH ]; then
pushd $(dirname $CIDATA_PATH)
mkdir -p $VMNAME
cd $VMNAME
mkdir -p $CIDATA_PATH
pushd $CIDATA_PATH
cat > user-data <<-EOS
#cloud-config
@@ -62,25 +61,19 @@ instance-id: $VMNAME
local-hostname: $VMNAME
EOS
genisoimage -output "$CIDATA_PATH" -volid cidata -joliet -rock user-data meta-data
chown libvirt-qemu:kvm "$CIDATA_PATH"
chmod 600 "$CIDATA_PATH"
popd
fi
# setting --os-variant to ubuntu20.04 and ubuntu18.04 breaks SSH and networking
virt-install \
--name "$VMNAME" \
--ram "$RAM" \
--vcpus "$CPUS" \
--cpu host \
--arch x86_64 \
--os-type linux \
--os-variant ubuntu16.04 \
--osinfo detect=on,name=ubuntujammy \
--hvm \
--virt-type kvm \
--disk "$IMAGE_PATH" \
--cdrom "$CIDATA_PATH" \
--boot hd \
--network=bridge=virbr0,model=virtio \
--graphics none \
@@ -88,4 +81,5 @@ virt-install \
--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
--import \
--cloud-init root-password-generate=off,disable=on,meta-data=$CIDATA_PATH/meta-data,user-data=$CIDATA_PATH/user-data