Client: first draft.

This commit is contained in:
Karchnu 2020-12-10 17:29:26 +01:00
parent ce74c1c2c1
commit c1ef4f6235
5 changed files with 271 additions and 10 deletions

View File

@ -21,5 +21,7 @@ dependencies:
targets: targets:
dnsmanager: dnsmanager:
main: src/main.cr main: src/main.cr
dnsmanager-client:
main: src/client/main.cr
license: MIT license: MIT

142
src/client/main.cr Normal file
View File

@ -0,0 +1,142 @@
require "authd"
require "ipc"
require "../network.cr"
require "../storage.cr"
require "yaml"
require "baguette-crystal-base"
require "../config"
require "./lib/*"
class Context
class_property command = "not-implemented"
class_property args : Array(String)? = nil
end
require "./parser.cr"
#def read_searches
# Array(DNSManager::Request::BLAH).from_json_files Context.args.not_nil!
#end
class Actions
property the_call = {} of String => Proc(Nil)
property dnsmanagerd : DNSManager::Client
property authd : AuthD::Client
property authd_config : Baguette::Configuration::Auth
property config : Baguette::Configuration::DNSManager
def initialize(@dnsmanagerd, @authd, @authd_config, @config)
#
# Admin section.
#
# Maintainance
@the_call["admin-maintainance"] = ->admin_maintainance
end
def admin_maintainance
subjects = Context.args.not_nil!
past_is_verbosity = false
subjects.each do |subject|
begin
case subject
when /verbosity/i
Baguette::Log.info "changing verbosity"
past_is_verbosity = true
next
end
key = @authd_config.shared_key
if past_is_verbosity
sub = DNSManager::Request::Maintainance::Subject::Verbosity
value = subject.to_i
pp! sub, value
pp! @dnsmanagerd.admin_maintainance key, sub, value
else
sub = DNSManager::Request::Maintainance::Subject.parse(subject)
pp! sub
pp! @dnsmanagerd.admin_maintainance key, sub
end
rescue e
puts "error for admin_maintainance #{subject}: #{e.message}"
end
end
end
end
def main
simulation, no_configuration, configuration_file = Baguette::Configuration.option_parser
# Authd configuration.
authd_config = if no_configuration
Baguette::Log.info "do not load a configuration file."
Baguette::Configuration::Auth.new
else
# Configuration file is for dnsmanagerd.
Baguette::Configuration::Auth.get || Baguette::Configuration::Auth.new
end
if key_file = authd_config.shared_key_file
authd_config.shared_key = File.read(key_file).chomp
end
# Authd configuration.
config = if no_configuration
Baguette::Log.info "do not load a configuration file."
Baguette::Configuration::DNSManager.new
else
# Configuration file is for dnsmanagerd.
Baguette::Configuration::DNSManager.get || Baguette::Configuration::DNSManager.new
end
Baguette::Context.verbosity = config.verbosity
Baguette::Log.info "verbosity: #{config.verbosity}."
parsing_cli authd_config
# dnsmanagerd connection and authentication
dnsmanagerd = DNSManager::Client.new
if simulation
pp! authd_config
pp! Context.command
pp! Context.args
exit 0
end
# Authd authentication, get the token and quit right away.
# If login == pass == "undef": do not even try.
if authd_config.login.nil? || authd_config.pass.nil?
Baguette::Log.info "no authd login"
else
login = authd_config.login.not_nil!
pass = authd_config.pass.not_nil!
token = authd_get_token login: login, pass: pass
dnsmanagerd.login token
end
authd = AuthD::Client.new
actions = Actions.new dnsmanagerd, authd, authd_config, config
# Now we did read the intent, we should proceed doing what was asked.
begin
actions.the_call[Context.command].call
rescue e
Baguette::Log.info "The command is not recognized (or implemented)."
end
# dnsmanagerd disconnection
dnsmanagerd.close
authd.close
rescue e
Baguette::Log.info "Exception: #{e}"
end
# Command line:
# tool [options] command subcommand [options-for-subcommand] [YAML-or-JSON-files]
main

