vmfloaty 0.9.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,11 +7,13 @@ require 'vmfloaty/ssh'
7
7
 
8
8
  class Service
9
9
  attr_reader :config
10
+ attr_accessor :silent
10
11
 
11
12
  def initialize(options, config_hash = {})
12
13
  options ||= Commander::Command::Options.new
13
14
  @config = Utils.get_service_config config_hash, options
14
15
  @service_object = Utils.get_service_object @config['type']
16
+ @silent = false
15
17
  end
16
18
 
17
19
  def method_missing(method_name, *args, &block)
@@ -36,7 +38,7 @@ class Service
36
38
 
37
39
  def user
38
40
  unless @config['user']
39
- puts "Enter your #{@config['url']} service username:"
41
+ FloatyLogger.info "Enter your #{@config['url']} service username:"
40
42
  @config['user'] = STDIN.gets.chomp
41
43
  end
42
44
  @config['user']
@@ -44,7 +46,7 @@ class Service
44
46
 
45
47
  def token
46
48
  unless @config['token']
47
- puts 'No token found. Retrieving a token...'
49
+ FloatyLogger.info 'No token found. Retrieving a token...'
48
50
  @config['token'] = get_new_token(nil)
49
51
  end
50
52
  @config['token']
@@ -75,10 +77,14 @@ class Service
75
77
  @service_object.list_active verbose, url, token, user
76
78
  end
77
79
 
78
- def retrieve(verbose, os_types, use_token = true)
79
- puts 'Requesting a vm without a token...' unless use_token
80
+ def retrieve(verbose, os_types, use_token = true, ondemand = nil)
81
+ FloatyLogger.info 'Requesting a vm without a token...' unless use_token
80
82
  token_value = use_token ? token : nil
81
- @service_object.retrieve verbose, os_types, token_value, url, user, @config
83
+ @service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand
84
+ end
85
+
86
+ def wait_for_request(verbose, requestid)
87
+ @service_object.wait_for_request verbose, requestid, url
82
88
  end
83
89
 
84
90
  def ssh(verbose, host_os, use_token = true)
@@ -87,20 +93,11 @@ class Service
87
93
  begin
88
94
  token_value = token || get_new_token(verbose)
89
95
  rescue TokenError => e
90
- STDERR.puts e
91
- STDERR.puts 'Could not get token... requesting vm without a token anyway...'
96
+ FloatyLogger.error e
97
+ FloatyLogger.info 'Could not get token... requesting vm without a token anyway...'
92
98
  end
93
99
  end
94
- Ssh.ssh(verbose, host_os, token_value, url)
95
- end
96
-
97
- def pretty_print_running(verbose, hostnames = [])
98
- if hostnames.empty?
99
- puts 'You have no running VMs.'
100
- else
101
- puts 'Running VMs:'
102
- @service_object.pretty_print_hosts(verbose, hostnames, url)
103
- end
100
+ Ssh.ssh(verbose, self, host_os, token_value)
104
101
  end
105
102
 
106
103
  def query(verbose, hostname)
@@ -108,6 +105,7 @@ class Service
108
105
  end
109
106
 
110
107
  def modify(verbose, hostname, modify_hash)
108
+ maybe_use_vmpooler
111
109
  @service_object.modify verbose, url, hostname, token, modify_hash
112
110
  end
113
111
 
@@ -120,18 +118,35 @@ class Service
120
118
  end
121
119
 
122
120
  def summary(verbose)
121
+ maybe_use_vmpooler
123
122
  @service_object.summary verbose, url
124
123
  end
125
124
 
126
125
  def snapshot(verbose, hostname)
126
+ maybe_use_vmpooler
127
127
  @service_object.snapshot verbose, url, hostname, token
128
128
  end
129
129
 
130
130
  def revert(verbose, hostname, snapshot_sha)
131
+ maybe_use_vmpooler
131
132
  @service_object.revert verbose, url, hostname, token, snapshot_sha
132
133
  end
133
134
 
134
135
  def disk(verbose, hostname, disk)
136
+ maybe_use_vmpooler
135
137
  @service_object.disk(verbose, url, hostname, token, disk)
136
138
  end
139
+
140
+ # some methods do not exist for ABS, and if possible should target the Pooler service
141
+ def maybe_use_vmpooler
142
+ if @service_object.is_a?(ABS.class)
143
+ if !self.silent
144
+ FloatyLogger.info "The service in use is ABS, but the requested method should run against vmpooler directly, using fallback_vmpooler config from ~/.vmfloaty.yml"
145
+ self.silent = true
146
+ end
147
+
148
+ @config = Utils.get_vmpooler_service_config(@config['vmpooler_fallback'])
149
+ @service_object = Pooler
150
+ end
151
+ end
137
152
  end
