kitsune-kit 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72a0142a3c968422bbf176e7c9166607d0cdb77bb98ad7dea178465d432be628
4
- data.tar.gz: 3231de17dda946adabd4f1ed6cc3811a03bcf42e61ffce251532871cabdb51c6
3
+ metadata.gz: 56c28afb6d454bee7e7751b75bfa3c131183fed868f158a324de8d804e54dab3
4
+ data.tar.gz: 2ca2b272f8bcfc12a92736aba334f4d70139cf0f5e3988a65c419ff52c644e6c
5
5
  SHA512:
6
- metadata.gz: 0f29ff9c74c0b2bfd9c224077ef958e661f13795e59ffae3d4f81f23181a38546cbf192056a35d1888cbfa55606d067cd1ae2f615c5c988ef38e291ddd02a359
7
- data.tar.gz: 4186a5914e1e8746691d01c2432591dc51e2b395ccd3c5b08b3bf95327d2be175fd36cf55eece21cc0872ad548789b6ba53a12a7644432f277df18aadabe21d0
6
+ metadata.gz: f90bb7fec9592df584b627f0dc7a66df6da61ce70b4c2cdf4028990db77c53a6f5e965b456d1edb031551ca9f9510302261c24579e88a5b231b27e934de024f1
7
+ data.tar.gz: d423fab92de78e0c2468bbf2d33eac4d1ea9115253f41dbf6e5f56a39e9dded302b66672753e9b02d130cf91a8acc0f203fd393dcdfd4e006798b361d94a6f4f
@@ -1,4 +1,4 @@
1
- # DigitalOcean Droplet defaults
1
+ # DigitalOcean Droplet
2
2
  DO_API_TOKEN=
3
3
  DROPLET_NAME=
4
4
  REGION=
@@ -6,12 +6,17 @@ SIZE=
6
6
  IMAGE=
7
7
  SSH_KEY_ID=
8
8
  TAG_NAME=
9
+ ENABLE_DO_METRICS=true
9
10
 
10
- # SSH configuration
11
+ # SSH
11
12
  SSH_KEY_PATH=
12
13
  # SSH_PORT=22 (optional)
13
14
 
14
- # PostgreSQL Docker defaults
15
+ # System
16
+ SWAP_SIZE_GB=2
17
+ DISABLE_SWAP=false
18
+
19
+ # PostgreSQL Docker
15
20
  POSTGRES_DB=
16
21
  POSTGRES_USER=
17
22
  POSTGRES_PASSWORD=
@@ -8,6 +8,9 @@ services:
8
8
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
9
9
  ports:
10
10
  - "${POSTGRES_PORT:-5432}:5432"
11
+ command: postgres -c listen_addresses='*'
12
+ networks:
13
+ - private
11
14
  volumes:
12
15
  - pgdata:/var/lib/postgresql/data
13
16
  healthcheck:
@@ -18,3 +21,7 @@ services:
18
21
 
19
22
  volumes:
20
23
  pgdata:
24
+
25
+ networks:
26
+ private:
27
+ driver: bridge
@@ -7,6 +7,8 @@ require_relative "commands/provision"
7
7
  require_relative "commands/setup_user"
8
8
  require_relative "commands/setup_firewall"
9
9
  require_relative "commands/setup_unattended"
10
+ require_relative "commands/setup_swap"
11
+ require_relative "commands/setup_do_metrics"
10
12
  require_relative "commands/bootstrap"
11
13
  require_relative "commands/setup_docker_prereqs"
12
14
  require_relative "commands/install_docker_engine"
@@ -43,6 +45,12 @@ module Kitsune
43
45
  desc "setup_unattended SUBCOMMAND", "Configure or rollback unattended-upgrades"
44
46
  subcommand "setup_unattended", Kitsune::Kit::Commands::SetupUnattended
45
47
 
48
+ desc "setup_swap SUBCOMMAND", "Configure or rollback swap memory"
49
+ subcommand "setup_swap", Kitsune::Kit::Commands::SetupSwap
50
+
51
+ desc "setup_do_metrics SUBCOMMAND", "Install or rollback DigitalOcean Metrics Agent"
52
+ subcommand "setup_do_metrics", Kitsune::Kit::Commands::SetupDoMetrics
53
+
46
54
  desc "bootstrap SUBCOMMAND", "Run full server setup or rollback"
