From 40072e90e45c6427839cdc8cea81139f567c4d85 Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Fri, 21 Aug 2020 11:42:12 -0700 Subject: [PATCH 1/8] Fix `print_to_stderr` option for Utils.pretty_print_hosts Previously this option had no effect on the output. This commit makes the option effective and also refactors the tests for this method to cover this case. --- lib/vmfloaty/utils.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/vmfloaty/utils.rb b/lib/vmfloaty/utils.rb index 9478d04..f6d69ef 100644 --- a/lib/vmfloaty/utils.rb +++ b/lib/vmfloaty/utils.rb @@ -85,6 +85,8 @@ class Utils end def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false, indent = 0) + output_target = print_to_stderr ? $stderr : $stdout + fetched_data = self.get_host_data(verbose, service, hostnames) fetched_data.each do |hostname, host_data| case service.type @@ -96,7 +98,8 @@ class Utils vmpooler_service = service.clone vmpooler_service.silent = true vmpooler_service.maybe_use_vmpooler - puts "- [JobID:#{host_data['request']['job']['id']}] <#{host_data['state']}>" + output_target.puts "- [JobID:#{host_data['request']['job']['id']}] <#{host_data['state']}>" + host_data['allocated_resources'].each do |vm_name, _i| self.pretty_print_hosts(verbose, vmpooler_service, vm_name['hostname'].split('.')[0], print_to_stderr, indent+2) end @@ -105,13 +108,13 @@ class Utils tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil? duration = "#{host_data['running']}/#{host_data['lifetime']} hours" metadata = [host_data['template'], duration, *tag_pairs] - puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})".gsub(/^/, ' ' * indent) + output_target.puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})".gsub(/^/, ' ' * indent) when 'NonstandardPooler' line = "- #{host_data['fqdn']} (#{host_data['os_triple']}" line += ", #{host_data['hours_left_on_reservation']}h remaining" line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty? line += ')' - puts line + output_target.puts line else raise "Invalid service type #{service.type}" end From b31f44fb40d2f711ff4267e250b1fbc67e9fb447 Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Fri, 21 Aug 2020 11:43:36 -0700 Subject: [PATCH 2/8] Add `--hostnameonly` option to `floaty list --active` Adds an option to the `floaty list` subcommand so that, when listing active hosts, floaty will output just the hostnames, without any additional information or formatting. Hostnames will be separated by a newline. This functionality is primarily intended for consuming by tooling (such as the tab completion scripts). --- lib/vmfloaty.rb | 5 +++ lib/vmfloaty/utils.rb | 15 +++++++ spec/vmfloaty/utils_spec.rb | 83 +++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/lib/vmfloaty.rb b/lib/vmfloaty.rb index e1cbb20..7d015f3 100644 --- a/lib/vmfloaty.rb +++ b/lib/vmfloaty.rb @@ -88,6 +88,7 @@ class Vmfloaty c.option '--service STRING', String, 'Configured pooler service name' c.option '--active', 'Prints information about active vms for a given token' c.option '--json', 'Prints information as JSON' + c.option '--hostnameonly', 'When listing active vms, prints only hostnames, one per line' c.option '--token STRING', String, 'Token for pooler service' c.option '--url STRING', String, 'URL of pooler service' c.option '--user STRING', String, 'User to authenticate with' @@ -115,6 +116,10 @@ class Vmfloaty else if options.json puts Utils.get_host_data(verbose, service, running_vms).to_json + elsif options.hostnameonly + Utils.get_host_data(verbose, service, running_vms).each do |hostname, host_data| + Utils.print_fqdn_for_host(service, hostname, host_data) + end else puts "Your VMs on #{host}:" Utils.pretty_print_hosts(verbose, service, running_vms) diff --git a/lib/vmfloaty/utils.rb b/lib/vmfloaty/utils.rb index f6d69ef..65cc053 100644 --- a/lib/vmfloaty/utils.rb +++ b/lib/vmfloaty/utils.rb @@ -84,6 +84,21 @@ class Utils os_types end + def self.print_fqdn_for_host(service, hostname, host_data) + case service.type + when 'ABS' + host_data['allocated_resources'].each do |vm_name, _i| + puts vm_name['hostname'] + end + when 'Pooler' + puts "#{hostname}.#{host_data['domain']}" + when 'NonstandardPooler' + puts host_data['fqdn'] + else + raise "Invalid service type #{service.type}" + end + end + def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false, indent = 0) output_target = print_to_stderr ? $stderr : $stdout diff --git a/spec/vmfloaty/utils_spec.rb b/spec/vmfloaty/utils_spec.rb index 3941eb2..48f6a3e 100644 --- a/spec/vmfloaty/utils_spec.rb +++ b/spec/vmfloaty/utils_spec.rb @@ -162,6 +162,89 @@ describe Utils do end end + describe '#print_fqdn_for_host' do + let(:url) { 'http://pooler.example.com' } + + subject { Utils.print_fqdn_for_host(service, hostname, host_data) } + + describe 'with vmpooler host' do + let(:service) { Service.new(MockOptions.new, 'url' => url) } + let(:hostname) { 'mcpy42eqjxli9g2' } + let(:domain) { 'delivery.mycompany.net' } + let(:fqdn) { [hostname, domain].join('.') } + + let(:host_data) do + { + 'template' => 'ubuntu-1604-x86_64', + 'lifetime' => 12, + 'running' => 9.66, + 'state' => 'running', + 'ip' => '127.0.0.1', + 'domain' => domain, + } + end + + it 'outputs fqdn for host' do + expect(STDOUT).to receive(:puts).with(fqdn) + + subject + end + end + + describe 'with nonstandard pooler host' do + let(:service) { Service.new(MockOptions.new, 'url' => url, 'type' => 'ns') } + let(:hostname) { 'sol11-9.delivery.mycompany.net' } + let(:host_data) do + { + 'fqdn' => hostname, + 'os_triple' => 'solaris-11-sparc', + 'reserved_by_user' => 'first.last', + 'reserved_for_reason' => '', + 'hours_left_on_reservation' => 35.89, + } + end + let(:fqdn) { hostname } # for nspooler these are the same + + it 'outputs fqdn for host' do + expect(STDOUT).to receive(:puts).with(fqdn) + + subject + end + end + + describe 'with ABS host' do + let(:service) { Service.new(MockOptions.new, 'url' => url, 'type' => 'abs') } + let(:hostname) { '1597952189390' } + let(:fqdn) { 'example-noun.delivery.puppetlabs.net' } + let(:template) { 'ubuntu-1604-x86_64' } + + # This seems to be the miminal stub response from ABS for the current output + let(:host_data) do + { + 'state' => 'allocated', + 'allocated_resources' => [ + { + 'hostname' => fqdn, + 'type' => template, + 'enging' => 'vmpooler', + }, + ], + 'request' => { + 'job' => { + 'id' => hostname, + } + }, + } + end + + it 'outputs fqdn for host' do + expect(STDOUT).to receive(:puts).with(fqdn) + + subject + end + end + end + describe '#pretty_print_hosts' do let(:url) { 'http://pooler.example.com' } From 57e7542f7312676f77f7aa86a6edd1f3ef34c667 Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Fri, 21 Aug 2020 11:46:10 -0700 Subject: [PATCH 3/8] Add tab completion script for zsh This commit adds a new tab completion script for zsh. It also fixes the completion script for bash to work with ABS backends. --- extras/completions/floaty.bash | 2 +- extras/completions/floaty.zsh | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 extras/completions/floaty.zsh diff --git a/extras/completions/floaty.bash b/extras/completions/floaty.bash index 5adee75..0c18c49 100644 --- a/extras/completions/floaty.bash +++ b/extras/completions/floaty.bash @@ -21,7 +21,7 @@ _vmfloaty() COMPREPLY=( $(compgen -W "${_vmfloaty_avail_templates}" -- "${cur}") ) elif [[ $hostname_subcommands =~ (^| )$prev($| ) ]] ; then - _vmfloaty_active_hostnames=$(floaty list --active 2>/dev/null | grep '^-' | cut -d' ' -f2) + _vmfloaty_active_hostnames=$(floaty list --active --hostnameonly 2>/dev/null) COMPREPLY=( $(compgen -W "${_vmfloaty_active_hostnames}" -- "${cur}") ) else COMPREPLY=( $(compgen -W "${subcommands}" -- "${cur}") ) diff --git a/extras/completions/floaty.zsh b/extras/completions/floaty.zsh new file mode 100644 index 0000000..77edf17 --- /dev/null +++ b/extras/completions/floaty.zsh @@ -0,0 +1,37 @@ +_floaty() +{ + local line subcommands template_subcommands hostname_subcommands + + subcommands="delete get help list modify query revert snapshot ssh status summary token" + + template_subcommands=("get" "ssh") + hostname_subcommands=("delete" "modify" "query" "revert" "snapshot") + + _arguments -C \ + "1: :(${subcommands})" \ + "*::arg:->args" + + if ((template_subcommands[(Ie)$line[1]])); then + _floaty_template_sub + elif ((hostname_subcommands[(Ie)$line[1]])); then + _floaty_hostname_sub + fi +} + +_floaty_template_sub() +{ + if [[ -z "$_vmfloaty_avail_templates" ]] ; then + _vmfloaty_avail_templates=$(floaty list 2>/dev/null) + fi + + _arguments "1: :(${_vmfloaty_avail_templates})" +} + +_floaty_hostname_sub() +{ + _vmfloaty_active_hostnames=$(floaty list --active --hostnameonly 2>/dev/null) + + _arguments "1: :(${_vmfloaty_active_hostnames})" +} + +compdef _floaty floaty From dee735e017cc709cea06d2a107f14f49b66a4fde Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Mon, 24 Aug 2020 16:22:03 -0700 Subject: [PATCH 4/8] (FIXUP) Collect hostnames in array before outputting --- lib/vmfloaty/utils.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/vmfloaty/utils.rb b/lib/vmfloaty/utils.rb index 65cc053..1f2418a 100644 --- a/lib/vmfloaty/utils.rb +++ b/lib/vmfloaty/utils.rb @@ -87,9 +87,13 @@ class Utils def self.print_fqdn_for_host(service, hostname, host_data) case service.type when 'ABS' + abs_hostnames = [] + host_data['allocated_resources'].each do |vm_name, _i| - puts vm_name['hostname'] + abs_hostnames << vm_name['hostname'] end + + puts abs_hostnames.join("\n") when 'Pooler' puts "#{hostname}.#{host_data['domain']}" when 'NonstandardPooler' From e269d71fea047c9c6afafa12b810041eb643a6a6 Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Mon, 21 Sep 2020 16:58:50 -0700 Subject: [PATCH 5/8] Add README for zsh tab completion --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 83e94cc..54e246e 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,12 @@ If you are running on macOS and use Homebrew's `bash-completion` formula, you ca ln -s $(floaty completion --shell bash) /usr/local/etc/bash_completion.d/floaty ``` +There is also tab completion for zsh: + +```zsh +source $(floaty completion --shell zsh) +``` + ## vmpooler API This cli tool uses the [vmpooler API](https://github.com/puppetlabs/vmpooler/blob/master/API.md). From 8546c1c4b67cae464ecf96baa29112e342dbe4d9 Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Mon, 21 Sep 2020 16:59:04 -0700 Subject: [PATCH 6/8] WIP: fixup specs after rebase --- spec/vmfloaty/utils_spec.rb | 240 +++++++++++++++++++++++++----------- 1 file changed, 169 insertions(+), 71 deletions(-) diff --git a/spec/vmfloaty/utils_spec.rb b/spec/vmfloaty/utils_spec.rb index 48f6a3e..af3a3fa 100644 --- a/spec/vmfloaty/utils_spec.rb +++ b/spec/vmfloaty/utils_spec.rb @@ -247,95 +247,193 @@ describe Utils do describe '#pretty_print_hosts' do let(:url) { 'http://pooler.example.com' } + let(:verbose) { nil } + let(:print_to_stderr) { false } - it 'prints a vmpooler output with host fqdn, template and duration info' do - hostname = 'mcpy42eqjxli9g2' - response_body = { hostname => { - 'template' => 'ubuntu-1604-x86_64', - 'lifetime' => 12, - 'running' => 9.66, - 'state' => 'running', - 'ip' => '127.0.0.1', - 'domain' => 'delivery.mycompany.net', - } } - output = '- mcpy42eqjxli9g2.delivery.mycompany.net (ubuntu-1604-x86_64, 9.66/12 hours)' - - expect(STDOUT).to receive(:puts).with(output) - - service = Service.new(MockOptions.new, 'url' => url) + before(:each) do allow(service).to receive(:query) - .with(nil, hostname) + .with(anything, hostname) .and_return(response_body) - - Utils.pretty_print_hosts(nil, service, hostname) end - it 'prints a vmpooler output with host fqdn, template, duration info, and tags when supplied' do - hostname = 'aiydvzpg23r415q' - response_body = { hostname => { - 'template' => 'redhat-7-x86_64', - 'lifetime' => 48, - 'running' => 7.67, - 'state' => 'running', - 'tags' => { - 'user' => 'bob', - 'role' => 'agent', - }, - 'ip' => '127.0.0.1', - 'domain' => 'delivery.mycompany.net', - } } - output = '- aiydvzpg23r415q.delivery.mycompany.net (redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)' + subject { Utils.pretty_print_hosts(verbose, service, hostname, print_to_stderr) } - expect(STDOUT).to receive(:puts).with(output) + describe 'with vmpooler service' do + let(:service) { Service.new(MockOptions.new, 'url' => url) } - service = Service.new(MockOptions.new, 'url' => url) - allow(service).to receive(:query) - .with(nil, hostname) - .and_return(response_body) + let(:hostname) { 'mcpy42eqjxli9g2' } + let(:domain) { 'delivery.mycompany.net' } + let(:fqdn) { [hostname, domain].join('.') } - Utils.pretty_print_hosts(nil, service, hostname) + let(:response_body) do + { + hostname => { + 'template' => 'ubuntu-1604-x86_64', + 'lifetime' => 12, + 'running' => 9.66, + 'state' => 'running', + 'ip' => '127.0.0.1', + 'domain' => domain, + } + } + end + + let(:default_output) { "- #{fqdn} (ubuntu-1604-x86_64, 9.66/12 hours)" } + + it 'prints output with host fqdn, template and duration info' do + expect(STDOUT).to receive(:puts).with(default_output) + + subject + end + + context 'when tags are supplied' do + let(:hostname) { 'aiydvzpg23r415q' } + let(:response_body) do + { + hostname => { + 'template' => 'redhat-7-x86_64', + 'lifetime' => 48, + 'running' => 7.67, + 'state' => 'running', + 'tags' => { + 'user' => 'bob', + 'role' => 'agent', + }, + 'ip' => '127.0.0.1', + 'domain' => domain, + } + } + end + + it 'prints output with host fqdn, template, duration info, and tags' do + output = "- #{fqdn} (redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)" + + expect(STDOUT).to receive(:puts).with(output) + + subject + end + end + + context 'when print_to_stderr option is true' do + let(:print_to_stderr) { true } + + it 'outputs to stderr instead of stdout' do + expect(STDERR).to receive(:puts).with(default_output) + + subject + end + end end - it 'prints a nonstandard pooler output with host, template, and time remaining' do - hostname = 'sol11-9.delivery.mycompany.net' - response_body = { hostname => { - 'fqdn' => hostname, - 'os_triple' => 'solaris-11-sparc', - 'reserved_by_user' => 'first.last', - 'reserved_for_reason' => '', - 'hours_left_on_reservation' => 35.89, - } } - output = '- sol11-9.delivery.mycompany.net (solaris-11-sparc, 35.89h remaining)' + describe 'with nonstandard pooler service' do + let(:service) { Service.new(MockOptions.new, 'url' => url, 'type' => 'ns') } - expect(STDOUT).to receive(:puts).with(output) + let(:hostname) { 'sol11-9.delivery.mycompany.net' } + let(:response_body) do + { + hostname => { + 'fqdn' => hostname, + 'os_triple' => 'solaris-11-sparc', + 'reserved_by_user' => 'first.last', + 'reserved_for_reason' => '', + 'hours_left_on_reservation' => 35.89, + } + } + end - service = Service.new(MockOptions.new, 'url' => url, 'type' => 'ns') - allow(service).to receive(:query) - .with(nil, hostname) - .and_return(response_body) + let(:default_output) { "- #{hostname} (solaris-11-sparc, 35.89h remaining)" } - Utils.pretty_print_hosts(nil, service, hostname) + it 'prints output with host, template, and time remaining' do + expect(STDOUT).to receive(:puts).with(default_output) + + subject + end + + context 'when reason is supplied' do + let(:response_body) do + { + hostname => { + 'fqdn' => hostname, + 'os_triple' => 'solaris-11-sparc', + 'reserved_by_user' => 'first.last', + 'reserved_for_reason' => 'testing', + 'hours_left_on_reservation' => 35.89, + } + } + end + + it 'prints output with host, template, time remaining, and reason' do + output = '- sol11-9.delivery.mycompany.net (solaris-11-sparc, 35.89h remaining, reason: testing)' + + expect(STDOUT).to receive(:puts).with(output) + + subject + end + end + + context 'when print_to_stderr option is true' do + let(:print_to_stderr) { true } + + it 'outputs to stderr instead of stdout' do + expect(STDERR).to receive(:puts).with(default_output) + + subject + end + end end - it 'prints a nonstandard pooler output with host, template, time remaining, and reason' do - hostname = 'sol11-9.delivery.mycompany.net' - response_body = { hostname => { - 'fqdn' => hostname, - 'os_triple' => 'solaris-11-sparc', - 'reserved_by_user' => 'first.last', - 'reserved_for_reason' => 'testing', - 'hours_left_on_reservation' => 35.89, - } } - output = '- sol11-9.delivery.mycompany.net (solaris-11-sparc, 35.89h remaining, reason: testing)' + describe 'with ABS service' do + let(:service) { Service.new(MockOptions.new, 'url' => url, 'type' => 'abs') } - expect(STDOUT).to receive(:puts).with(output) + let(:hostname) { '1597952189390' } + let(:fqdn) { 'example-noun.delivery.puppetlabs.net' } + let(:template) { 'ubuntu-1604-x86_64' } - service = Service.new(MockOptions.new, 'url' => url, 'type' => 'ns') - allow(service).to receive(:query) - .with(nil, hostname) - .and_return(response_body) + # This seems to be the miminal stub response from ABS for the current output + let(:response_body) do + { + hostname => { + 'state' => 'allocated', + 'allocated_resources' => [ + { + 'hostname' => fqdn, + 'type' => template, + 'engine' => 'vmpooler', + }, + ], + 'request' => { + 'job' => { + 'id' => hostname, + } + }, + } + } + end - Utils.pretty_print_hosts(nil, service, hostname) + let(:default_output) { "- [JobID:#{hostname}] #{fqdn} (#{template}) " } + + before(:each) do + allow(Utils).to receive(:get_vmpooler_service_config).and_return({ + 'url' => 'http://vmpooler.example.com', + 'token' => 'krypto-knight' + }) + end + + it 'prints output with job id, host, and template' do + expect(STDOUT).to receive(:puts).with(default_output) + + subject + end + + context 'when print_to_stderr option is true' do + let(:print_to_stderr) { true } + + it 'outputs to stderr instead of stdout' do + expect(STDERR).to receive(:puts).with(default_output) + + subject + end + end end end From 45f0ef031edde2e2da95f5a896f73844a7725334 Mon Sep 17 00:00:00 2001 From: Samuel Beaulieu Date: Tue, 22 Sep 2020 09:15:15 -0500 Subject: [PATCH 7/8] Fix spec tests for ABS pretty print ABS now returns the ABS job_id on the first line, then every vmpooler hostname indented. It queries them from vmpooler to get the metadata like lifetime etc --- spec/vmfloaty/utils_spec.rb | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/spec/vmfloaty/utils_spec.rb b/spec/vmfloaty/utils_spec.rb index af3a3fa..561c38b 100644 --- a/spec/vmfloaty/utils_spec.rb +++ b/spec/vmfloaty/utils_spec.rb @@ -387,6 +387,7 @@ describe Utils do let(:hostname) { '1597952189390' } let(:fqdn) { 'example-noun.delivery.puppetlabs.net' } + let(:fqdn_hostname) {'example-noun'} let(:template) { 'ubuntu-1604-x86_64' } # This seems to be the miminal stub response from ABS for the current output @@ -410,17 +411,41 @@ describe Utils do } end - let(:default_output) { "- [JobID:#{hostname}] #{fqdn} (#{template}) " } + # The vmpooler response contains metadata that is printed + let(:domain) { 'delivery.mycompany.net' } + let(:response_body_vmpooler) do + { + fqdn_hostname => { + 'template' => 'redhat-7-x86_64', + 'lifetime' => 48, + 'running' => 7.67, + 'state' => 'running', + 'tags' => { + 'user' => 'bob', + 'role' => 'agent', + }, + 'ip' => '127.0.0.1', + 'domain' => domain, + } + } + end before(:each) do allow(Utils).to receive(:get_vmpooler_service_config).and_return({ 'url' => 'http://vmpooler.example.com', 'token' => 'krypto-knight' }) + allow(service).to receive(:query) + .with(anything, fqdn_hostname) + .and_return(response_body_vmpooler) end + let(:default_output_first_line) { "- [JobID:#{hostname}] " } + let(:default_output_second_line) { " - example-noun.delivery.mycompany.net (redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)" } + it 'prints output with job id, host, and template' do - expect(STDOUT).to receive(:puts).with(default_output) + expect(STDOUT).to receive(:puts).with(default_output_first_line) + expect(STDOUT).to receive(:puts).with(default_output_second_line) subject end @@ -429,7 +454,8 @@ describe Utils do let(:print_to_stderr) { true } it 'outputs to stderr instead of stdout' do - expect(STDERR).to receive(:puts).with(default_output) + expect(STDERR).to receive(:puts).with(default_output_first_line) + expect(STDERR).to receive(:puts).with(default_output_second_line) subject end From 2b56448d50b0d4fbddcae72c4ac08d9ae760ea93 Mon Sep 17 00:00:00 2001 From: Samuel Beaulieu Date: Tue, 22 Sep 2020 09:53:13 -0500 Subject: [PATCH 8/8] Fix pretty print when multiple backend services are returned by ABS. Added test with vmpooler and nspooler result --- lib/vmfloaty/utils.rb | 16 +++--- spec/vmfloaty/utils_spec.rb | 97 +++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/lib/vmfloaty/utils.rb b/lib/vmfloaty/utils.rb index 1f2418a..a569415 100644 --- a/lib/vmfloaty/utils.rb +++ b/lib/vmfloaty/utils.rb @@ -114,13 +114,17 @@ class Utils # # Create a vmpooler service to query each hostname there so as to get the metadata too - vmpooler_service = service.clone - vmpooler_service.silent = true - vmpooler_service.maybe_use_vmpooler output_target.puts "- [JobID:#{host_data['request']['job']['id']}] <#{host_data['state']}>" - - host_data['allocated_resources'].each do |vm_name, _i| - self.pretty_print_hosts(verbose, vmpooler_service, vm_name['hostname'].split('.')[0], print_to_stderr, indent+2) + host_data['allocated_resources'].each do |allocated_resources, _i| + if allocated_resources['engine'] == "vmpooler" + vmpooler_service = service.clone + vmpooler_service.silent = true + vmpooler_service.maybe_use_vmpooler + self.pretty_print_hosts(verbose, vmpooler_service, allocated_resources['hostname'].split('.')[0], print_to_stderr, indent+2) + else + #TODO we could add more specific metadata for the other services, nspooler and aws + output_target.puts " - #{allocated_resources['hostname']} (#{allocated_resources['type']})" + end end when 'Pooler' tag_pairs = [] diff --git a/spec/vmfloaty/utils_spec.rb b/spec/vmfloaty/utils_spec.rb index 561c38b..e26e0f1 100644 --- a/spec/vmfloaty/utils_spec.rb +++ b/spec/vmfloaty/utils_spec.rb @@ -386,7 +386,7 @@ describe Utils do let(:service) { Service.new(MockOptions.new, 'url' => url, 'type' => 'abs') } let(:hostname) { '1597952189390' } - let(:fqdn) { 'example-noun.delivery.puppetlabs.net' } + let(:fqdn) { 'example-noun.delivery.mycompany.net' } let(:fqdn_hostname) {'example-noun'} let(:template) { 'ubuntu-1604-x86_64' } @@ -416,7 +416,7 @@ describe Utils do let(:response_body_vmpooler) do { fqdn_hostname => { - 'template' => 'redhat-7-x86_64', + 'template' => template, 'lifetime' => 48, 'running' => 7.67, 'state' => 'running', @@ -441,7 +441,7 @@ describe Utils do end let(:default_output_first_line) { "- [JobID:#{hostname}] " } - let(:default_output_second_line) { " - example-noun.delivery.mycompany.net (redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)" } + let(:default_output_second_line) { " - #{fqdn} (#{template}, 7.67/48 hours, user: bob, role: agent)" } it 'prints output with job id, host, and template' do expect(STDOUT).to receive(:puts).with(default_output_first_line) @@ -461,6 +461,97 @@ describe Utils do end end end + + describe 'with ABS service returning vmpooler and nspooler resources' do + let(:service) { Service.new(MockOptions.new, 'url' => url, 'type' => 'abs') } + + let(:hostname) { '1597952189390' } + let(:fqdn) { 'this-noun.delivery.mycompany.net' } + let(:fqdn_ns) { 'that-noun.delivery.mycompany.net' } + let(:fqdn_hostname) {'this-noun'} + let(:fqdn_ns_hostname) {'that-noun'} + let(:template) { 'ubuntu-1604-x86_64' } + let(:template_ns) { 'solaris-10-sparc' } + + # This seems to be the miminal stub response from ABS for the current output + let(:response_body) do + { + hostname => { + 'state' => 'allocated', + 'allocated_resources' => [ + { + 'hostname' => fqdn, + 'type' => template, + 'engine' => 'vmpooler', + }, + { + 'hostname' => fqdn_ns, + 'type' => template_ns, + 'engine' => 'nspooler', + }, + ], + 'request' => { + 'job' => { + 'id' => hostname, + } + }, + } + } + end + + # The vmpooler response contains metadata that is printed + let(:domain) { 'delivery.mycompany.net' } + let(:response_body_vmpooler) do + { + fqdn_hostname => { + 'template' => template, + 'lifetime' => 48, + 'running' => 7.67, + 'state' => 'running', + 'tags' => { + 'user' => 'bob', + 'role' => 'agent', + }, + 'ip' => '127.0.0.1', + 'domain' => domain, + } + } + end + + before(:each) do + allow(Utils).to receive(:get_vmpooler_service_config).and_return({ + 'url' => 'http://vmpooler.example.com', + 'token' => 'krypto-knight' + }) + allow(service).to receive(:query) + .with(anything, fqdn_hostname) + .and_return(response_body_vmpooler) + end + + let(:default_output_first_line) { "- [JobID:#{hostname}] " } + let(:default_output_second_line) { " - #{fqdn} (#{template}, 7.67/48 hours, user: bob, role: agent)" } + let(:default_output_third_line) { " - #{fqdn_ns} (#{template_ns})" } + + it 'prints output with job id, host, and template' do + expect(STDOUT).to receive(:puts).with(default_output_first_line) + expect(STDOUT).to receive(:puts).with(default_output_second_line) + expect(STDOUT).to receive(:puts).with(default_output_third_line) + + subject + end + + context 'when print_to_stderr option is true' do + let(:print_to_stderr) { true } + + it 'outputs to stderr instead of stdout' do + expect(STDERR).to receive(:puts).with(default_output_first_line) + expect(STDERR).to receive(:puts).with(default_output_second_line) + expect(STDERR).to receive(:puts).with(default_output_third_line) + + subject + end + end + end end describe '#get_vmpooler_service_config' do