video-iac/jkctl

162 lines
4.3 KiB
Ruby
Executable File

#!/usr/bin/env ruby
require 'optparse'
require 'fileutils'
class Jkctl
def initialize
@options = { env: 'stg' }
@repo_root = File.expand_path('..', __dir__)
parse_options
end
def run
command = ARGV.shift
case command
when "k8s"
handle_k8s
when "db"
handle_db
else
show_help
end
end
private
def parse_options
OptionParser.new do |opts|
opts.banner = "Usage: jkctl [command] [options]"
opts.on("-s", "--stg", "Staging environment (default)") { @options[:env] = "stg" }
opts.on("-p", "--prd", "Production environment") { @options[:env] = "prd" }
end.parse!
end
def handle_k8s
subcommand = ARGV.shift
case subcommand
when "sync"
scope = ARGV.shift # infra or app
sync_k8s(scope)
when "status"
status_k8s
else
puts "Usage: jkctl k8s [sync|status] [infra|app]"
end
end
def handle_db
subcommand = ARGV.shift
case subcommand
when "backup"
backup_db
else
puts "Usage: jkctl db backup"
end
end
def sync_k8s(scope)
unless %w[infra app].include?(scope)
puts "Error: sync requires a scope (infra or app)"
exit 1
end
set_kubeconfig
namespace = scope == 'infra' ? 'jam-cloud-infra' : 'jam-cloud'
manifest_dir = File.join(@repo_root, 'video-iac', 'k8s', namespace)
puts "🚀 Syncing k8s #{scope} for #{@options[:env]}..."
# Ensure namespace exists
ns_file = File.join(manifest_dir, "namespace.yaml")
execute("kubectl apply -f #{ns_file}")
# Apply all yaml files in the directory (except namespace which we just did)
Dir.glob(File.join(manifest_dir, "*.yaml")).each do |file|
next if file.end_index?("namespace.yaml")
execute("kubectl apply -f #{file}")
end
# Rollout status for deployments in this scope
deployments = `kubectl get deployments -n #{namespace} -o name`.split("\n")
deployments.each do |deploy|
puts "Checking status for #{deploy}..."
execute("kubectl rollout status #{deploy} -n #{namespace}")
end
status_k8s(namespace)
end
def status_k8s(filter_ns = nil)
set_kubeconfig
namespaces = filter_ns ? [filter_ns] : %w[jam-cloud-infra jam-cloud]
puts "\n📊 K8s Status Summary (#{@options[:env]}):"
namespaces.each do |ns|
puts "\n--- Namespace: #{ns} ---"
# Check if namespace exists first
exists = system("kubectl get ns #{ns} > /dev/null 2>&1")
unless exists
puts "Namespace does not exist yet."
next
end
puts "Pods:"
# Get pod status, restarts, and age
output = `kubectl get pods -n #{ns} -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,RESTARTS:.status.containerStatuses[0].restartCount,AGE:.metadata.creationTimestamp`
puts output.empty? ? "No pods found." : output
puts "\nServices:"
output = `kubectl get svc -n #{ns} -o wide`
puts output.empty? ? "No services found." : output
end
end
def backup_db
puts "Backing up DB for #{@options[:env]} (Skipped per instruction)..."
end
def set_kubeconfig
if @options[:env] == 'stg'
# Extract path from activate-stg script
activate_script = File.join(Dir.home, 'bin', 'activate-stg')
if File.exist?(activate_script)
content = File.read(activate_script)
if content =~ /export KUBECONFIG=(.+)/
path = $1.strip.gsub('~', Dir.home)
ENV['KUBECONFIG'] = path
end
else
puts "Warning: #{activate_script} not found. Ensure KUBECONFIG is set manually."
end
else
# Placeholder for production kubeconfig logic
puts "Error: Production kubeconfig path not defined."
exit 1
end
end
def execute(cmd)
puts "Executing: #{cmd}"
system(cmd) || (puts "Command failed: #{cmd}"; exit 1)
end
def show_help
puts "Available commands:"
puts " k8s sync [infra|app] - Sync Kubernetes manifests"
puts " k8s status - Show status of k8s components"
puts " db backup - Perform database backup"
puts "\nOptions:"
puts " -s, --stg - Use staging environment (default)"
puts " -p, --prd - Use production environment"
end
end
# Support end_with? polyfill if needed or use end_with?
class String
def end_index?(suffix)
self.end_with?(suffix)
end
end
Jkctl.new.run