47
55
  subcommand "bootstrap", Kitsune::Kit::Commands::Bootstrap
48
56
 
@@ -42,6 +42,8 @@ module Kitsune
42
42
  run_cli("setup_user create", droplet_ip, filled_options)
43
43
  run_cli("setup_firewall create", droplet_ip, filled_options)
44
44
  run_cli("setup_unattended create", droplet_ip, filled_options)
45
+ run_cli("setup_swap create", droplet_ip, filled_options)
46
+ run_cli("setup_do_metrics create", droplet_ip, filled_options)
45
47
  end
46
48
 
47
49
  def rollback_sequence(filled_options)
@@ -60,6 +62,8 @@ module Kitsune
60
62
  droplet_ip = provisioner.send(:public_ip, droplet)
61
63
  say "→ Using Droplet IP: #{droplet_ip}", :cyan
62
64
 
65
+ run_cli("setup_do_metrics rollback", droplet_ip, filled_options)
66
+
63
67
  if ssh_accessible?(droplet_ip, filled_options)
64
68
  run_cli("setup_unattended rollback", droplet_ip, filled_options)
65
69
  run_cli("setup_firewall rollback", droplet_ip, filled_options)
@@ -67,6 +71,7 @@ module Kitsune
67
71
  say "⏭️ Skipping unattended-upgrades and firewall rollback (no deploy user)", :yellow
68
72
  end
69
73
 
74
+ run_cli("setup_swap rollback", droplet_ip, filled_options)
70
75
  run_cli("setup_user rollback", droplet_ip, filled_options)
71
76
 
72
77
  unless filled_options[:keep_server]
@@ -0,0 +1,123 @@
1
+ require "thor"
2
+ require "net/ssh"
3
+ require_relative "../defaults"
4
+ require_relative "../options_builder"
5
+
6
+ module Kitsune
7
+ module Kit
8
+ module Commands
9
+ class SetupDoMetrics < Thor
10
+ namespace "setup_do_metrics"
11
+
12
+ class_option :server_ip, aliases: "-s", required: true, desc: "Server IP address"
13
+ class_option :ssh_port, aliases: "-p", desc: "SSH port"
14
+ class_option :ssh_key_path, aliases: "-k", desc: "SSH private key path"
15
+
16
+ desc "create", "Install and enable the DigitalOcean Metrics Agent"
17
+ def create
18
+ unless Kitsune::Kit::Defaults.metrics[:enable_do_metrics]
19
+ say "⚠️ DigitalOcean Metrics Agent setup is disabled via ENABLE_DO_METRICS=false", :yellow
20
+ return
21
+ end
22
+
23
+ filled_options = Kitsune::Kit::OptionsBuilder.build(
24
+ options,
25
+ required: [:server_ip],
26
+ defaults: Kitsune::Kit::Defaults.ssh
27
+ )
28
+
29
+ with_ssh(filled_options) do |ssh|
30
+ install_agent(ssh)
31
+ end
32
+ end
33
+
34
+ desc "rollback", "Uninstall the DigitalOcean Metrics Agent"
35
+ def rollback
36
+ filled_options = Kitsune::Kit::OptionsBuilder.build(
37
+ options,
38
+ required: [:server_ip],
39
+ defaults: Kitsune::Kit::Defaults.ssh
40
+ )
41
+
42
+ with_ssh(filled_options) do |ssh|
43
+ uninstall_agent(ssh)
44
+ end
45
+ end
46
+
47
+ no_commands do
48
+ def with_ssh(filled_options)
49
+ Net::SSH.start(
50
+ filled_options[:server_ip],
51
+ "deploy",
52
+ port: filled_options[:ssh_port],
53
+ keys: [File.expand_path(filled_options[:ssh_key_path])],
54
+ non_interactive: true,
55
+ timeout: 5
56
+ ) do |ssh|
57
+ yield ssh
58
+ end
59
+ end
60
+
61
+ def install_agent(ssh)
62
+ marker = "/usr/local/backups/setup_do_metrics.after"
63
+
64
+ script = <<~BASH
65
+ set -e
66
+ sudo mkdir -p /usr/local/backups
67
+
68
+ if [ -f "#{marker}" ]; then
69
+ echo "🔁 Metrics Agent already installed, skipping."
70
+ exit 0
71
+ fi
72
+
73
+ echo "✍🏻 Installing DigitalOcean Metrics Agent..."
74
+ curl -sSL https://repos.insights.digitalocean.com/install.sh | sudo bash
75
+
76
+ sudo touch "#{marker}"
77
+ echo "✅ Metrics Agent installed"
78
+
79
+ ps aux | grep do-agent | grep -v grep || echo "⚠️ do-agent process not found"
80
+ BASH
81
+
82
+ say ssh.exec!(script)
83
+ end
84
+
85
+ def uninstall_agent(ssh)
86
+ marker = "/usr/local/backups/setup_do_metrics.after"
87
+
88
+ script = <<~BASH
89
+ set -e
90
+
91
+ if [ ! -f "#{marker}" ]; then
92
+ echo "💡 No marker for metrics agent found. Skipping rollback."
93
+ exit 0
94
+ fi
95
+
96
+ echo "🧹 Uninstalling DigitalOcean Metrics Agent..."
97
+
98
+ if dpkg -l | grep -q do-agent; then
99
+ echo "📦 Removing do-agent package..."
100
+ sudo apt-get remove --purge -y do-agent
101
+ else
102
+ echo "💡 do-agent is not installed, skipping package removal."
103
+ fi
104
+
105
+ if systemctl list-unit-files | grep -q do-agent.service; then
106
+ echo "✍🏻 Stopping do-agent service..."
107
+ sudo systemctl stop do-agent || true
108
+ sudo systemctl disable do-agent || true
109
+ else
110
+ echo "💡 do-agent.service not found in systemd, skipping stop/disable"
111
+ fi
112
+
113
+ sudo rm -f "#{marker}"
114
+ echo "✅ Metrics Agent removed"
115
+ BASH
116
+
117
+ say ssh.exec!(script)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -46,6 +46,8 @@ module Kitsune
46
46
 