@@ -14,21 +14,27 @@ class Ssh
14
14
  nil
15
15
  end
16
16
 
17
- def self.ssh(verbose, host_os, token, url)
17
+ def self.command_string(verbose, service, host_os, use_token)
18
18
  ssh_path = which('ssh')
19
19
  raise 'Could not determine path to ssh' unless ssh_path
20
20
 
21
21
  os_types = {}
22
22
  os_types[host_os] = 1
23
23
 
24
- response = Pooler.retrieve(verbose, os_types, token, url)
25
- raise "Could not get vm from vmpooler:\n #{response}" unless response['ok']
24
+ response = service.retrieve(verbose, os_types, use_token)
25
+ raise "Could not get vm from #{service.type}:\n #{response}" unless response['ok']
26
26
 
27
27
  user = /win/.match?(host_os) ? 'Administrator' : 'root'
28
28
 
29
- hostname = "#{response[host_os]['hostname']}.#{response['domain']}"
30
- cmd = "#{ssh_path} #{user}@#{hostname}"
29
+ hostname = response[host_os]['hostname']
30
+ hostname = response[host_os]['hostname'][0] if response[host_os]['hostname'].is_a?(Array)
31
+ hostname = "#{hostname}.#{response['domain']}" unless hostname.end_with?('puppetlabs.net')
31
32
 
33
+ "#{ssh_path} #{user}@#{hostname}"
34
+ end
35
+
36
+ def self.ssh(verbose, service, host_os, use_token)
37
+ cmd = command_string(verbose, service, host_os, use_token)
32
38
  # TODO: Should this respect more ssh settings? Can it be configured
33
39
  # by users ssh config and does this respect those settings?
34
40
  Kernel.exec(cmd)
@@ -3,6 +3,7 @@
3
3
  require 'vmfloaty/abs'
4
4
  require 'vmfloaty/nonstandard_pooler'
5
5
  require 'vmfloaty/pooler'
6
+ require 'vmfloaty/conf'
6
7
 
7
8
  class Utils
8
9
  # TODO: Takes the json response body from an HTTP GET
@@ -45,7 +46,12 @@ class Utils
45
46
 
46
47
  result = {}
47
48
 
48
- response_body.each do |os, value|
49
+ # ABS has a job_id associated with hosts so pass that along
50
+ abs_job_id = response_body.delete('job_id')
51
+ result['job_id'] = abs_job_id unless abs_job_id.nil?
52
+
53
+ filtered_response_body = response_body.reject { |key, _| key == 'request_id' || key == 'ready' }
54
+ filtered_response_body.each do |os, value|
49
55
  hostnames = Array(value['hostname'])
50
56
  hostnames.map! { |host| "#{host}.#{domain}" } if domain
51
57
  result[os] = hostnames
@@ -56,7 +62,8 @@ class Utils
56
62
 
57
63
  def self.format_host_output(hosts)
58
64
  hosts.flat_map do |os, names|
59
- names.map { |name| "- #{name} (#{os})" }
65
+ # Assume hosts are stored in Arrays and ignore everything else
66
+ names.map { |name| "- #{name} (#{os})" } if names.is_a? Array
60
67
  end.join("\n")
61
68
  end
62
69
 
@@ -77,41 +84,96 @@ class Utils
77
84
  os_types
78
85
  end
79
86
 
