Use Logger for non-result output

This adds the Logger class for log output, all of which goes to STDERR,
and uses puts to send only the command result to STDOUT.
This commit is contained in:
barriserloth 2020-08-11 10:31:14 -07:00 committed by Austin Blatt
parent 4755343df2
commit 8ec90007ca
7 changed files with 81 additions and 67 deletions

View file

@ -13,10 +13,15 @@ require 'vmfloaty/conf'
require 'vmfloaty/utils' require 'vmfloaty/utils'
require 'vmfloaty/service' require 'vmfloaty/service'
require 'vmfloaty/ssh' require 'vmfloaty/ssh'
require 'vmfloaty/logger'
class Vmfloaty class Vmfloaty
include Commander::Methods include Commander::Methods
def self.logger
@logger ||= FloatyLogger.new
end
def run # rubocop:disable Metrics/AbcSize def run # rubocop:disable Metrics/AbcSize
program :version, Vmfloaty::VERSION program :version, Vmfloaty::VERSION
program :description, "A CLI helper tool for Puppet's vmpooler to help you stay afloat" program :description, "A CLI helper tool for Puppet's vmpooler to help you stay afloat"
@ -45,7 +50,7 @@ class Vmfloaty
force = options.force force = options.force
if args.empty? if args.empty?
STDERR.puts 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.' logger.error 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.'
exit 1 exit 1
end end
@ -54,13 +59,13 @@ class Vmfloaty
max_pool_request = 5 max_pool_request = 5
large_pool_requests = os_types.select { |_, v| v > max_pool_request } large_pool_requests = os_types.select { |_, v| v > max_pool_request }
if !large_pool_requests.empty? && !force if !large_pool_requests.empty? && !force
STDERR.puts "Requesting vms over #{max_pool_request} requires a --force flag." logger.error "Requesting vms over #{max_pool_request} requires a --force flag."
STDERR.puts 'Try again with `floaty get --force`' logger.error 'Try again with `floaty get --force`'
exit 1 exit 1
end end
if os_types.empty? if os_types.empty?
STDERR.puts 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.' logger.error 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.'
exit 1 exit 1
end end
@ -71,9 +76,9 @@ class Vmfloaty
hosts = Utils.standardize_hostnames(response) hosts = Utils.standardize_hostnames(response)
if options.json || options.ondemand if options.json || options.ondemand
STDOUT.puts JSON.pretty_generate(hosts) puts JSON.pretty_generate(hosts)
else else
STDOUT.puts Utils.format_host_output(hosts) puts Utils.format_host_output(hosts)
end end
end end
end end
@ -99,15 +104,15 @@ class Vmfloaty
running_vms = service.list_active(verbose) running_vms = service.list_active(verbose)
host = URI.parse(service.url).host host = URI.parse(service.url).host
if running_vms.empty? if running_vms.empty?
STDOUT.puts "You have no running VMs on #{host}" puts "You have no running VMs on #{host}"
else else
STDOUT.puts "Your VMs on #{host}:" puts "Your VMs on #{host}:"
Utils.pretty_print_hosts(verbose, service, running_vms) Utils.pretty_print_hosts(verbose, service, running_vms)
end end
else else
# list available vms from pooler # list available vms from pooler
os_list = service.list(verbose, filter) os_list = service.list(verbose, filter)
STDOUT.puts os_list puts os_list
end end
end end
end end
@ -151,7 +156,7 @@ class Vmfloaty
modify_all = options.all modify_all = options.all
if hostname.nil? && !modify_all if hostname.nil? && !modify_all
STDERR.puts 'ERROR: Provide a hostname or specify --all.' logger.error 'ERROR: Provide a hostname or specify --all.'
exit 1 exit 1
end end
running_vms = modify_all ? service.list_active(verbose) : hostname.split(',') running_vms = modify_all ? service.list_active(verbose) : hostname.split(',')
@ -172,17 +177,17 @@ class Vmfloaty
begin begin
modified_hash[vm] = service.modify(verbose, vm, modify_hash) modified_hash[vm] = service.modify(verbose, vm, modify_hash)
rescue ModifyError => e rescue ModifyError => e
STDERR.puts e logger.error e
ok = false ok = false
end end
end end
if ok if ok
if modify_all if modify_all
STDOUT.puts 'Successfully modified all VMs.' puts 'Successfully modified all VMs.'
else else
STDOUT.puts "Successfully modified VM #{hostname}." puts "Successfully modified VM #{hostname}."
end end
STDOUT.puts 'Use `floaty list --active` to see the results.' puts 'Use `floaty list --active` to see the results.'
end end
end end
end end
@ -214,11 +219,10 @@ class Vmfloaty
if delete_all if delete_all
running_vms = service.list_active(verbose) running_vms = service.list_active(verbose)
if running_vms.empty? if running_vms.empty?
STDOUT.puts 'You have no running VMs.' puts 'You have no running VMs.'
else else
Utils.pretty_print_hosts(verbose, service, running_vms, true) Utils.pretty_print_hosts(verbose, service, running_vms, true)
# Confirm deletion # Confirm deletion
STDERR.puts
confirmed = true confirmed = true
confirmed = agree('Delete all these VMs? [y/N]') unless force confirmed = agree('Delete all these VMs? [y/N]') unless force
if confirmed if confirmed
@ -243,23 +247,23 @@ class Vmfloaty
end end
end end
else else
STDERR.puts 'You did not provide any hosts to delete' logger.info 'You did not provide any hosts to delete'
exit 1 exit 1
end end
unless failures.empty? unless failures.empty?
STDERR.puts 'Unable to delete the following VMs:' logger.info 'Unable to delete the following VMs:'
failures.each do |hostname| failures.each do |hostname|
STDERR.puts "- #{hostname}" logger.info "- #{hostname}"
end end
STDERR.puts 'Check `floaty list --active`; Do you need to specify a different service?' logger.info 'Check `floaty list --active`; Do you need to specify a different service?'
end end
unless successes.empty? unless successes.empty?
STDERR.puts unless failures.empty? logger.info unless failures.empty?
STDOUT.puts 'Scheduled the following VMs for deletion:' puts 'Scheduled the following VMs for deletion:'
successes.each do |hostname| successes.each do |hostname|
STDOUT.puts "- #{hostname}" puts "- #{hostname}"
end end
end end
@ -284,11 +288,11 @@ class Vmfloaty
begin begin
snapshot_req = service.snapshot(verbose, hostname) snapshot_req = service.snapshot(verbose, hostname)
rescue TokenError, ModifyError => e rescue TokenError, ModifyError => e
STDERR.puts e logger.error e
exit 1 exit 1
end end
STDOUT.puts "Snapshot pending. Use `floaty query #{hostname}` to determine when snapshot is valid." puts "Snapshot pending. Use `floaty query #{hostname}` to determine when snapshot is valid."
pp snapshot_req pp snapshot_req
end end
end end
@ -309,12 +313,12 @@ class Vmfloaty
hostname = args[0] hostname = args[0]
snapshot_sha = args[1] || options.snapshot snapshot_sha = args[1] || options.snapshot
STDERR.puts "Two snapshot arguments were given....using snapshot #{snapshot_sha}" if args[1] && options.snapshot logger.info "Two snapshot arguments were given....using snapshot #{snapshot_sha}" if args[1] && options.snapshot
begin begin
revert_req = service.revert(verbose, hostname, snapshot_sha) revert_req = service.revert(verbose, hostname, snapshot_sha)
rescue TokenError, ModifyError => e rescue TokenError, ModifyError => e
STDERR.puts e logger.error e
exit 1 exit 1
end end
@ -379,24 +383,24 @@ class Vmfloaty
case action case action
when 'get' when 'get'
token = service.get_new_token(verbose) token = service.get_new_token(verbose)
STDOUT.puts token puts token
when 'delete' when 'delete'
result = service.delete_token(verbose, options.token) result = service.delete_token(verbose, options.token)
STDOUT.puts result puts result
when 'status' when 'status'
token_value = options.token token_value = options.token
token_value = args[1] if token_value.nil? token_value = args[1] if token_value.nil?
status = service.token_status(verbose, token_value) status = service.token_status(verbose, token_value)
STDOUT.puts status puts status
when nil when nil
STDERR.puts 'No action provided' logger.error 'No action provided'
exit 1 exit 1
else else
STDERR.puts "Unknown action: #{action}" logger.error "Unknown action: #{action}"
exit 1 exit 1
end end
rescue TokenError => e rescue TokenError => e
STDERR.puts e logger.error e
exit 1 exit 1
end end
exit 0 exit 0
@ -420,13 +424,13 @@ class Vmfloaty
use_token = !options.notoken use_token = !options.notoken
if args.empty? if args.empty?
STDERR.puts 'No operating systems provided to obtain. See `floaty ssh --help` for more information on how to get VMs.' logger.error 'No operating systems provided to obtain. See `floaty ssh --help` for more information on how to get VMs.'
exit 1 exit 1
end end
host_os = args.first host_os = args.first
STDERR.puts "Can't ssh to multiple hosts; Using #{host_os} only..." if args.length > 1 logger.info "Can't ssh to multiple hosts; Using #{host_os} only..." if args.length > 1
service.ssh(verbose, host_os, use_token) service.ssh(verbose, host_os, use_token)
exit 0 exit 0
@ -450,10 +454,10 @@ class Vmfloaty
completion_file = File.expand_path(File.join('..', '..', 'extras', 'completions', "floaty.#{shell}"), __FILE__) completion_file = File.expand_path(File.join('..', '..', 'extras', 'completions', "floaty.#{shell}"), __FILE__)
if File.exist?(completion_file) if File.exist?(completion_file)
STDOUT.puts completion_file puts completion_file
exit 0 exit 0
else else
STDERR.puts "Could not find completion file for '#{shell}': No such file #{completion_file}" logger.error "Could not find completion file for '#{shell}': No such file #{completion_file}"
exit 1 exit 1
end end
end end

