bin/mkitc in mkit-0.4.3 vs bin/mkitc in mkit-0.5.0

- old
+ new

@@ -7,29 +7,28 @@ require 'net/http' require 'json' require 'net_http_unix' require 'securerandom' require 'erb' +require 'uri' +require 'fileutils' -class InvalidParametersException < RuntimeError +class InvalidParametersException < Exception attr_reader :command + def initialize(cause, command = nil) super(cause) @command = command end end -class MKItClient - def initialize - @client = NetX::HTTPUnix.new('localhost', 4567) - end - - def dict +class CommandPalette + def schema global_args = [ { short: '-v', long: '--verbose', help: 'verbose', mandatory: false, value: nil } ] - command_dict = [ + [ { cmd: 'ps', args: [ { name: 'id', mandatory: false, uri: '/<%=id%>' } ], @@ -138,144 +137,158 @@ help: 'proxy service status' } ], help: 'haproxy status and control', usage: ['<start|stop|restart|status>'] + }, + { + cmd: 'profile', + options: [ + { + cmd: 'set', + request: { verb: 'set' }, + args: [ + { name: 'profile_name', mandatory: true } + ], + help: 'set mkit client configuration profile' + }, + { + cmd: 'show', + request: { verb: 'show' }, + help: 'show mkit client current profile' + } + ], + help: 'mkit client configuration profile', + usage: ['<[set <profile_name>]|[show]>'] } ] - command_dict end +end - def help(cause: nil, cmd: nil) - msg = '' - if cause.nil? - my_cmd = cmd - else - msg += "MKItc: #{cause.message}\n" - my_cmd = cause.command - end - if my_cmd.nil? - msg += "\nUsage: mkitc <command> [options]\n\n" - msg += "Micro k8s on Ruby - a simple tool to mimic a (very) minimalistic k8 cluster\n\n" - msg += "Commands:\n\n" - dict.each do |c| - msg += format("%-10s %s\n", c[:cmd], c[:help]) - end - msg += "\n" - msg += "Run 'mkitc help <command>' for specific command information.\n\n" - else - msg += format("\nUsage: mkitc %s %s\n\n", my_cmd[:cmd], my_cmd[:usage].nil? ? '' : my_cmd[:usage].join(' ')) - msg += format("%s\n", my_cmd[:help]) - unless my_cmd[:options].nil? - msg += "\nOptions:\n" - my_cmd[:options].each do |c| - msg += format("%-10s %s\n", c[:cmd], c[:help]) - end - end - msg += "\n" - end - puts msg - exit 1 +class MKItClient + def initialize + @root = File.expand_path('..', __dir__) + @config_dir = "#{ENV['HOME']}/.mkit" + @profile_file = "#{@config_dir}/current" + @commands = CommandPalette.new + create_default_config end - def create(request, request_hash = nil) - unless File.file?(request_hash[:file]) - raise InvalidParametersException.new('File not found.', c = dict.select { |k| k[:cmd] == 'create' }.first) + def create_default_config + unless File.exist?(@config_dir) + puts "Creating config directory on '#{@config_dir}'..." + FileUtils.mkdir_p(@config_dir) end + FileUtils.cp("#{@root}/config/mkitc_config.yml", @config_dir) unless File.exist?("#{@config_dir}/mkitc_config.yml") + profile({ verb: 'set' }, { profile_name: 'local' }) unless File.exist?(@profile_file) + end - yaml = YAML.load_file(request_hash[:file]) - if yaml['service'].nil? - raise InvalidParametersException.new('Invalid configuration file', c = dict.select { |k| k[:cmd] == 'create' }.first) - else - request(request, request_hash) + def read_configuration + current_profile = File.read(@profile_file) + if current_profile.nil? || current_profile.empty? + # force set default + profile({ verb: 'set' }, { profile_name: 'local' }) + current_profile = 'local' end - end + cfg = YAML.load_file("#{@config_dir}/mkitc_config.yml") - def update(request, request_hash = nil) - unless File.file?(request_hash[:file]) - raise InvalidParametersException.new('File not found.', c = dict.select { |k| k[:cmd] == 'update' }.first) + if cfg['mkit'].nil? || cfg['mkit'][current_profile.lstrip].nil? + raise InvalidParametersException, "invalid configuration found on '~/.mkit' or profile not found" end - yaml = YAML.load_file(request_hash[:file]) - if yaml['service'].nil? - raise InvalidParametersException.new('Invalid configuration file', c = dict.select { |k| k[:cmd] == 'update' }.first) + @configuration = cfg['mkit'][current_profile.lstrip] + end + + def client + read_configuration + uri = URI(@configuration['server.uri']) + case uri.scheme + when 'https' + @client = NetX::HTTPUnix.new(uri.host, uri.port) + @client.use_ssl = true + @client.verify_mode = OpenSSL::SSL::VERIFY_NONE + when 'http' + @client = NetX::HTTPUnix.new(uri.host, uri.port) + when 'sock' + @client = NetX::HTTPUnix.new("unix://#{uri.path}") else - id = yaml['service']['name'] - request_hash[:id] = id - request(request, request_hash) + raise InvalidParametersException, 'Invalid mkit server uri. Please check configuration' end + @client end + def dict + @commands.schema + end + + def find_command(cmd) + dict.select { |k| k[:cmd] == cmd }.first + end + def parse_args(args) cmd = args[0] c = nil # short circuit for help if cmd == 'help' || args.empty? if args.size > 1 - c = dict.select { |k| k[:cmd] == args[1] }.first + c = find_command(args[1]) raise InvalidParametersException, "'#{args[1]}' is not a valid help topic." if c.nil? end return help(cmd: c) else - c = dict.select { |k| k[:cmd] == cmd }.first + c = find_command(cmd) end raise InvalidParametersException, 'Command not found' if c.nil? + command = c myargs = args.dup myargs.delete(cmd) - max_args_size = c[:args].nil? ? 0 : c[:args].size - max_options_size = c[:options].nil? ? 0 : 1 - max_args_size += max_options_size - - min_args_size = c[:args].nil? ? 0 : c[:args].select { |a| a[:mandatory] == true }.size - min_options_size = c[:options].nil? ? 0 : 1 - min_args_size += min_options_size - - if myargs.size > max_args_size || myargs.size < min_args_size - raise InvalidParametersException.new('Invalid parameters found.', c) - end - request_hash = {} - request = c[:request] + request = command[:request] unless myargs.empty? - unless c[:args].nil? - idx = 0 - c[:args].each do |a| - request_hash[a[:name].to_sym] = myargs[idx] - request[:uri] = request[:uri] + a[:uri] unless a[:uri].nil? - idx += 1 - end - end # options unless c[:options].nil? - option = nil - myargs.each do |s| - option = c[:options].select { |o| o[:cmd] == s }.first - raise InvalidParametersException.new('Invalid parameters found.', c) if option.nil? || option.empty? - end - raise InvalidParametersException.new('Invalid parameters found.', c) if option.nil? || option.empty? + command = c[:options].select { |o| o[:cmd] == myargs[0] }.first + raise InvalidParametersException.new('Invalid parameters found.', c) if command.nil? || command.empty? - request = option[:request] + myargs.delete_at(0) + request = command[:request] end + fill_cmd_args(command[:args], myargs, request, request_hash) end - raise InvalidParametersException, "Can't find request." if request.nil? + raise InvalidParametersException.new('Invalid command or parameters.', c) if request.nil? + validate_command(command, request_hash) if respond_to? c[:cmd] send(c[:cmd], request, request_hash) else request(request, request_hash) end end - def doIt(args) - result = parse_args(args) - puts result - rescue InvalidParametersException => e - help(cause: e) + def fill_cmd_args(args, myargs, request, request_hash) + return if args.nil? + + idx = 0 + args.each do |a| + request_hash[a[:name].to_sym] = myargs[idx] + request[:uri] = request[:uri] + a[:uri] unless a[:uri].nil? + idx += 1 + end end + def validate_command(command, request_hash) + return if command[:args].nil? + + command[:args].select { |a| a[:mandatory] == true }.each do |a| + if request_hash[a[:name].to_sym].nil? + raise InvalidParametersException.new("Missing mandatory parameter: #{a[:name]}", command) + end + end + end + def request(request, request_args = nil) req = nil uri = ERB.new(request[:uri]).result_with_hash(request_args) request[:file] = request_args[:file] @@ -302,11 +315,11 @@ when :get req = Net::HTTP::Get.new(uri) when :delete req = Net::HTTP::Delete.new(uri) end - @client.request(req).body + client.request(req).body end def attach(file) boundary = SecureRandom.alphanumeric body = [] @@ -315,9 +328,109 @@ body << "Content-Type: text/plain\r\n" body << "\r\n" body << File.read(file) body << "\r\n--#{boundary}--\r\n" [body.join, boundary] + end + + def doIt(args) + result = parse_args(args) + puts result + rescue InvalidParametersException => e + help(cause: e) + end + + def help(cause: nil, cmd: nil) + msg = '' + if cause.nil? + my_cmd = cmd + else + msg += "MKItc: #{cause.message}\n" + my_cmd = cause.command + end + if my_cmd.nil? + msg += "\nUsage: mkitc <command> [options]\n\n" + msg += "Micro k8s on Ruby - a simple tool to mimic a (very) minimalistic k8 cluster\n\n" + msg += "Commands:\n\n" + dict.each do |c| + msg += format("%-10s %s\n", c[:cmd], c[:help]) + end + msg += "\n" + msg += "Run 'mkitc help <command>' for specific command information.\n\n" + else + msg += format("\nUsage: mkitc %s %s\n\n", my_cmd[:cmd], my_cmd[:usage].nil? ? '' : my_cmd[:usage].join(' ')) + msg += format("%s\n", my_cmd[:help]) + unless my_cmd[:options].nil? + msg += "\nOptions:\n" + my_cmd[:options].each do |c| + msg += format("%-10s %s\n", c[:cmd], c[:help]) + end + end + msg += "\n" + end + puts msg + exit 1 + end + + def create(request, request_hash = nil) + unless File.file?(request_hash[:file]) + raise InvalidParametersException.new('File not found.', find_command('create')) + end + + yaml = YAML.load_file(request_hash[:file]) + if yaml['service'].nil? + raise InvalidParametersException.new('Invalid configuration file', find_command('create')) + else + request(request, request_hash) + end + end + + def update(request, request_hash = nil) + unless File.file?(request_hash[:file]) + raise InvalidParametersException.new('File not found.', find_command('update')) + end + + yaml = YAML.load_file(request_hash[:file]) + if yaml['service'].nil? + raise InvalidParametersException.new('Invalid configuration file', find_command('update')) + else + id = yaml['service']['name'] + request_hash[:id] = id + request(request, request_hash) + end + end + + def profile(request, request_hash = {}) + cfg = YAML.load_file("#{@config_dir}/mkitc_config.yml") + cmd = find_command('profile') + if cfg['mkit'].nil? + raise InvalidParametersException.new( + "Invalid configuration on '~/.mkit'\nPlease fix or clean up for defaults apply", cmd + ) + end + + case request[:verb] + when 'set' + profile = request_hash[:profile_name] + if cfg['mkit'][profile.lstrip].nil? + raise InvalidParametersException.new("Profile not found on '~/.mkit' configuration", cmd) + end + + puts "Setting current profile to #{profile}." + File.write(@profile_file, request_hash[:profile_name]) + '' + when 'show' + active = File.read("#{@config_dir}/current") + cfg['mkit'].map do |k, _v| + if k == active + "*#{k}" + else + k + end + end.join(' ') + else + raise InvalidParametersException.new("Invalid 'profile' operation", cmd) + end end end # # go