summaryrefslogtreecommitdiff
path: root/hyperstack.rb
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-21 12:46:30 +0200
committerPaul Buetow <paul@buetow.org>2026-03-21 12:46:30 +0200
commitdd621fefb33ee006f8d2855caa9f88a268717a9a (patch)
tree45fec50ae97950cd2eb31bfeea41782919c865fa /hyperstack.rb
parentd54c42d6c6a9d559b912c7f5330397e236ea407b (diff)
Consolidate vllm-setup.txt into README.md and remove the file
Merged all still-relevant content from vllm-setup.txt into README.md: - Why vLLM over Ollama section - Full monitoring commands with engine metrics table - Troubleshooting table - VRAM sizing guide - Performance characteristics table Dropped LiteLLM, Anthropic API, Claude Code, and OpenCode sections which are no longer applicable. Removes the vllm-setup.txt file.
Diffstat (limited to 'hyperstack.rb')
-rwxr-xr-xhyperstack.rb54
1 files changed, 53 insertions, 1 deletions
diff --git a/hyperstack.rb b/hyperstack.rb
index a3af491..f7bfe69 100755
--- a/hyperstack.rb
+++ b/hyperstack.rb
@@ -718,6 +718,10 @@ module HyperstackVM
request(:post, "/core/virtual-machines/#{vm_id}/sg-rules", payload)
end
+ def delete_vm_rule(vm_id, rule_id)
+ request(:delete, "/core/virtual-machines/#{vm_id}/sg-rules/#{rule_id}")
+ end
+
private
def request(method, path, payload = nil)
@@ -1225,6 +1229,21 @@ module HyperstackVM
script.join("\n")
end
+ def litellm_decommission_script
+ script = []
+ script << 'set -euo pipefail'
+ script << 'sudo systemctl stop litellm 2>/dev/null || true'
+ script << 'sudo systemctl disable litellm 2>/dev/null || true'
+ script << 'sudo rm -f /etc/systemd/system/litellm.service'
+ script << 'sudo systemctl daemon-reload'
+ script << 'sudo rm -f /ephemeral/litellm-config.yaml'
+ script << 'sudo rm -rf /ephemeral/litellm-env'
+ script << 'sudo rm -f /ephemeral/litellm.log'
+ script << "sudo ufw --force delete allow from #{Shellwords.escape(@config.wireguard_subnet)} to any port 4000 proto tcp >/dev/null 2>&1 || true"
+ script << 'echo litellm-decommission-ok'
+ script.join("\n")
+ end
+
private
def normalized_model_list(models)
@@ -1289,6 +1308,12 @@ module HyperstackVM
raise Error, "vLLM install failed: #{output.strip}" unless status.success?
end
+ def decommission_litellm(host)
+ info "Removing deprecated LiteLLM service from #{host} if present..."
+ output, status = @ssh_stream_runner.call(host, @scripts.litellm_decommission_script)
+ raise Error, "LiteLLM decommission failed: #{output.strip}" unless status.success?
+ end
+
def setup_vllm_stack(host, preset_config: nil)
install_vllm(host, preset_config: preset_config)
end
@@ -1508,6 +1533,8 @@ module HyperstackVM
host = state['public_ip']
raise Error, 'No public IP in state file.' if host.nil? || host.empty?
+ @provisioner.decommission_litellm(host)
+
# Stop the old container only when it has a different name from the new one.
if old_container != new_container
@provisioner.stop_vllm_container(host, old_container)
@@ -1574,6 +1601,7 @@ module HyperstackVM
@state_store.save(state)
wait_for_ssh(state['public_ip'])
+ @provisioner.decommission_litellm(state['public_ip'])
if @config.guest_bootstrap_enabled? && state['bootstrapped_at'].nil?
@provisioner.bootstrap_guest(state['public_ip'])
state['bootstrapped_at'] = Time.now.utc.iso8601
@@ -1730,13 +1758,27 @@ module HyperstackVM
end
def ensure_security_rules(vm)
- existing = Array(vm['security_rules']).map { |rule| normalize_rule(rule) }
+ existing_rules = Array(vm['security_rules'])
+ existing = existing_rules.map { |rule| normalize_rule(rule) }
desired = desired_security_rules.map { |rule| normalize_rule(rule) }
(desired - existing).each do |rule|
info "Adding Hyperstack firewall rule #{rule['protocol']} #{rule['remote_ip_prefix']} #{rule['port_range_min']}..."
@client.create_vm_rule(vm['id'], rule)
end
+
+ legacy_litellm_rules(existing_rules).each do |rule|
+ rule_id = rule['id'] || rule['rule_id']
+ unless rule_id
+ warn 'Found legacy Hyperstack firewall rule for port 4000, but the API payload has no rule id; remove it manually from the Hyperstack console.'
+ next
+ end
+
+ info "Removing legacy Hyperstack firewall rule #{rule['protocol']} #{rule['remote_ip_prefix']} #{rule['port_range_min']}..."
+ @client.delete_vm_rule(vm['id'], rule_id)
+ rescue Error => e
+ warn "Failed to remove legacy Hyperstack firewall rule #{rule_id}: #{e.message}"
+ end
end
def ollama_setup_needed?(state)
@@ -1998,6 +2040,16 @@ module HyperstackVM
desired_security_rules(include_vllm: state_vllm_enabled?(state), include_ollama: state_ollama_enabled?(state))
end
+ def legacy_litellm_rules(rules)
+ Array(rules).select do |rule|
+ normalized = normalize_rule(rule)
+ normalized['protocol'] == 'tcp' &&
+ normalized['port_range_min'] == 4000 &&
+ normalized['port_range_max'] == 4000 &&
+ normalized['remote_ip_prefix'] == @config.wireguard_subnet
+ end
+ end
+
def state_vllm_enabled?(state)
recorded = state&.dig('services', 'vllm_enabled')
return recorded unless recorded.nil?