47
47
  desc "rollback", "Remove PostgreSQL Docker setup from remote server"
48
48
  def rollback
49
+ postgres_defaults = Kitsune::Kit::Defaults.postgres
50
+
49
51
  filled_options = Kitsune::Kit::OptionsBuilder.build(
50
52
  options,
51
53
  required: [:server_ip],
@@ -53,7 +55,7 @@ module Kitsune
53
55
  )
54
56
 
55
57
  with_ssh_connection(filled_options) do |ssh|
56
- perform_rollback(ssh)
58
+ perform_rollback(ssh, postgres_defaults)
57
59
  end
58
60
  end
59
61
 
@@ -184,7 +186,7 @@ module Kitsune
184
186
  if ! sudo ufw status | grep -q "#{postgres_defaults[:postgres_port]}"; then
185
187
  sudo ufw allow #{postgres_defaults[:postgres_port]}
186
188
  else
187
- echo "🔸 Port #{postgres_defaults[:postgres_port]} is already allowed in ufw."
189
+ echo "💡 Port #{postgres_defaults[:postgres_port]} is already allowed in ufw."
188
190
  fi
189
191
  else
190
192
  echo "⚠️ ufw not found. Skipping firewall configuration."
@@ -193,7 +195,7 @@ module Kitsune
193
195
  ssh.exec!(firewall)
194
196
  end
195
197
 
196
- def perform_rollback(ssh)
198
+ def perform_rollback(ssh, postgres_defaults)
197
199
  output = ssh.exec! <<~EOH
198
200
  set -e
199
201
 
@@ -213,7 +215,7 @@ module Kitsune
213
215
 
214
216
  if command -v ufw >/dev/null; then
215
217
  echo "🛡️ Removing PostgreSQL port from firewall..."
216
- sudo ufw delete allow 5432 || true
218
+ sudo ufw delete allow #{postgres_defaults[:postgres_port]} || true
217
219
  fi
218
220
  else
219
221
  echo "💡 Nothing to rollback"