View file

@ -68,7 +68,7 @@ class ABS
ret_val.push(req_hash) ret_val.push(req_hash)
rescue NoMethodError rescue NoMethodError
STDERR.puts "Warning: couldn't parse line returned from abs/status/queue: ".yellow Vmfloaty.logger.warn "Warning: couldn't parse line returned from abs/status/queue: "
end end
end end
@ -85,7 +85,7 @@ class ABS
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
conn.headers['X-AUTH-TOKEN'] = token if token conn.headers['X-AUTH-TOKEN'] = token if token
STDERR.puts "Trying to delete hosts #{hosts}" if verbose Vmfloaty.logger.info "Trying to delete hosts #{hosts}" if verbose
requests = get_active_requests(verbose, url, user) requests = get_active_requests(verbose, url, user)
jobs_to_delete = [] jobs_to_delete = []
@ -113,7 +113,7 @@ class ABS
} }
jobs_to_delete.push(req_hash) jobs_to_delete.push(req_hash)
else else
STDERR.puts "When using ABS you must delete all vms that you requested at the same time: Can't delete #{req_hash['request']['job']['id']}: #{hosts} does not include all of #{req_hash['allocated_resources']}" Vmfloaty.logger.info "When using ABS you must delete all vms that you requested at the same time: Can't delete #{req_hash['request']['job']['id']}: #{hosts} does not include all of #{req_hash['allocated_resources']}"
end end
end end
end end
@ -127,7 +127,7 @@ class ABS
'hosts' => job['allocated_resources'], 'hosts' => job['allocated_resources'],
} }
STDERR.puts "Deleting #{req_obj}" if verbose Vmfloaty.logger.info "Deleting #{req_obj}" if verbose
return_result = conn.post 'return', req_obj.to_json return_result = conn.post 'return', req_obj.to_json
req_obj['hosts'].each do |host| req_obj['hosts'].each do |host|
@ -220,11 +220,11 @@ class ABS
end end
end end
STDERR.puts "Posting to ABS #{req_obj.to_json}" if verbose Vmfloaty.logger.info "Posting to ABS #{req_obj.to_json}" if verbose
# os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+') # os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
# raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty? # raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
STDERR.puts "Requesting VMs with job_id: #{saved_job_id}. Will retry for up to an hour." Vmfloaty.logger.info "Requesting VMs with job_id: #{saved_job_id}. Will retry for up to an hour."
res = conn.post 'request', req_obj.to_json res = conn.post 'request', req_obj.to_json
retries = 360 retries = 360
@ -237,7 +237,7 @@ class ABS
sleep_seconds = 10 if i >= 10 sleep_seconds = 10 if i >= 10
sleep_seconds = i if i < 10 sleep_seconds = i if i < 10
STDERR.puts "Waiting #{sleep_seconds} seconds to check if ABS request has been filled. Queue Position: #{queue_place}... (x#{i})" Vmfloaty.logger.info "Waiting #{sleep_seconds} seconds to check if ABS request has been filled. Queue Position: #{queue_place}... (x#{i})"
sleep(sleep_seconds) sleep(sleep_seconds)
end end
@ -276,7 +276,7 @@ class ABS
end end
def self.snapshot(_verbose, _url, _hostname, _token) def self.snapshot(_verbose, _url, _hostname, _token)
STDERR.puts "Can't snapshot with ABS, use '--service vmpooler' (even for vms checked out with ABS)" Vmfloaty.logger.info "Can't snapshot with ABS, use '--service vmpooler' (even for vms checked out with ABS)"
end end
def self.status(verbose, url) def self.status(verbose, url)
@ -297,7 +297,7 @@ class ABS
def self.query(verbose, url, hostname) def self.query(verbose, url, hostname)
return @active_hostnames if @active_hostnames return @active_hostnames if @active_hostnames
STDERR.puts "For vmpooler/snapshot information, use '--service vmpooler' (even for vms checked out with ABS)" Vmfloaty.logger.info "For vmpooler/snapshot information, use '--service vmpooler' (even for vms checked out with ABS)"
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
res = conn.get "host/#{hostname}" res = conn.get "host/#{hostname}"

