lib/gaptool_client/commands.rb in gaptool-client-0.8.0.pre.beta1 vs lib/gaptool_client/commands.rb in gaptool-client-0.8.0.pre.beta2

- old
+ new

@@ -2,10 +2,11 @@ # rubocop:disable Metrics/LineLength require 'rainbow' require 'json' require 'clamp' require 'set' +require 'logger' require 'gaptool_client/api' require 'gaptool_client/helpers' require 'gaptool_client/ssh' module Gaptool @@ -80,11 +81,11 @@ option ['-e', '--environment'], 'ENVIRONMENT', 'Instance environment' option ['-i', '--instance'], 'INSTANCE', 'Instance id (i-xxxxxxxx)' option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.' option ['-x', '--exclude-hidden'], :flag, 'Exclude hidden hosts' option ['-c', '--continue-on-errors'], :flag, 'Continue execution even if one or more hosts fail' - option ['-b', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE + option ['-B', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE parameter 'COMMAND ...', 'Command to run', attribute_name: :commands def execute params = exclude_hidden? ? {} : { hidden: true } nodes = Gaptool::API.query_nodes(params.merge(instance: instance, @@ -214,11 +215,11 @@ 'branch of the chef repository to use (defaults to last branch used during init/chefrun)', default: nil) option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.' option ['-W', '--whyrun'], :flag, 'Whyrun, like dry-run but different.' option ['-c', '--continue-on-errors'], :flag, 'Continue execution even if one or more hosts fail' - option ['-b', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE + option ['-B', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE def execute attrs = Gaptool::Helpers.split_attrs(attribute_list) nodes = Gaptool::API.query_nodes(hidden: hidden? ? true : nil, role: role, @@ -239,13 +240,13 @@ json['run_list'] ||= node['chef_runlist'] || ['recipe[main]'] git = 'sudo -u admin git' pull = "#{git} fetch --all; #{git} reset --hard origin/`#{git} rev-parse --abbrev-ref HEAD`" wopts = node['whyrun'] ? ' -W ' : '' - unless node['chef_branch'].nil? - json['chefbranch'] = node['chef_branch'] - pull = "#{git} checkout -f #{node['chef_branch']}; #{git} fetch --all; #{git} reset --hard origin/#{node['chef_branch']}" + unless node['attrs']['chef_branch'].nil? + json['chefbranch'] = node['attrs']['chef_branch'] + pull = "#{git} checkout -f #{node['attrs']['chef_branch']}; #{git} fetch --all; #{git} reset --hard origin/#{node['attrs']['chef_branch']}" end upload!(StringIO.new(json.to_json), '/tmp/chef.json') script = <<-EOS #!/bin/bash set -e @@ -276,11 +277,11 @@ option ['-i', '--instance'], 'INSTANCE', 'Instance ID, e.g. i-12345678. If set, all applications MUST be hosted on this node.' option ['-A', '--attribute'], 'ATTRIBUTE', 'Pass one or more parameters to the deploy recipe in recipe.attr=value format', multivalued: true option ['-H', '--hidden'], :flag, 'Display hidden hosts' option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.' option ['-c', '--continue-on-errors'], :flag, 'Continue execution even if one or more hosts fail' - option ['-b', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE + option ['-B', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE option ['-v', '--verbose'], :flag, 'More verbose output' def execute attrs = Gaptool::Helpers.split_attrs(attribute_list) if instance @@ -373,8 +374,81 @@ version = File.read(File.realpath(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))).strip puts "gaptool-client #{version} using gaptool-api #{Gaptool::API.client.version}" return 0 unless remote? vinfo = Gaptool::API.client.api_version puts "gaptool-server #{vinfo['server_version']}" + end + end + + class ScpCommand < Clamp::Command + option ['-r', '--role'], 'ROLE', 'Instance role' + option ['-e', '--environment'], 'ENVIRONMENT', 'Instance environment' + option ['-i', '--instance'], 'INSTANCE', 'Instance id (i-xxxxxxxx)' + option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.' + option ['-x', '--exclude-hidden'], :flag, 'Exclude hidden hosts' + option ['-c', '--continue-on-errors'], :flag, 'Continue execution even if one or more hosts fail' + option ['-B', '--batch-size'], 'SIZE', "How many hosts to run in parallel (defaults to #{Gaptool::SSH::BATCH_SIZE})", default: Gaptool::SSH::BATCH_SIZE + parameter 'SRC', 'Source file spec', attribute_name: :src + parameter '[DEST]', 'Dest file spec.', attribute_name: :dest + + def execute + if src.start_with?(':') + # from remote to local + signal_usage_error('SRC and DEST cannot be both remote') \ + if dest && dest.start_with?(':') + source = src[1..-1] + destf = dest ? dest : File.join(Dir.pwd, File.basename(source)) + destd = File.dirname(destf) + Gaptool::Helpers.error("Cannot write to #{destd}") \ + unless File.writable?(destd) + + pre_hook = proc do |node| + download! node['source'], "#{node['destf']}.#{node['instance']}" + end + + else + # from local to remote + signal_usage_error('SRC and DEST cannot be both local') \ + if dest && !dest.start_with?(':') + begin + source = File.realpath(src) + rescue => e + Gaptool::Helpers.error(e) + end + destf = dest ? dest[1..-1] : File.basename(src) + if destf.end_with?('/') + destd = destf + destf = File.join(destf, File.basename(src)) + else + destd = File.dirname(destf) + end + + pre_hook = proc do |node| + if test("[ -w #{node['destd']} ]") + upload! node['source'], node['destf'] + else + fail "No such directory #{node['destd']}" \ + unless test("[ -d #{node['destd']} ]") + tmp = File.join('/tmp', File.basename(node['destf'])) + upload! node['source'], tmp + execute("sudo mv #{tmp} #{node['destf']}") + end + end + end + + params = exclude_hidden? ? {} : { hidden: true } + nodes = Gaptool::API.query_nodes(params.merge(instance: instance, + role: role, + environment: environment)) + nodes = nodes.map { |x| x.merge('source' => source, 'destd' => destd, 'destf' => destf) } + + res = Gaptool::SSH.exec( + nodes, [], + pre_hooks: [pre_hook], serial: serial?, + continue_on_errors: continue_on_errors?, + batch_size: batch_size, + log_level: Logger::INFO + ) + exit res end end end