@@ -0,0 +1,151 @@
1
+ require "thor"
2
+ require "net/ssh"
3
+ require_relative "../defaults"
4
+ require_relative "../options_builder"
5
+
6
+ module Kitsune
7
+ module Kit
8
+ module Commands
9
+ class SetupSwap < Thor
10
+ namespace "setup_swap"
11
+
12
+ class_option :server_ip, aliases: "-s", required: true, desc: "Server IP address"
13
+ class_option :ssh_port, aliases: "-p", desc: "SSH port"
14
+ class_option :ssh_key_path, aliases: "-k", desc: "SSH private key path"
15
+ class_option :size_gb, type: :numeric, desc: "Swap size in GB"
16
+ class_option :swappiness, type: :numeric, desc: "vm.swappiness value (0-100)"
17
+
18
+ desc "create", "Create and activate a swap file on the remote server"
19
+ def create
20
+ if Kitsune::Kit::Defaults.system[:disable_swap]
21
+ say "⚠️ Swap setup is disabled via DISABLE_SWAP=true", :yellow
22
+ return
23
+ end
24
+
25
+ filled_options = Kitsune::Kit::OptionsBuilder.build(
26
+ options,
27
+ required: [:server_ip],
28
+ defaults: Kitsune::Kit::Defaults.system.merge(Kitsune::Kit::Defaults.ssh)
29
+ )
30
+
31
+ with_ssh_connection(filled_options) do |ssh|
32
+ perform_setup(ssh, filled_options)
33
+ end
34
+ end
35
+
36
+ desc "rollback", "Disable and remove swap file from remote server"
37
+ def rollback
38
+ filled_options = Kitsune::Kit::OptionsBuilder.build(
39
+ options,
40
+ required: [:server_ip],
41
+ defaults: Kitsune::Kit::Defaults.system.merge(Kitsune::Kit::Defaults.ssh)
42
+ )
43
+
44
+ with_ssh_connection(filled_options) do |ssh|
45
+ perform_rollback(ssh)
46
+ end
47
+ end
48
+
49
+ no_commands do
50
+ def with_ssh_connection(filled)
51
+ server = filled[:server_ip]
52
+ port = filled[:ssh_port]
53
+ key = File.expand_path(filled[:ssh_key_path])
54
+
55
+ say "🔑 Connecting as deploy@#{server}:#{port}", :green
56
+ Net::SSH.start(server, "deploy", port: port, keys: [key], non_interactive: true, timeout: 5) do |ssh|
57
+ yield ssh
58
+ end
59
+ end
60
+
61
+ def perform_setup(ssh, filled_options)
62
+ size_gb = filled_options[:swap_size_gb].to_i
63
+ swappiness = filled_options[:swap_swappiness].to_i
64
+
65
+ abort "❌ Invalid swap size" if size_gb <= 0
66
+
67
+ script = <<~EOH
68
+ set -e
69
+
70
+ BACKUP_DIR="/usr/local/backups"
71
+ MARKER_FILE="${BACKUP_DIR}/setup_swap.after"
72
+ SWAPPINESS_BEFORE_FILE="${BACKUP_DIR}/setup_swap.swappiness.before"
73
+
74
+ if [ -f "$MARKER_FILE" ]; then
75
+ echo "🔁 Swap already set up, skipping."
76
+ exit 0
77
+ fi
78
+
79
+ SWAPFILE="/swapfile"
80
+ SIZE_GB=#{size_gb}
81
+ SIZE_BYTES=$((SIZE_GB * 1024 * 1024 * 1024))
82
+
83
+ echo "📝 Creating ${SIZE_GB}GB swap file..."
84
+ sudo fallocate -l ${SIZE_BYTES} ${SWAPFILE}
85
+ sudo chmod 600 ${SWAPFILE}
86
+ sudo mkswap ${SWAPFILE}
87
+ sudo swapon ${SWAPFILE}
88
+ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
89
+
90
+ # Backup swappiness if not already backed up
91
+ if [ ! -f "$SWAPPINESS_BEFORE_FILE" ]; then
92
+ CURRENT=$(cat /proc/sys/vm/swappiness)
93
+ echo "$CURRENT" | sudo tee "$SWAPPINESS_BEFORE_FILE"
94
+ echo "✍🏻 Backed up vm.swappiness: $CURRENT"
95
+ fi
96
+
97
+ echo "🛠️ Setting vm.swappiness=#{swappiness}"
98
+ sudo sysctl vm.swappiness=#{swappiness}
99
+ echo "vm.swappiness=#{swappiness}" | sudo tee -a /etc/sysctl.conf
100
+
101
+ sudo mkdir -p "$BACKUP_DIR"
102
+ sudo touch "$MARKER_FILE"
103
+
104
+ echo "✅ Swap file created and swappiness set"
105
+ free -h
106
+ EOH
107
+
108
+ say ssh.exec!(script)
109
+ end
110
+
111
+ def perform_rollback(ssh)
112
+ script = <<~EOH
113
+ set -e
114
+
115
+ BACKUP_DIR="/usr/local/backups"
116
+ MARKER_FILE="${BACKUP_DIR}/setup_swap.after"
117
+ SWAPPINESS_BEFORE_FILE="${BACKUP_DIR}/setup_swap.swappiness.before"
118
+
119
+ if [ ! -f "$MARKER_FILE" ]; then
120
+ echo "💡 No swap marker found, skipping rollback."
121
+ exit 0
122
+ fi
123
+
124
+ echo "🧹 Removing swap..."
125
+ sudo swapoff /swapfile || true
126
+ sudo rm -f /swapfile
127
+ sudo sed -i '/\\/swapfile none swap sw 0 0/d' /etc/fstab
128
+ sudo rm -f "$MARKER_FILE"
129
+
130
+ if [ -f "$SWAPPINESS_BEFORE_FILE" ]; then
131
+ ORIGINAL=$(cat "$SWAPPINESS_BEFORE_FILE")
132
+ echo "🔁 Restoring vm.swappiness: $ORIGINAL"
133
+ sudo sysctl vm.swappiness=$ORIGINAL
134
+ sudo sed -i '/vm.swappiness=/d' /etc/sysctl.conf
135
+ echo "vm.swappiness=$ORIGINAL" | sudo tee -a /etc/sysctl.conf
136
+ sudo rm -f "$SWAPPINESS_BEFORE_FILE"
137
+ else
138
+ echo "💡 No swappiness backup found, skipping restore."
139
+ fi
140
+
141
+ echo "✅ Swap rollback completed"
142
+ free -h
143
+ EOH
144
+
145
+ say ssh.exec!(script)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -22,6 +22,16 @@ module Kitsune
22
22
  image: "postgres:15"