View file

@ -8,7 +8,7 @@ class Conf
begin begin
conf = YAML.load_file("#{Dir.home}/.vmfloaty.yml") conf = YAML.load_file("#{Dir.home}/.vmfloaty.yml")
rescue StandardError rescue StandardError
STDERR.puts "WARNING: There was no config file at #{Dir.home}/.vmfloaty.yml" Vmfloaty.logger.warn "WARNING: There was no config file at #{Dir.home}/.vmfloaty.yml"
end end
conf conf
end end

11
lib/vmfloaty/logger.rb Normal file
View file

@ -0,0 +1,11 @@
require 'logger'
class FloatyLogger < ::Logger
def initialize
super(STDERR)
self.level = ::Logger::INFO
self.formatter = proc do |severity, datetime, progname, msg|
"#{msg}\n"
end
end
end

View file

@ -60,10 +60,10 @@ class Pooler
while check_ondemandvm(verbose, request_id, url) == false while check_ondemandvm(verbose, request_id, url) == false
return false if (Time.now - start_time).to_i > timeout return false if (Time.now - start_time).to_i > timeout
STDOUT.puts "waiting for request #{request_id} to be fulfilled" Vmfloaty.logger.info "waiting for request #{request_id} to be fulfilled"
sleep 5 sleep 5
end end
STDOUT.puts "The request has been fulfilled" Vmfloaty.logger.info "The request has been fulfilled"
check_ondemandvm(verbose, request_id, url) check_ondemandvm(verbose, request_id, url)
end end