80
- def self.pretty_print_hosts(verbose, service, hostnames = [])
87
+ def self.print_fqdn_for_host(service, hostname, host_data)
88
+ case service.type
89
+ when 'ABS'
90
+ abs_hostnames = []
91
+
92
+ host_data['allocated_resources'].each do |vm_name, _i|
93
+ abs_hostnames << vm_name['hostname']
94
+ end
95
+
96
+ puts abs_hostnames.join("\n")
97
+ when 'Pooler'
98
+ puts "#{hostname}.#{host_data['domain']}"
99
+ when 'NonstandardPooler'
100
+ puts host_data['fqdn']
101
+ else
102
+ raise "Invalid service type #{service.type}"
103
+ end
104
+ end
105
+
106
+ def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false, indent = 0)
107
+ output_target = print_to_stderr ? $stderr : $stdout
108
+
109
+ fetched_data = self.get_host_data(verbose, service, hostnames)
110
+ fetched_data.each do |hostname, host_data|
111
+ case service.type
112
+ when 'ABS'
113
+ # For ABS, 'hostname' variable is the jobID
114
+ #
115
+ # Create a vmpooler service to query each hostname there so as to get the metadata too
116
+
117
+ output_target.puts "- [JobID:#{host_data['request']['job']['id']}] <#{host_data['state']}>"
118
+ host_data['allocated_resources'].each do |allocated_resources, _i|
119
+ if allocated_resources['engine'] == "vmpooler"
120
+ vmpooler_service = service.clone
121
+ vmpooler_service.silent = true
122
+ vmpooler_service.maybe_use_vmpooler
123
+ self.pretty_print_hosts(verbose, vmpooler_service, allocated_resources['hostname'].split('.')[0], print_to_stderr, indent+2)
124
+ else
125
+ #TODO we could add more specific metadata for the other services, nspooler and aws
126
+ output_target.puts " - #{allocated_resources['hostname']} (#{allocated_resources['type']})"
127
+ end
128
+ end
129
+ when 'Pooler'
130
+ tag_pairs = []
131
+ tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
132
+ duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
133
+ metadata = [host_data['template'], duration, *tag_pairs]
134
+ output_target.puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})".gsub(/^/, ' ' * indent)
135
+ when 'NonstandardPooler'
136
+ line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
137
+ line += ", #{host_data['hours_left_on_reservation']}h remaining"
138
+ line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
139
+ line += ')'
140
+ output_target.puts line
141
+ else
142
+ raise "Invalid service type #{service.type}"
143
+ end
144
+ end
145
+ end
146
+
147
+ def self.get_host_data(verbose, service, hostnames = [])
148
+ result = {}
81
149
  hostnames = [hostnames] unless hostnames.is_a? Array
82
150
  hostnames.each do |hostname|
83
151
  begin
84
152
  response = service.query(verbose, hostname)
85
153
  host_data = response[hostname]
86
-
87
- case service.type
88
- when 'ABS'
89
- # For ABS, 'hostname' variable is the jobID
90
- if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
91
- host_data['allocated_resources'].each do |vm_name, _i|
92
- puts "- [JobID:#{host_data['request']['job']['id']}] #{vm_name['hostname']} (#{vm_name['type']}) <#{host_data['state']}>"
154
+ if block_given?
155
+ yield host_data result
156
+ else
157
+ case service.type
158
+ when 'ABS'
159
+ # For ABS, 'hostname' variable is the jobID
160
+ if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
161
+ result[hostname] = host_data
93
162
  end
163
+ when 'Pooler'
164
+ result[hostname] = host_data
165
+ when 'NonstandardPooler'
166
+ result[hostname] = host_data
167
+ else
168
+ raise "Invalid service type #{service.type}"
94
169
  end
95
- when 'Pooler'
96
- tag_pairs = []
97
- tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
98
- duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
99
- metadata = [host_data['template'], duration, *tag_pairs]
100
- puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})"
101
- when 'NonstandardPooler'
102
- line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
103
- line += ", #{host_data['hours_left_on_reservation']}h remaining"
104
- line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
105
- line += ')'
106
- puts line
107
- else
108
- raise "Invalid service type #{service.type}"
109
170
  end
110
171
  rescue StandardError => e
111
- STDERR.puts("Something went wrong while trying to gather information on #{hostname}:")
112
- STDERR.puts(e)
172
+ FloatyLogger.error("Something went wrong while trying to gather information on #{hostname}:")
173
+ FloatyLogger.error(e)
113
174
  end
114
175
  end
176
+ result
115
177
  end
116
178
 
117
179
  def self.pretty_print_status(verbose, service)
@@ -133,7 +195,7 @@ class Utils
133
195
  char = 'o'
134
196
  puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
135
197
  rescue StandardError => e
136
- puts "#{name.ljust(width)} #{e.red}"
198
+ FloatyLogger.error "#{name.ljust(width)} #{e.red}"
137
199
  end
138
200
  end
139
201
  puts message.colorize(status_response['status']['ok'] ? :default : :red)
@@ -152,11 +214,11 @@ class Utils
152
214
  char = 'o'
153
215
  puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
154
216
  rescue StandardError => e
155
- puts "#{name.ljust(width)} #{e.red}"
217
+ FloatyLogger.error "#{name.ljust(width)} #{e.red}"
156
218
  end
157
219
  end
158
220
  when 'ABS'