23
23
  }.freeze
24
24
 
25
+ SYSTEM = {
26
+ swap_size_gb: 2,
27
+ swap_swappiness: 10,
28
+ disable_swap: false
29
+ }.freeze
30
+
31
+ METRICS = {
32
+ enable_do_metrics: true
33
+ }.freeze
34
+
25
35
  def self.infra
26
36
  {
27
37
  droplet_name: ENV.fetch('DROPLET_NAME', DROPLET[:droplet_name]),
@@ -51,6 +61,20 @@ module Kitsune
51
61
  postgres_image: ENV.fetch('POSTGRES_IMAGE', POSTGRES[:image])
52
62
  }
53
63
  end
64
+
65
+ def self.system
66
+ {
67
+ swap_size_gb: ENV.fetch("SWAP_SIZE_GB", SYSTEM[:swap_size_gb]).to_i,
68
+ swap_swappiness: ENV.fetch("SWAP_SWAPPINESS", SYSTEM[:swap_swappiness]).to_i,
69
+ disable_swap: ENV.fetch("DISABLE_SWAP", SYSTEM[:disable_swap].to_s) == "true"
70
+ }
71
+ end
72
+
73
+ def self.metrics
74
+ {
75
+ enable_do_metrics: ENV.fetch("ENABLE_DO_METRICS", METRICS[:enable_do_metrics].to_s) == "true"
76
+ }
77
+ end
54
78
  end
55
79
  end
56
80
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kitsune
4
4
  module Kit
5
- VERSION = "0.1.1"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitsune-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Omar Herrera
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-01 00:00:00.000000000 Z
11
+ date: 2025-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-ssh
@@ -193,9 +193,11 @@ files:
193
193
  - lib/kitsune/kit/commands/install_docker_engine.rb
194
194
  - lib/kitsune/kit/commands/postinstall_docker.rb
195
195
  - lib/kitsune/kit/commands/provision.rb
196
+ - lib/kitsune/kit/commands/setup_do_metrics.rb
196
197
  - lib/kitsune/kit/commands/setup_docker_prereqs.rb
197
198
  - lib/kitsune/kit/commands/setup_firewall.rb
198
199
  - lib/kitsune/kit/commands/setup_postgres_docker.rb
200
+ - lib/kitsune/kit/commands/setup_swap.rb
199
201
  - lib/kitsune/kit/commands/setup_unattended.rb
200
202
  - lib/kitsune/kit/commands/setup_user.rb
201
203
  - lib/kitsune/kit/commands/switch_env.rb