RemoteSystemctl/app.rb

77 lines
1.7 KiB
Ruby
Executable File

#!/usr/bin/env ruby
require "sinatra/base"
require "dotenv"
require "slim"
module RS
APP_ENV = ENV.fetch("REMOTE_SYSTEMCTL_ENV") { "development" }
LOADED_ENV = Dotenv.load(".env.#{APP_ENV}.local", ".env.local", ".env")
PASSWORDS = LOADED_ENV.filter { |k, _| k =~ /^PASSWORD_/ }.to_h
SERVICE_NAMES = PASSWORDS.map { |k, _| k.gsub(/^PASSWORD_/, '') }
class Service
attr_reader :name, :state
def initialize(name:)
@name = name
@state = "default"
end
def password = PASSWORDS["PASSWORD_#{@name}"]
def start! = act! :start
def stop! = act! :stop
private def act!(action)
`systemctl --user #{action} #{@name}`
@state = action
end
end
class ServiceIndex
def initialize(service_list)
@index = service_list.map { [_1, Service.new(name: _1)] }.to_h
end
def [](service_name) = @index[service_name]
def each(&block) = @index.values.each(&block)
end
SERVICES = ServiceIndex.new(SERVICE_NAMES)
class App < Sinatra::Base
get "/" do
slim :index, locals: { services: SERVICES }
end
post "/:service/:action" do
service = SERVICES[params["service"]]
if !service
status_code 404
return "Service not found"
end
if params["password"] != service.password
status_code 403
return "Invalid password"
end
case params["action"]
when "start"
service.start!
when "stop"
service.stop!
end
redirect "/"
end
set :bind, ENV["REMOTE_SYSTEMCTL_BIND"] || "127.0.0.1"
set :port, ENV["REMOTE_SYSTEMCTL_PORT"] || "10001"
set :environment, APP_ENV
ENV["RACK_ENV"] = APP_ENV
run! if app_file == $PROGRAM_NAME
end
end