vmfloaty 0.8.2 → 0.11.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.
- checksums.yaml +5 -5
- data/README.md +96 -55
- data/bin/floaty +2 -1
- data/lib/vmfloaty.rb +66 -65
- data/lib/vmfloaty/abs.rb +318 -0
- data/lib/vmfloaty/auth.rb +14 -22
- data/lib/vmfloaty/conf.rb +4 -3
- data/lib/vmfloaty/errors.rb +6 -4
- data/lib/vmfloaty/http.rb +14 -25
- data/lib/vmfloaty/logger.rb +27 -0
- data/lib/vmfloaty/nonstandard_pooler.rb +15 -31
- data/lib/vmfloaty/pooler.rb +64 -55
- data/lib/vmfloaty/service.rb +26 -27
- data/lib/vmfloaty/ssh.rb +25 -25
- data/lib/vmfloaty/utils.rb +94 -84
- data/lib/vmfloaty/version.rb +3 -1
- data/spec/spec_helper.rb +13 -0
- data/spec/vmfloaty/abs/auth_spec.rb +84 -0
- data/spec/vmfloaty/abs_spec.rb +126 -0
- data/spec/vmfloaty/auth_spec.rb +39 -43
- data/spec/vmfloaty/nonstandard_pooler_spec.rb +132 -146
- data/spec/vmfloaty/pooler_spec.rb +121 -101
- data/spec/vmfloaty/service_spec.rb +17 -17
- data/spec/vmfloaty/ssh_spec.rb +49 -0
- data/spec/vmfloaty/utils_spec.rb +114 -113
- data/spec/vmfloaty/vmfloaty_services_spec.rb +39 -0
- metadata +39 -22
data/lib/vmfloaty/utils.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'vmfloaty/abs'
|
|
2
4
|
require 'vmfloaty/nonstandard_pooler'
|
|
5
|
+
require 'vmfloaty/pooler'
|
|
3
6
|
|
|
4
7
|
class Utils
|
|
5
8
|
# TODO: Takes the json response body from an HTTP GET
|
|
@@ -28,20 +31,24 @@ class Utils
|
|
|
28
31
|
# }
|
|
29
32
|
# }
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
# abs pooler response body example when `floaty get` arguments are :
|
|
35
|
+
# {
|
|
36
|
+
# "hostname"=>"thin-soutane.delivery.puppetlabs.net",
|
|
37
|
+
# "type"=>"centos-7.2-tmpfs-x86_64",
|
|
38
|
+
# "engine"=>"vmpooler"
|
|
39
|
+
# }
|
|
40
|
+
|
|
41
|
+
raise ArgumentError, "Bad GET response passed to format_hosts: #{response_body.to_json}" unless response_body.delete('ok')
|
|
34
42
|
|
|
35
43
|
# vmpooler reports the domain separately from the hostname
|
|
36
44
|
domain = response_body.delete('domain')
|
|
37
45
|
|
|
38
46
|
result = {}
|
|
39
47
|
|
|
40
|
-
response_body.
|
|
48
|
+
filtered_response_body = response_body.reject { |key, _| key == 'request_id' || key == 'ready' }
|
|
49
|
+
filtered_response_body.each do |os, value|
|
|
41
50
|
hostnames = Array(value['hostname'])
|
|
42
|
-
if domain
|
|
43
|
-
hostnames.map! {|host| "#{host}.#{domain}"}
|
|
44
|
-
end
|
|
51
|
+
hostnames.map! { |host| "#{host}.#{domain}" } if domain
|
|
45
52
|
result[os] = hostnames
|
|
46
53
|
end
|
|
47
54
|
|
|
@@ -65,18 +72,13 @@ class Utils
|
|
|
65
72
|
# ...]
|
|
66
73
|
os_types = {}
|
|
67
74
|
os_args.each do |arg|
|
|
68
|
-
os_arr = arg.split(
|
|
69
|
-
|
|
70
|
-
# assume they didn't specify an = sign if split returns 1 size
|
|
71
|
-
os_types[os_arr[0]] = 1
|
|
72
|
-
else
|
|
73
|
-
os_types[os_arr[0]] = os_arr[1].to_i
|
|
74
|
-
end
|
|
75
|
+
os_arr = arg.split('=')
|
|
76
|
+
os_types[os_arr[0]] = os_arr.size == 1 ? 1 : os_arr[1].to_i
|
|
75
77
|
end
|
|
76
78
|
os_types
|
|
77
79
|
end
|
|
78
80
|
|
|
79
|
-
def self.pretty_print_hosts(verbose, service, hostnames = [])
|
|
81
|
+
def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false)
|
|
80
82
|
hostnames = [hostnames] unless hostnames.is_a? Array
|
|
81
83
|
hostnames.each do |hostname|
|
|
82
84
|
begin
|
|
@@ -84,28 +86,31 @@ class Utils
|
|
|
84
86
|
host_data = response[hostname]
|
|
85
87
|
|
|
86
88
|
case service.type
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
|
|
93
|
-
metadata = [host_data['template'], duration, *tag_pairs]
|
|
94
|
-
puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(", ")})"
|
|
95
|
-
when 'NonstandardPooler'
|
|
96
|
-
line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
|
|
97
|
-
line += ", #{host_data['hours_left_on_reservation']}h remaining"
|
|
98
|
-
unless host_data['reserved_for_reason'].empty?
|
|
99
|
-
line += ", reason: #{host_data['reserved_for_reason']}"
|
|
89
|
+
when 'ABS'
|
|
90
|
+
# For ABS, 'hostname' variable is the jobID
|
|
91
|
+
if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
|
|
92
|
+
host_data['allocated_resources'].each do |vm_name, _i|
|
|
93
|
+
puts "- [JobID:#{host_data['request']['job']['id']}] #{vm_name['hostname']} (#{vm_name['type']}) <#{host_data['state']}>"
|
|
100
94
|
end
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
end
|
|
96
|
+
when 'Pooler'
|
|
97
|
+
tag_pairs = []
|
|
98
|
+
tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
|
|
99
|
+
duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
|
|
100
|
+
metadata = [host_data['template'], duration, *tag_pairs]
|
|
101
|
+
puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})"
|
|
102
|
+
when 'NonstandardPooler'
|
|
103
|
+
line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
|
|
104
|
+
line += ", #{host_data['hours_left_on_reservation']}h remaining"
|
|
105
|
+
line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
|
|
106
|
+
line += ')'
|
|
107
|
+
puts line
|
|
108
|
+
else
|
|
109
|
+
raise "Invalid service type #{service.type}"
|
|
105
110
|
end
|
|
106
|
-
rescue => e
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
rescue StandardError => e
|
|
112
|
+
FloatyLogger.error("Something went wrong while trying to gather information on #{hostname}:")
|
|
113
|
+
FloatyLogger.error(e)
|
|
109
114
|
end
|
|
110
115
|
end
|
|
111
116
|
end
|
|
@@ -114,45 +119,48 @@ class Utils
|
|
|
114
119
|
status_response = service.status(verbose)
|
|
115
120
|
|
|
116
121
|
case service.type
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
end
|
|
122
|
+
when 'Pooler'
|
|
123
|
+
message = status_response['status']['message']
|
|
124
|
+
pools = status_response['pools']
|
|
125
|
+
pools.select! { |_, pool| pool['ready'] < pool['max'] } unless verbose
|
|
126
|
+
|
|
127
|
+
width = pools.keys.map(&:length).max
|
|
128
|
+
pools.each do |name, pool|
|
|
129
|
+
begin
|
|
130
|
+
max = pool['max']
|
|
131
|
+
ready = pool['ready']
|
|
132
|
+
pending = pool['pending']
|
|
133
|
+
missing = max - ready - pending
|
|
134
|
+
char = 'o'
|
|
135
|
+
puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
|
|
136
|
+
rescue StandardError => e
|
|
137
|
+
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
|
|
134
138
|
end
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
139
|
+
end
|
|
140
|
+
puts message.colorize(status_response['status']['ok'] ? :default : :red)
|
|
141
|
+
when 'NonstandardPooler'
|
|
142
|
+
pools = status_response
|
|
143
|
+
pools.delete 'ok'
|
|
144
|
+
pools.select! { |_, pool| pool['available_hosts'] < pool['total_hosts'] } unless verbose
|
|
145
|
+
|
|
146
|
+
width = pools.keys.map(&:length).max
|
|
147
|
+
pools.each do |name, pool|
|
|
148
|
+
begin
|
|
149
|
+
max = pool['total_hosts']
|
|
150
|
+
ready = pool['available_hosts']
|
|
151
|
+
pending = pool['pending'] || 0 # not available for nspooler
|
|
152
|
+
missing = max - ready - pending
|
|
153
|
+
char = 'o'
|
|
154
|
+
puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
|
|
155
|
+
rescue StandardError => e
|
|
156
|
+
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
|
|
153
157
|
end
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
end
|
|
159
|
+
when 'ABS'
|
|
160
|
+
FloatyLogger.error 'ABS Not OK' unless status_response
|
|
161
|
+
puts 'ABS is OK'.green if status_response
|
|
162
|
+
else
|
|
163
|
+
raise "Invalid service type #{service.type}"
|
|
156
164
|
end
|
|
157
165
|
end
|
|
158
166
|
|
|
@@ -165,9 +173,12 @@ class Utils
|
|
|
165
173
|
end
|
|
166
174
|
|
|
167
175
|
def self.get_service_object(type = '')
|
|
168
|
-
nspooler_strings = [
|
|
176
|
+
nspooler_strings = %w[ns nspooler nonstandard nonstandard_pooler]
|
|
177
|
+
abs_strings = %w[abs alwaysbescheduling always_be_scheduling]
|
|
169
178
|
if nspooler_strings.include? type.downcase
|
|
170
179
|
NonstandardPooler
|
|
180
|
+
elsif abs_strings.include? type.downcase
|
|
181
|
+
ABS
|
|
171
182
|
else
|
|
172
183
|
Pooler
|
|
173
184
|
end
|
|
@@ -176,10 +187,10 @@ class Utils
|
|
|
176
187
|
def self.get_service_config(config, options)
|
|
177
188
|
# The top-level url, user, and token values in the config file are treated as defaults
|
|
178
189
|
service_config = {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
190
|
+
'url' => config['url'],
|
|
191
|
+
'user' => config['user'],
|
|
192
|
+
'token' => config['token'],
|
|
193
|
+
'type' => config['type'] || 'vmpooler',
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
if config['services']
|
|
@@ -190,16 +201,15 @@ class Utils
|
|
|
190
201
|
service_config.merge! values
|
|
191
202
|
else
|
|
192
203
|
# If the user provided a service name at the command line, use that service if posible, or fail
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
raise ArgumentError, "Could not find a configured service named '#{options.service}' in ~/.vmfloaty.yml"
|
|
198
|
-
end
|
|
204
|
+
raise ArgumentError, "Could not find a configured service named '#{options.service}' in ~/.vmfloaty.yml" unless config['services'][options.service]
|
|
205
|
+
|
|
206
|
+
# If the service is configured but some values are missing, use the top-level defaults to fill them in
|
|
207
|
+
service_config.merge! config['services'][options.service]
|
|
199
208
|
end
|
|
200
209
|
end
|
|
201
210
|
|
|
202
211
|
# Prioritize an explicitly specified url, user, or token if the user provided one
|
|
212
|
+
service_config['priority'] = options.priority unless options.priority.nil?
|
|
203
213
|
service_config['url'] = options.url unless options.url.nil?
|
|
204
214
|
service_config['token'] = options.token unless options.token.nil?
|
|
205
215
|
service_config['user'] = options.user unless options.user.nil?
|
data/lib/vmfloaty/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
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
|
+
|
|
1
14
|
require 'vmfloaty'
|
|
2
15
|
require 'webmock/rspec'
|
|
3
16
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require_relative '../../../lib/vmfloaty/auth'
|
|
5
|
+
|
|
6
|
+
describe Pooler do
|
|
7
|
+
before :each do
|
|
8
|
+
@abs_url = 'https://abs.example.com/api/v2'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#get_token' do
|
|
12
|
+
before :each do
|
|
13
|
+
@get_token_response = '{"ok": true,"token":"utpg2i2xswor6h8ttjhu3d47z53yy47y"}'
|
|
14
|
+
@token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'returns a token from abs' do
|
|
18
|
+
stub_request(:post, 'https://first.last:password@abs.example.com/api/v2/token')
|
|
19
|
+
.to_return(:status => 200, :body => @get_token_response, :headers => {})
|
|
20
|
+
|
|
21
|
+
token = Auth.get_token(false, @abs_url, 'first.last', 'password')
|
|
22
|
+
expect(token).to eq @token
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'raises a token error if something goes wrong' do
|
|
26
|
+
stub_request(:post, 'https://first.last:password@abs.example.com/api/v2/token')
|
|
27
|
+
.to_return(:status => 500, :body => '{"ok":false}', :headers => {})
|
|
28
|
+
|
|
29
|
+
expect { Auth.get_token(false, @abs_url, 'first.last', 'password') }.to raise_error(TokenError)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '#delete_token' do
|
|
34
|
+
before :each do
|
|
35
|
+
@delete_token_response = '{"ok":true}'
|
|
36
|
+
@token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'deletes the specified token' do
|
|
40
|
+
stub_request(:delete, 'https://first.last:password@abs.example.com/api/v2/token/utpg2i2xswor6h8ttjhu3d47z53yy47y')
|
|
41
|
+
.to_return(:status => 200, :body => @delete_token_response, :headers => {})
|
|
42
|
+
|
|
43
|
+
expect(Auth.delete_token(false, @abs_url, 'first.last', 'password', @token)).to eq JSON.parse(@delete_token_response)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'raises a token error if something goes wrong' do
|
|
47
|
+
stub_request(:delete, 'https://first.last:password@abs.example.com/api/v2/token/utpg2i2xswor6h8ttjhu3d47z53yy47y')
|
|
48
|
+
.to_return(:status => 500, :body => '{"ok":false}', :headers => {})
|
|
49
|
+
|
|
50
|
+
expect { Auth.delete_token(false, @abs_url, 'first.last', 'password', @token) }.to raise_error(TokenError)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'raises a token error if no token provided' do
|
|
54
|
+
expect { Auth.delete_token(false, @abs_url, 'first.last', 'password', nil) }.to raise_error(TokenError)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '#token_status' do
|
|
59
|
+
before :each do
|
|
60
|
+
@token_status_response = '{"ok":true,"utpg2i2xswor6h8ttjhu3d47z53yy47y":{"created":"2015-04-28 19:17:47 -0700"}}'
|
|
61
|
+
@token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'checks the status of a token' do
|
|
65
|
+
stub_request(:get, "#{@abs_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y")
|
|
66
|
+
.with(:headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3' })
|
|
67
|
+
.to_return(:status => 200, :body => @token_status_response, :headers => {})
|
|
68
|
+
|
|
69
|
+
expect(Auth.token_status(false, @abs_url, @token)).to eq JSON.parse(@token_status_response)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'raises a token error if something goes wrong' do
|
|
73
|
+
stub_request(:get, "#{@abs_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y")
|
|
74
|
+
.with(:headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3' })
|
|
75
|
+
.to_return(:status => 500, :body => '{"ok":false}', :headers => {})
|
|
76
|
+
|
|
77
|
+
expect { Auth.token_status(false, @abs_url, @token) }.to raise_error(TokenError)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'raises a token error if no token provided' do
|
|
81
|
+
expect { Auth.token_status(false, @abs_url, nil) }.to raise_error(TokenError)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'vmfloaty/utils'
|
|
5
|
+
require 'vmfloaty/errors'
|
|
6
|
+
require 'vmfloaty/abs'
|
|
7
|
+
|
|
8
|
+
describe ABS do
|
|
9
|
+
before :each do
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe '#format' do
|
|
13
|
+
it 'returns an hash formatted like a vmpooler return' do
|
|
14
|
+
abs_formatted_response = [
|
|
15
|
+
{ 'hostname' => 'aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', 'engine' => 'vmpooler' },
|
|
16
|
+
{ 'hostname' => 'aaaaaaaaaaaaaab.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', 'engine' => 'vmpooler' },
|
|
17
|
+
{ 'hostname' => 'aaaaaaaaaaaaaac.delivery.puppetlabs.net', 'type' => 'ubuntu-7.2-x86_64', 'engine' => 'vmpooler' },
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
vmpooler_formatted_response = ABS.translated(abs_formatted_response)
|
|
21
|
+
|
|
22
|
+
vmpooler_formatted_compare = {
|
|
23
|
+
'centos-7.2-x86_64' => {},
|
|
24
|
+
'ubuntu-7.2-x86_64' => {},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
vmpooler_formatted_compare['centos-7.2-x86_64']['hostname'] = ['aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'aaaaaaaaaaaaaab.delivery.puppetlabs.net']
|
|
28
|
+
vmpooler_formatted_compare['ubuntu-7.2-x86_64']['hostname'] = ['aaaaaaaaaaaaaac.delivery.puppetlabs.net']
|
|
29
|
+
|
|
30
|
+
vmpooler_formatted_compare['ok'] = true
|
|
31
|
+
|
|
32
|
+
expect(vmpooler_formatted_response).to eq(vmpooler_formatted_compare)
|
|
33
|
+
vmpooler_formatted_response.delete('ok')
|
|
34
|
+
vmpooler_formatted_compare.delete('ok')
|
|
35
|
+
expect(vmpooler_formatted_response).to eq(vmpooler_formatted_compare)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'won\'t delete a job if not all vms are listed' do
|
|
39
|
+
hosts = ['host1']
|
|
40
|
+
allocated_resources = [
|
|
41
|
+
{
|
|
42
|
+
'hostname' => 'host1',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
'hostname' => 'host2',
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
expect(ABS.all_job_resources_accounted_for(allocated_resources, hosts)).to eq(false)
|
|
49
|
+
|
|
50
|
+
hosts = ['host1', 'host2']
|
|
51
|
+
allocated_resources = [
|
|
52
|
+
{
|
|
53
|
+
'hostname' => 'host1',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
'hostname' => 'host2',
|
|
57
|
+
},
|
|
58
|
+
]
|
|
59
|
+
expect(ABS.all_job_resources_accounted_for(allocated_resources, hosts)).to eq(true)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
before :each do
|
|
63
|
+
@abs_url = 'https://abs.example.com'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#test_abs_status_queue_endpoint' do
|
|
67
|
+
before :each do
|
|
68
|
+
# rubocop:disable Layout/LineLength
|
|
69
|
+
@active_requests_response = '
|
|
70
|
+
[
|
|
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}}",
|
|
72
|
+
"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}}"
|
|
74
|
+
]'
|
|
75
|
+
# rubocop:enable Layout/LineLength
|
|
76
|
+
@token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
|
|
77
|
+
@test_user = 'test-user'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'will skip a line with a null value returned from abs' do
|
|
81
|
+
stub_request(:get, 'https://abs.example.com/status/queue')
|
|
82
|
+
.to_return(:status => 200, :body => @active_requests_response, :headers => {})
|
|
83
|
+
|
|
84
|
+
ret = ABS.get_active_requests(false, @abs_url, @test_user)
|
|
85
|
+
|
|
86
|
+
expect(ret[0]).to include(
|
|
87
|
+
'allocated_resources' => [{
|
|
88
|
+
'hostname' => 'take-this.delivery.puppetlabs.net',
|
|
89
|
+
'type' => 'win-2012r2-x86_64',
|
|
90
|
+
'engine' => 'vmpooler',
|
|
91
|
+
}],
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe '#test_abs_delete_jobid' do
|
|
97
|
+
before :each do
|
|
98
|
+
# rubocop:disable Layout/LineLength
|
|
99
|
+
@active_requests_response = '
|
|
100
|
+
[
|
|
101
|
+
"{ \"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}}"
|
|
102
|
+
]'
|
|
103
|
+
@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 }
|
|
104
|
+
# rubocop:enable Layout/LineLength
|
|
105
|
+
@token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
|
|
106
|
+
@test_user = 'test-user'
|
|
107
|
+
# Job ID
|
|
108
|
+
@hosts = ['1579300120799']
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'will delete the whole job' do
|
|
112
|
+
stub_request(:get, 'https://abs.example.com/status/queue')
|
|
113
|
+
.to_return(:status => 200, :body => @active_requests_response, :headers => {})
|
|
114
|
+
stub_request(:post, 'https://abs.example.com/return')
|
|
115
|
+
.with(:body => @return_request)
|
|
116
|
+
.to_return(:status => 200, :body => 'OK', :headers => {})
|
|
117
|
+
|
|
118
|
+
ret = ABS.delete(false, @abs_url, @hosts, @token, @test_user)
|
|
119
|
+
|
|
120
|
+
expect(ret).to include(
|
|
121
|
+
'craggy-chord.delivery.puppetlabs.net' => { 'ok'=>true }, 'visible-revival.delivery.puppetlabs.net' => { 'ok'=>true },
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|