#!/usr/bin/env ruby require "thor" require "dddr" require "harbr" require "sucker_punch" require "terminal-table" require 'yaml' require 'ostruct' class HarbrCLI < Thor DEFAULT_DIRECTORY = "/var/harbr" DEFAULT_DIRECTORY_DATA_DIR = "#{DEFAULT_DIRECTORY}/.data" Dddr.configure do |config| config.data_dir = DEFAULT_DIRECTORY_DATA_DIR end no_commands do def load_manifest(container, version) manifest_path = "/var/harbr/#{container}/#{version}/config/manifest.yml" if File.exist?(manifest_path) manifest_data = YAML.load_file(manifest_path) OpenStruct.new(manifest_data) else puts "Manifest file not found for container '#{container}', version '#{version}'" nil end end 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, 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 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 scan_for_containers Dir.glob("/var/harbr/*").each_with_object({}) do |container_path, hash| next unless File.directory?(container_path) container_name = File.basename(container_path) versions = Dir.glob("#{container_path}/versions/*").select { |path| File.directory?(path) } versions.each { |version_path| hash["#{container_name}/versions/#{File.basename(version_path)}"] = true } end end PLACED_FILE = '/var/harbr/.placed' def place(container, version) placed_containers = File.exist?(PLACED_FILE) ? File.read(PLACED_FILE).split("\n") : [] if placed_containers.include?("#{container}/#{version}") puts "Container '#{container}', Version '#{version}' is already placed." else puts "Placing container: '#{container}', Version: '#{version}'" run_tasks(container, version) File.open(PLACED_FILE, 'a') { |file| file.puts("#{container}/#{version}") } end end def run_tasks(container, version) manifest = load_manifest(container,version) Harbr::Container::Job.perform_async(manifest) puts "Running tasks for container: '#{container}', Version: '#{version}'" end end desc "setup", "Set up Harbr environment" def setup # Check and create /var/harbr directory check_and_create_directory("/var/harbr") # 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 "monitor", "Monitor /var/harbr for new container versions" def monitor puts "Monitoring /var/harbr for new container versions..." last_known_state = {} loop do current_state = scan_for_containers new_versions = current_state.keys - last_known_state.keys new_versions.each do |container_version| container, version = container_version.split("/versions/") place(container, version) end last_known_state = current_state sleep 10 # Poll every 10 seconds end end end HarbrCLI.start(ARGV)