View file

@ -36,7 +36,7 @@ class Service
def user def user
unless @config['user'] unless @config['user']
STDERR.puts "Enter your #{@config['url']} service username:" Vmfloaty.logger.info "Enter your #{@config['url']} service username:"
@config['user'] = STDIN.gets.chomp @config['user'] = STDIN.gets.chomp
end end
@config['user'] @config['user']
@ -44,7 +44,7 @@ class Service
def token def token
unless @config['token'] unless @config['token']
STDERR.puts 'No token found. Retrieving a token...' Vmfloaty.logger.info 'No token found. Retrieving a token...'
@config['token'] = get_new_token(nil) @config['token'] = get_new_token(nil)
end end
@config['token'] @config['token']
@ -76,7 +76,7 @@ class Service
end end
def retrieve(verbose, os_types, use_token = true, ondemand = nil) def retrieve(verbose, os_types, use_token = true, ondemand = nil)
STDERR.puts 'Requesting a vm without a token...' unless use_token Vmfloaty.logger.info 'Requesting a vm without a token...' unless use_token
token_value = use_token ? token : nil token_value = use_token ? token : nil
@service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand @service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand
end end
@ -91,8 +91,8 @@ class Service
begin begin
token_value = token || get_new_token(verbose) token_value = token || get_new_token(verbose)
rescue TokenError => e rescue TokenError => e
STDERR.puts e Vmfloaty.logger.error e
STDERR.puts 'Could not get token... requesting vm without a token anyway...' Vmfloaty.logger.info 'Could not get token... requesting vm without a token anyway...'
end end
end end
Ssh.ssh(verbose, self, host_os, token_value) Ssh.ssh(verbose, self, host_os, token_value)

