# coding: utf-8 module Dag module CLI class Cluster < SubCommand include Dag::CLI::Utils::NumberToHuman class NotClusterFound < StandardError; end desc 'attach ([CLUSTER])', 'Attach cluster' def attach(cluster = nil) if cluster attached_cluster = handle_api_failure do open_client{ cluster }.cluster end local_store { |db| db[:cluster] = cluster } say_status "Attach cluster", attached_cluster.name else cluster = local_store { |db| db[:cluster] } begin raise NotClusterFound if cluster.nil? say_status "Attached cluster", cluster rescue NotClusterFound abort "Please attach to the cluster\nType 'dag cluster attach [CLUSTER]'" end end end desc 'detach', 'Detach cluster' def detach attached_cluster = '' local_store do |db| attached_cluster = db[:cluster] raise NotClusterFound if attached_cluster.nil? db[:cluster] = nil end say_status "Detach cluster", attached_cluster rescue NotClusterFound abort "Please attach to the cluster\nType 'dag attach [CLUSTER]'" end desc 'list', 'show cluster list' def list headers = %w(# name status type instances) rows = [] attach_cluster = local_store { |db| db[:cluster] } handle_api_failure do client.clusters.each do |cluster| total_container = cluster.instances.lazy.map{|c| c["quantity"] }.inject(:+) cluster_row = [cluster.name, cluster.status, cluster.type, total_container || 0] rows << if attach_cluster == cluster.name cluster_row.unshift('*') else cluster_row.unshift(nil) end end end terminal_table(rows, headers: headers, max_width: Float::INFINITY) end desc 'info', 'Cluster instance info id/dfs_used/non_dfs_used/capacity/grade' def info headers = %w(instance_id grade dfs_used non_dfs_used capacity) rows = [] cluster = handle_api_failure do open_client.cluster end statistics = cluster.statistics unless statistics return say_status( "InvalidClusterState", "Cluster status is invalid: #{cluster.status}", :red ) end statistics.instances.each do |instance| rows << [ instance.instance_id, instance.grade, number_to_human(instance.disk.dfs_used), number_to_human(instance.disk.non_dfs_used), number_to_human(instance.disk.capacity) ] end puts "Cluster: #{cluster.name}" terminal_table(rows, headers: headers) end desc 'restart', 'restart cluster' option :force, type: :boolean, aliases: '-f', default: false, desc: 'cluster force restart' option :type, type: :string, aliases: '-t', default: nil, desc: 'change cluster type' option :wait, type: :boolean, aliases: '-w', default: false, desc: 'wait until normal cluster status' option :assumeyes, type: :boolean, aliases: '-y', desc: 'assume that the answer to any question which would be asked is yes' def restart unless options[:assumeyes] loop do ans = ask 'Is this ok [y/N]:' case ans when 'y' break when 'N' exit end end end headers = %w(name type force) rows = [] cluster = handle_api_failure do open_client.cluster end options[:type] ||= cluster.type params = { force: options[:force], type: options[:type] } handle_api_failure do cluster.restart(params) end rows << [cluster.name, params[:type], params[:force]] terminal_table(rows, headers: headers) if options[:wait] puts puts 'wait cluster ready...' wait_ready end end desc 'wait_ready', 'wait cluster ready' def wait_ready pretime = Time.now prestate = "" state = [] state_num = 0 while true do cluster = handle_api_failure do open_client.cluster end st = cluster.status now = Proc.new { "#{st}(#{(Time.now-pretime).round}s)" } fiber = Fiber.new {|state| Fiber.yield state } if prestate != st prestate = st pretime = Time.now state << now.call state_num += 1 end state[state_num-1] = now.call print "#{fiber.resume(state*' ')}\r" $stdout.flush if %w(norm failed ptfailed error).include? st print "\n" break end sleep 1 end end desc 'log [OUTPUT_PATH]', 'export cluster log' option :compress, type: :boolean, aliases: '-c', default: false def log(output_log_path) params = { compress: options[:compress], output_log_path: output_log_path } handle_api_failure do cluster = open_client.cluster cluster.export_log(params) end end end end end