159
- puts 'ABS Not OK'.red unless status_response
221
+ FloatyLogger.error 'ABS Not OK' unless status_response
160
222
  puts 'ABS is OK'.green if status_response
161
223
  else
162
224
  raise "Invalid service type #{service.type}"
@@ -172,12 +234,15 @@ class Utils
172
234
  end
173
235
 
174
236
  def self.get_service_object(type = '')
175
- nspooler_strings = %w[ns nspooler nonstandard nonstandard_pooler]
176
237
  abs_strings = %w[abs alwaysbescheduling always_be_scheduling]
177
- if nspooler_strings.include? type.downcase
178
- NonstandardPooler
179
- elsif abs_strings.include? type.downcase
238
+ nspooler_strings = %w[ns nspooler nonstandard nonstandard_pooler]
239
+ vmpooler_strings = %w[vmpooler]
240
+ if abs_strings.include? type.downcase
180
241
  ABS
242
+ elsif nspooler_strings.include? type.downcase
243
+ NonstandardPooler
244
+ elsif vmpooler_strings.include? type.downcase
245
+ Pooler
181
246
  else
182
247
  Pooler
183
248
  end
@@ -205,6 +270,9 @@ class Utils
205
270
  # If the service is configured but some values are missing, use the top-level defaults to fill them in
206
271
  service_config.merge! config['services'][options.service]
207
272
  end
273
+ # No config file but service is declared on command line
274
+ elsif !config['services'] && options.service
275
+ service_config['type'] = options.service
208
276
  end
209
277
 
210
278
  # Prioritize an explicitly specified url, user, or token if the user provided one
@@ -215,4 +283,30 @@ class Utils
215
283
 
216
284
  service_config
217
285
  end
286
+
287
+ # This method gets the vmpooler service configured in ~/.vmfloaty
288
+ def self.get_vmpooler_service_config(vmpooler_fallback)
289
+ config = Conf.read_config
290
+ # The top-level url, user, and token values in the config file are treated as defaults
291
+ service_config = {
292
+ 'url' => config['url'],
293
+ 'user' => config['user'],
294
+ 'token' => config['token'],
295
+ 'type' => 'vmpooler',
296
+ }
297
+
298
+ # at a minimum, the url needs to be configured
299
+ if config['services'] && config['services'][vmpooler_fallback] && config['services'][vmpooler_fallback]['url']
300
+ # If the service is configured but some values are missing, use the top-level defaults to fill them in
301
+ service_config.merge! config['services'][vmpooler_fallback]
302
+ else
303
+ if vmpooler_fallback.nil?
304
+ raise ArgumentError, "The abs service should have a key named 'vmpooler_fallback' in ~/.vmfloaty.yml with a value that points to a vmpooler service name use this format:\nservices:\n myabs:\n url: 'http://abs.com'\n user: 'superman'\n token: 'kryptonite'\n vmpooler_fallback: 'myvmpooler'\n myvmpooler:\n url: 'http://vmpooler.com'\n user: 'superman'\n token: 'kryptonite'"
305
+ else
306
+ raise ArgumentError, "Could not find a configured service named '#{vmpooler_fallback}' in ~/.vmfloaty.yml use this format:\nservices:\n #{vmpooler_fallback}:\n url: 'http://vmpooler.com'\n user: 'superman'\n token: 'kryptonite'"
307
+ end
308
+ end
309
+
310
+ service_config
311
+ end
218
312
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Vmfloaty
4
- VERSION = '0.9.1'
4
+ VERSION = '1.0.0'
5
5
  end
6
+
@@ -1,5 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'simplecov'
4
+ require 'coveralls'
5
+
6
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
7
+ SimpleCov::Formatter::HTMLFormatter,
8
+ Coveralls::SimpleCov::Formatter
9
+ ])
10
+ SimpleCov.start do
11
+ add_filter %r{^/spec/}
12
+ end
13
+
3
14
  require 'vmfloaty'
4
15
  require 'webmock/rspec'
5
16
 
@@ -9,15 +9,60 @@ describe ABS do
9
9
  before :each do
10
10
  end
11
11
 