View file

@ -45,7 +45,6 @@ class Utils
result = {} result = {}
STDERR.puts "response body is #{response_body}"
filtered_response_body = response_body.reject { |key, _| key == 'request_id' || key == 'ready' } filtered_response_body = response_body.reject { |key, _| key == 'request_id' || key == 'ready' }
filtered_response_body.each do |os, value| filtered_response_body.each do |os, value|
hostnames = Array(value['hostname']) hostnames = Array(value['hostname'])
@ -91,7 +90,7 @@ class Utils
# For ABS, 'hostname' variable is the jobID # For ABS, 'hostname' variable is the jobID
if host_data['state'] == 'allocated' || host_data['state'] == 'filled' if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
host_data['allocated_resources'].each do |vm_name, _i| host_data['allocated_resources'].each do |vm_name, _i|
STDOUT.puts "- [JobID:#{host_data['request']['job']['id']}] #{vm_name['hostname']} (#{vm_name['type']}) <#{host_data['state']}>" puts "- [JobID:#{host_data['request']['job']['id']}] #{vm_name['hostname']} (#{vm_name['type']}) <#{host_data['state']}>"
end end
end end
when 'Pooler' when 'Pooler'
@ -99,19 +98,19 @@ class Utils
tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil? tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
duration = "#{host_data['running']}/#{host_data['lifetime']} hours" duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
metadata = [host_data['template'], duration, *tag_pairs] metadata = [host_data['template'], duration, *tag_pairs]
STDOUT.puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})" puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})"
when 'NonstandardPooler' when 'NonstandardPooler'
line = "- #{host_data['fqdn']} (#{host_data['os_triple']}" line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
line += ", #{host_data['hours_left_on_reservation']}h remaining" line += ", #{host_data['hours_left_on_reservation']}h remaining"
line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty? line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
line += ')' line += ')'
STDOUT.puts line puts line
else else
raise "Invalid service type #{service.type}" raise "Invalid service type #{service.type}"
end end
rescue StandardError => e rescue StandardError => e
STDERR.puts("Something went wrong while trying to gather information on #{hostname}:") Vmfloaty.logger.error("Something went wrong while trying to gather information on #{hostname}:")
STDERR.puts(e) Vmfloaty.logger.error(e)
end end
end end
end end
@ -133,12 +132,12 @@ class Utils
pending = pool['pending'] pending = pool['pending']
missing = max - ready - pending missing = max - ready - pending
char = 'o' char = 'o'
STDOUT.puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}" puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
rescue StandardError => e rescue StandardError => e
STDERR.puts "#{name.ljust(width)} #{e.red}" Vmfloaty.logger.error "#{name.ljust(width)} #{e.red}"
end end
end end
STDOUT.puts message.colorize(status_response['status']['ok'] ? :default : :red) puts message.colorize(status_response['status']['ok'] ? :default : :red)
when 'NonstandardPooler' when 'NonstandardPooler'
pools = status_response pools = status_response
pools.delete 'ok' pools.delete 'ok'
@ -152,14 +151,14 @@ class Utils
pending = pool['pending'] || 0 # not available for nspooler pending = pool['pending'] || 0 # not available for nspooler
missing = max - ready - pending missing = max - ready - pending
char = 'o' char = 'o'
STDOUT.puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}" puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
rescue StandardError => e rescue StandardError => e
STDERR.puts "#{name.ljust(width)} #{e.red}" Vmfloaty.logger.error "#{name.ljust(width)} #{e.red}"
end end
end end
when 'ABS' when 'ABS'
STDERR.puts 'ABS Not OK'.red unless status_response Vmfloaty.logger.error 'ABS Not OK' unless status_response
STDOUT.puts 'ABS is OK'.green if status_response puts 'ABS is OK'.green if status_response
else else
raise "Invalid service type #{service.type}" raise "Invalid service type #{service.type}"
end end