115
src/client/parser.cr Normal file
View File

@ -0,0 +1,115 @@
require "option_parser"
class OptionParser
def to_s(io : IO)
if banner = @banner
io << banner
io << "\n\n"
end
@flags.join io, "\n"
end
end
def parsing_cli(authd_config : Baguette::Configuration::Auth)
opt_authd_admin = -> (parser : OptionParser, authd_config : Baguette::Configuration::Auth) {
parser.on "-k file", "--key-file file", "Read the authd shared key from a file." do |file|
authd_config.shared_key = File.read(file).chomp
Baguette::Log.info "Key for admin operations: #{authd_config.shared_key}."
end
}
# frequently used functions
opt_authd_login = -> (parser : OptionParser, authd_config : Baguette::Configuration::Auth) {
parser.on "-l LOGIN", "--login LOGIN", "Authd user login." do |login|
authd_config.login = login
Baguette::Log.info "User login for authd: #{authd_config.login}."
end
parser.on "-p PASSWORD", "--password PASSWORD", "Authd user password." do |password|
authd_config.pass = password
Baguette::Log.info "User password for authd: #{authd_config.pass}."
end
}
opt_help = -> (parser : OptionParser) {
parser.on "-h", "--help", "Prints command usage." do
puts "usage: #{PROGRAM_NAME} command -h"
puts
puts parser
case Context.command
when /admin-maintainance/
Baguette::Log.warning "should provide subjects to request"
Baguette::Log.warning "as in:"
DNSManager::Request::Maintainance::Subject.names.each do |n|
Baguette::Log.warning "- #{n}"
end
end
exit 0
end
}
# Unrecognized parameters are used to create commands with multiple arguments.
# Example: user add _login email phone_
# Here, login, email and phone are unrecognized arguments.
# Still, the "user add" command expect them.
unrecognized_args_to_context_args = -> (parser : OptionParser,
nexact : Int32?,
at_least : Int32?) {
# With the right args, these will be interpreted as serialized data.
parser.unknown_args do |args|
# either we test with the exact expected number of arguments or the least.
if exact = nexact
if args.size != exact
Baguette::Log.error "#{parser}"
exit 1
end
elsif least = at_least
if args.size < least
Baguette::Log.error "#{parser}"
exit 1
end
else
Baguette::Log.error "Number of parameters not even provided!"
Baguette::Log.error "#{parser}"
exit 1
end
args.each do |arg|
Baguette::Log.debug "Unrecognized argument: #{arg} (adding to Context.args)"
if Context.args.nil?
Context.args = Array(String).new
end
Context.args.not_nil! << arg
end
end
}
parser = OptionParser.new do |parser|
parser.banner = "Welcome on the DNSManager CLI administration."
# Admin section.
parser.on "admin", "Admin operations." do
# All admin operations require the shared key.
opt_authd_admin.call parser, authd_config
# Maintenance.
parser.on("maintainance", "Maintainance operation of the website.") do
Baguette::Log.info "Maintainance operation of the website."
Context.command = "admin-maintainance"
parser.banner = "COMMAND: admin maintainance subject [value]"
unrecognized_args_to_context_args.call parser, nil, 1
end
end
opt_help.call parser
end
parser.parse
end

11
src/config.cr Normal file
View File

@ -0,0 +1,11 @@
class Baguette::Configuration
class DNSManager < IPC
property service_name : String = "dnsmanager"
property recreate_indexes : Bool = false
property storage_directory : String = "storage"
def initialize
end
end
end

View File

@ -6,16 +6,7 @@ require "ipc/json"
require "authd" require "authd"
require "baguette-crystal-base" require "baguette-crystal-base"
class Baguette::Configuration require "./config"
class DNSManager < IPC
property service_name : String = "dnsmanager"
property recreate_indexes : Bool = false
property storage_directory : String = "storage"
def initialize
end
end
end
module DNSManager module DNSManager
class Exception < ::Exception class Exception < ::Exception