#!/usr/bin/env ruby require_relative "../lib/harbr" class HarbrCLI < Thor no_commands do def display_containers_table(containers) return puts "No containers available." if containers.empty? # Define headers based on Container attributes headers = ["Name", "Host Header", "IP", "Port"] rows = containers.map do |container| [container.name, container.host_header, container.ip.nil? ? "127.0.0.1" : container.ip, container.port] end table = ::Terminal::Table.new(headings: headers, rows: rows) puts "" puts "Harbr Containers" puts "" puts table puts "" end def check_and_create_directory(path) unless Dir.exist?(path) puts "Creating directory: #{path}" FileUtils.mkdir_p(path) end end def command_exists?(command) system("command -v #{command} > /dev/null 2>&1") end def write_to_file(path, contents) dirname = File.dirname(path) FileUtils.mkdir_p(dirname) unless File.directory?(dirname) File.write(path, contents) end def install_with_snap(package) puts "Installing #{package} using Snap..." system("sudo snap install #{package}") or raise "Failed to install #{package}" end def install_with_apt(package) puts "Installing #{package} using apt..." system("sudo apt install #{package}") or raise "Failed to install #{package}" end def create_traefik_config(containers) config = { "http" => { "routers" => {}, "services" => {} } } containers.each do |container| container.ip = "127.0.0.1" name = container.name.tr(".", "-") router_key = "#{name}-router-secure" config["http"]["routers"][router_key] = { "rule" => "Host(`#{container.host_header}`)", "service" => "#{name}-service", "entryPoints" => ["https"], "tls" => { "certResolver" => "myresolver" } } config["http"]["services"]["#{name}-service"] = { "loadBalancer" => { "servers" => [{"url" => "http://#{container.ip}:#{container.port}"}] } } end File.write("/etc/traefik/harbr.toml", TomlRB.dump(config)) puts "Traefik configuration written to /etc/traefik/harbr.toml" end end desc "destroy", "Destroy a container and remove all traces" def destroy(name) puts "Destroying container: #{name}" container_repo = Harbr::Container::Repository.new ["live.#{name}", "next.#{name}", name].each do |container_name| container_repo.get_by_name(container_name).each do |container| `port release #{container.port}` puts "released port #{container.port} successfully." container_repo.delete(container) end `rm -rf /etc/service/#{container_name}` `rm -rf /etc/sv/harbr/#{container_name}` puts "Container #{container_name} destroyed successfully." end `rm -rf /var/harbr/containers/#{name}` `rm -rf /var/log/harbr/#{name}` create_traefik_config(container_repo.all) end desc "logs", "Show logs" def logs exec "tail -f /var/log/harbr/current" end desc "peek CONTAINER", "Peek in a given container" method_option :live, type: :boolean, aliases: "-l", desc: "Process in live mode" method_option :next, type: :boolean, default: true, aliases: "-n", desc: "Process in next mode" def peek(container) container_repo = Harbr::Container::Repository.new container = container_repo.find_by_name(container) if container exec "tail -f /var/log/harbr/#{container.name}/live/current" if options[:live] exec "tail -f /var/log/harbr/#{container.name}/next/current" if options[:next] else puts "Container not recognized" end end desc "setup", "Set up Harbr environment" def setup # Check and create /var/harbr directory check_and_create_directory("/var/harbr/containers") check_and_create_directory("/var/dddr") # Check for Ruby, Traefik, and runit, and install if necessary install_with_snap("ruby") unless command_exists?("ruby") install_with_snap("traefik") unless command_exists?("traefik") install_with_apt("runit") unless command_exists?("runit") puts "Setup completed successfully." end desc "containers", "show all containers" def containers container_repo = Harbr::Container::Repository.new display_containers_table(container_repo.all) end desc "deploy", "deploy a container to production" method_option :live, type: :boolean, default: false, aliases: "-l", desc: "deploy to live environment" method_option :next, type: :boolean, default: false, aliases: "-n", desc: "deploy to next environment" def deploy(name, version = nil) if options[:live] /versions\/(?\d*)/ =~ `ls -l /var/harbr/containers/#{name}/next` version = $1 raise "Ooops! next version not found!" if version.nil? Harbr::Job.perform_async(name, version, "live") /versions\/(?\d*)/ =~ `ls -l /var/harbr/containers/#{name}/live` `ln -sf /var/harbr/containers/#{name}/version/#{$1} /var/harbr/containers/#{name}/rollback` puts "deploy version #{version} of #{name} to live environment" end if options[:next] `ln -sf /var/harbr/containers/#{name}/version/#{version} /var/harbr/containers/#{name}/next` Harbr::Job.perform_async(name, version, "next") puts "deploy version #{version} of #{name} to next environment" end end desc "containerise", "deploy a container to a lxd comtainer" method_option :live, type: :boolean, default: false, aliases: "-l", desc: "deploy to live environment" method_option :next, type: :boolean, default: false, aliases: "-n", desc: "deploy to next environment" def containerise(name, version = nil) if options[:live] /versions\/(?\d*)/ =~ `ls -l /var/harbr/containers/#{name}/next` version = $1 raise "Ooops! next version not found!" if version.nil? Harbr::Lxd::Job.perform_async(name, 9292, "live") /versions\/(?\d*)/ =~ `ls -l /var/harbr/containers/#{name}/live` `ln -sf /var/harbr/containers/#{name}/version/#{$1} /var/harbr/containers/#{name}/rollback` puts "deploy version #{version} of #{name} to live environment" end if options[:next] `ln -sf /var/harbr/containers/#{name}/version/#{version} /var/harbr/containers/#{name}/next` Harbr::Lxd::Job.perform_async(name, 9292, "next") puts "deploy version #{version} of #{name} to next environment" end end desc "rollback", "rollback last deploy" def rollback(name) Dir.chdir("/var/harbr/containers/#{name}") do if File.exist?("rollback") Dir.chdir("/var/harbr/containers/#{name}/") do /(?:. * -> (?:.*))/ =~ `ls -l /var/harbr/containers/#{name}/rollback` `rm -r live` `ln -sf #{$2} live` `sv restart live.#{name}` end puts "rollback successful" end end end desc "update", "update to the latest version of harbr" def update system "gem update harbr" end end HarbrCLI.start(ARGV)