12
+ describe '#list' do
13
+ it 'skips empty platforms and lists aws' do
14
+ stub_request(:get, "http://foo/status/platforms/vmpooler").
15
+ to_return(:status => 200, :body => "", :headers => {})
16
+ stub_request(:get, "http://foo/status/platforms/ondemand_vmpooler").
17
+ to_return(:status => 200, :body => "", :headers => {})
18
+ stub_request(:get, "http://foo/status/platforms/nspooler").
19
+ to_return(:status => 200, :body => "", :headers => {})
20
+ body = '{
21
+ "aws_platforms": [
22
+ "amazon-6-x86_64",
23
+ "amazon-7-x86_64",
24
+ "amazon-7-arm64",
25
+ "centos-7-x86-64-west",
26
+ "redhat-8-arm64"
27
+ ]
28
+ }'
29
+ stub_request(:get, "http://foo/status/platforms/aws").
30
+ to_return(:status => 200, :body => body, :headers => {})
31
+
32
+
33
+ results = ABS.list(false, "http://foo")
34
+
35
+ expect(results).to include("amazon-6-x86_64", "amazon-7-x86_64", "amazon-7-arm64", "centos-7-x86-64-west", "redhat-8-arm64")
36
+ end
37
+ it 'legacy JSON string, prior to PR 306' do
38
+ stub_request(:get, "http://foo/status/platforms/vmpooler").
39
+ to_return(:status => 200, :body => "", :headers => {})
40
+ stub_request(:get, "http://foo/status/platforms/ondemand_vmpooler").
41
+ to_return(:status => 200, :body => "", :headers => {})
42
+ stub_request(:get, "http://foo/status/platforms/nspooler").
43
+ to_return(:status => 200, :body => "", :headers => {})
44
+ body = '{
45
+ "aws_platforms": "[\"amazon-6-x86_64\",\"amazon-7-x86_64\",\"amazon-7-arm64\",\"centos-7-x86-64-west\",\"redhat-8-arm64\"]"
46
+ }'
47
+ stub_request(:get, "http://foo/status/platforms/aws").
48
+ to_return(:status => 200, :body => body, :headers => {})
49
+
50
+ results = ABS.list(false, "http://foo")
51
+
52
+ expect(results).to include("amazon-6-x86_64", "amazon-7-x86_64", "amazon-7-arm64", "centos-7-x86-64-west", "redhat-8-arm64")
53
+ end
54
+ end
55
+
12
56
  describe '#format' do
13
- it 'returns an hash formatted like a vmpooler return' do
57
+ it 'returns an hash formatted like a vmpooler return, plus the job_id' do
58
+ job_id = "generated_by_floaty_12345"
14
59
  abs_formatted_response = [
15
60
  { 'hostname' => 'aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', 'engine' => 'vmpooler' },
16
61
  { 'hostname' => 'aaaaaaaaaaaaaab.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', 'engine' => 'vmpooler' },
17
62
  { 'hostname' => 'aaaaaaaaaaaaaac.delivery.puppetlabs.net', 'type' => 'ubuntu-7.2-x86_64', 'engine' => 'vmpooler' },
18
63
  ]
19
64
 
20
- vmpooler_formatted_response = ABS.translated(abs_formatted_response)
65
+ vmpooler_formatted_response = ABS.translated(abs_formatted_response, job_id)
21
66
 
