bin/mkitc in mkit-0.4.1 vs bin/mkitc in mkit-0.4.2

- old
+ new

@@ -6,144 +6,310 @@ require 'yaml' require 'net/http' require 'json' require 'net_http_unix' require 'securerandom' +require 'erb' -class MKItClient +class InvalidParametersException < RuntimeError + attr_reader :command + def initialize(cause, command = nil) + super(cause) + @command = command + end +end +class MKItClient def initialize - @client = NetX::HTTPUnix.new("localhost",4567) + @client = NetX::HTTPUnix.new('localhost', 4567) end - def parse_args(args) - request = nil - case args[0] - when /^ps$/ - if args.include?('-v') - params = {verbose: 'true'} - args.delete('-v') - else - params = {} + def dict + global_args = [ + { short: '-v', long: '--verbose', help: 'verbose', mandatory: false, value: nil } + ] + command_dict = [ + { + cmd: 'ps', + args: [ + { name: 'id', mandatory: false, uri: '/<%=id%>' } + ], + help: 'show services status (alias for status)', + usage: ['[service_id_or_name]'], + request: { verb: :get, uri: '/services' } + }, + { + cmd: 'status', + args: [ + { name: 'id', mandatory: false, uri: '/<%=id%>' } + ], + help: 'show services status', + usage: ['[service_id_or_name]'], + request: { verb: :get, uri: '/services' } + }, + { + cmd: 'start', + args: [ + { name: 'id', mandatory: true } + ], + help: 'start service', + usage: ['<service_id_or_name>'], + request: { verb: :put, uri: '/services/<%=id%>/start' } + }, + { + cmd: 'stop', + args: [ + { name: 'id', mandatory: true } + ], + help: 'stop service', + usage: ['<service_id_or_name>'], + request: { verb: :put, uri: '/services/<%=id%>/stop' } + }, + { + cmd: 'restart', + args: [ + { name: 'id', mandatory: true } + ], + help: 'restart service', + usage: ['<service_id_or_name>'], + request: { verb: :put, uri: '/services/<%=id%>/restart' } + }, + { + cmd: 'create', + args: [ + { name: 'file', mandatory: true } + ], + help: 'create new service', + usage: ['<service.yaml>'], + request: { verb: :post, uri: '/services' } + }, + { + cmd: 'update', + args: [ + { name: 'file', mandatory: true } + ], + help: 'update service', + usage: ['<service.yaml>'], + request: { verb: :put, uri: '/services/<%=id%>' } + }, + { + cmd: 'rm', + args: [ + { name: 'id', mandatory: true } + ], + help: 'remove service', + usage: ['<service_id_or_name>'], + request: { verb: :delete, uri: '/services/<%=id%>' } + }, + { + cmd: 'version', + help: 'prints mkit server version', + request: { verb: :get, uri: '/mkit/version' } + }, + { + cmd: 'proxy', + options: [ + { + cmd: 'start', + request: { verb: :put, uri: '/mkit/proxy/start' }, + help: 'start proxy service' + }, + { + cmd: 'stop', + request: { verb: :put, uri: '/mkit/proxy/stop' }, + help: 'stop proxy service' + }, + { + cmd: 'restart', + request: { verb: :put, uri: '/mkit/proxy/restart' }, + help: 'restarts proxy service' + }, + { + cmd: 'status', + request: { verb: :get, uri: '/mkit/proxy/status' }, + help: 'proxy service status' + } + ], + help: 'haproxy status and control', + usage: ['<start|stop|restart|status>'] + } + ] + command_dict + 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 - case args.size - when 1 - #mkitc ps [-v] GET services[?verbose=true] - request = { verb: :get, uri: '/services', params: params } - when 2 - #mkitc ps {id} GET services/{id} - id = args[1] - request = { verb: :get, uri: "/services/#{id}" } - else - raise 'invalid parameters' + 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 - when /^config:show$/ - #mkitc config:show {id} => GET services/{id}/config - #TODO - when /^stop$/ - #mkitc stop {id} => PUT services/{id}/stop - case args.size - when 2 - id = args[1] - request = { verb: :put, uri: "/services/#{id}/stop" } - else - raise 'invalid parameters' + 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.', c = dict.select { |k| k[:cmd] == 'create' }.first) + 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) + end + end + + 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) + 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) + else + id = yaml['service']['name'] + request_hash[:id] = id + request(request, request_hash) + end + 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 + raise InvalidParametersException, "'#{args[1]}' is not a valid help topic." if c.nil? end - when /^start$/ - #mkitc start {id} => PUT services/{id}/start - case args.size - when 2 - id = args[1] - request = { verb: :put, uri: "/services/#{id}/start" } - else - raise 'invalid parameters' + return help(cmd: c) + else + c = dict.select { |k| k[:cmd] == cmd }.first + end + raise InvalidParametersException, 'Command not found' if c.nil? + + 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] + 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 - when /^rm$/ - #mkitc rm {id} => DELETE services/{id} - case args.size - when 2 - id = args[1] - request = { verb: :delete, uri: "/services/#{id}" } - else - raise 'invalid parameters' - end - when /^create$/ - #mkitc create service.yaml => POST services service.yaml - case args.size - when 2 - file = args[1] - request = { verb: :post, uri: "/services", file: file } - else - raise 'invalid parameters' - end - when /^update$/ - #mkitc update service.yaml => PUT services/{id} service.yaml - case args.size - when 2 - file = args[1] - yaml = YAML.load_file(file) - if yaml["service"].nil? - raise 'invalid configuration file' - else - id = yaml["service"]["name"] - request = { verb: :put, uri: "/services/#{id}", file: file } + # 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 - else - raise 'invalid parameters' + raise InvalidParametersException.new('Invalid parameters found.', c) if option.nil? || option.empty? + + request = option[:request] end + end + raise InvalidParametersException, "Can't find request." if request.nil? + + if respond_to? c[:cmd] + send(c[:cmd], request, request_hash) else - raise "Usage: invalid parameters" + request(request, request_hash) end - request end def doIt(args) - operation = parse_args(args) - puts request(operation).body + result = parse_args(args) + puts result + rescue InvalidParametersException => e + help(cause: e) end - def request(request) + def request(request, request_args = nil) req = nil - uri = request[:uri] + uri = ERB.new(request[:uri]).result_with_hash(request_args) + request[:file] = request_args[:file] + unless request[:params].nil? || request[:params].empty? - uri = uri + '?' + request[:params].map{|k,v| "#{k}=#{v}"}.join('&') + uri = uri + '?' + request[:params].map { |k, v| "#{k}=#{v}" }.join('&') end case request[:verb] when :post req = Net::HTTP::Post.new(uri) unless request[:file].nil? (body, boundary) = attach(request[:file]) req.body = body - req["Content-Type"] = "multipart/form-data, boundary=#{boundary}" + req['Content-Type'] = "multipart/form-data, boundary=#{boundary}" end when :put req = Net::HTTP::Put.new(uri) unless request[:file].nil? (body, boundary) = attach(request[:file]) req.body = body - req["Content-Type"] = "multipart/form-data, boundary=#{boundary}" + req['Content-Type'] = "multipart/form-data, boundary=#{boundary}" end when :patch req = Net::HTTP::Patch.new(uri) when :get req = Net::HTTP::Get.new(uri) when :delete req = Net::HTTP::Delete.new(uri) end - @client.request(req) + @client.request(req).body end def attach(file) - boundary=SecureRandom.alphanumeric + boundary = SecureRandom.alphanumeric body = [] body << "--#{boundary}\r\n" body << "Content-Disposition: form-data; name=file; filename='#{File.basename(file)}'\r\n" body << "Content-Type: text/plain\r\n" body << "\r\n" body << File.read(file) body << "\r\n--#{boundary}--\r\n" - [ body.join, boundary] + [body.join, boundary] end end # # go @@ -153,6 +319,5 @@ # # if ARGV.any? # parse args # host, socket, config file # end -