22
67
  vmpooler_formatted_compare = {
23
68
  'centos-7.2-x86_64' => {},
@@ -29,6 +74,8 @@ describe ABS do
29
74
 
30
75
  vmpooler_formatted_compare['ok'] = true
31
76
 
77
+ vmpooler_formatted_compare['job_id'] = job_id
78
+
32
79
  expect(vmpooler_formatted_response).to eq(vmpooler_formatted_compare)
33
80
  vmpooler_formatted_response.delete('ok')
34
81
  vmpooler_formatted_compare.delete('ok')
@@ -65,14 +112,14 @@ describe ABS do
65
112
 
66
113
  describe '#test_abs_status_queue_endpoint' do
67
114
  before :each do
68
- # rubocop:disable Metrics/LineLength
115
+ # rubocop:disable Layout/LineLength
69
116
  @active_requests_response = '
70
117
  [
71
- "{ \"state\":\"allocated\",\"last_processed\":\"2019-12-16 23:00:34 +0000\",\"allocated_resources\":[{\"hostname\":\"take-this.delivery.puppetlabs.net\",\"type\":\"win-2012r2-x86_64\",\"engine\":\"vmpooler\"}],\"audit_log\":{\"2019-12-13 16:45:29 +0000\":\"Allocated take-this.delivery.puppetlabs.net for job 1576255517241\"},\"request\":{\"resources\":{\"win-2012r2-x86_64\":1},\"job\":{\"id\":\"1576255517241\",\"tags\":{\"user\":\"test-user\"},\"user\":\"test-user\",\"time-received\":1576255519},\"priority\":1}}",
118
+ { "state":"allocated","last_processed":"2019-12-16 23:00:34 +0000","allocated_resources":[{"hostname":"take-this.delivery.puppetlabs.net","type":"win-2012r2-x86_64","engine":"vmpooler"}],"audit_log":{"2019-12-13 16:45:29 +0000":"Allocated take-this.delivery.puppetlabs.net for job 1576255517241"},"request":{"resources":{"win-2012r2-x86_64":1},"job":{"id":"1576255517241","tags":{"user":"test-user"},"user":"test-user","time-received":1576255519},"priority":1}},
72
119
  "null",
73
- "{\"state\":\"allocated\",\"last_processed\":\"2019-12-16 23:00:34 +0000\",\"allocated_resources\":[{\"hostname\":\"not-this.delivery.puppetlabs.net\",\"type\":\"win-2012r2-x86_64\",\"engine\":\"vmpooler\"}],\"audit_log\":{\"2019-12-13 16:46:14 +0000\":\"Allocated not-this.delivery.puppetlabs.net for job 1576255565159\"},\"request\":{\"resources\":{\"win-2012r2-x86_64\":1},\"job\":{\"id\":\"1576255565159\",\"tags\":{\"user\":\"not-test-user\"},\"user\":\"not-test-user\",\"time-received\":1576255566},\"priority\":1}}"
120
+ {"state":"allocated","last_processed":"2019-12-16 23:00:34 +0000","allocated_resources":[{"hostname":"not-this.delivery.puppetlabs.net","type":"win-2012r2-x86_64","engine":"vmpooler"}],"audit_log":{"2019-12-13 16:46:14 +0000":"Allocated not-this.delivery.puppetlabs.net for job 1576255565159"},"request":{"resources":{"win-2012r2-x86_64":1},"job":{"id":"1576255565159","tags":{"user":"not-test-user"},"user":"not-test-user","time-received":1576255566},"priority":1}}
74
121
  ]'
75
- # rubocop:enable Metrics/LineLength
122
+ # rubocop:enable Layout/LineLength
76
123
  @token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
77
124
  @test_user = 'test-user'
78
125
  end
@@ -92,5 +139,35 @@ describe ABS do
92
139
  )
93
140
  end
94
141
  end
142
+
143
+ describe '#test_abs_delete_jobid' do
144
+ before :each do
145
+ # rubocop:disable Layout/LineLength
146
+ @active_requests_response = '
147
+ [
148
+ { "state":"allocated", "last_processed":"2020-01-17 22:29:13 +0000", "allocated_resources":[{"hostname":"craggy-chord.delivery.puppetlabs.net", "type":"centos-7-x86_64", "engine":"vmpooler"}, {"hostname":"visible-revival.delivery.puppetlabs.net", "type":"centos-7-x86_64", "engine":"vmpooler"}], "audit_log":{"2020-01-17 22:28:45 +0000":"Allocated craggy-chord.delivery.puppetlabs.net, visible-revival.delivery.puppetlabs.net for job 1579300120799"}, "request":{"resources":{"centos-7-x86_64":2}, "job":{"id":"1579300120799", "tags":{"user":"test-user"}, "user":"test-user", "time-received":1579300120}, "priority":3}}
149
+ ]'
150
+ @return_request = { '{"job_id":"1579300120799","hosts":{"hostname":"craggy-chord.delivery.puppetlabs.net","type":"centos-7-x86_64","engine":"vmpooler"},{"hostname":"visible-revival.delivery.puppetlabs.net","type":"centos-7-x86_64","engine":"vmpooler"}}'=>true }
151
+ # rubocop:enable Layout/LineLength
152
+ @token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
153
+ @test_user = 'test-user'
154
+ # Job ID
155
+ @hosts = ['1579300120799']
156
+ end
157
+
158
+ it 'will delete the whole job' do
159
+ stub_request(:get, 'https://abs.example.com/status/queue')
160
+ .to_return(:status => 200, :body => @active_requests_response, :headers => {})
161
+ stub_request(:post, 'https://abs.example.com/return')
162
+ .with(:body => @return_request)
163
+ .to_return(:status => 200, :body => 'OK', :headers => {})
164
+
165
+ ret = ABS.delete(false, @abs_url, @hosts, @token, @test_user)
166
+
167
+ expect(ret).to include(
168
+ 'craggy-chord.delivery.puppetlabs.net' => { 'ok'=>true }, 'visible-revival.delivery.puppetlabs.net' => { 'ok'=>true },
169
+ )
170
+ end
171
+ end
95
172
  end
96
173
  end