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.
- checksums.yaml +4 -4
- data/README.md +84 -104
- data/extras/completions/floaty.bash +2 -2
- data/extras/completions/floaty.zsh +37 -0
- data/lib/vmfloaty.rb +154 -40
- data/lib/vmfloaty/abs.rb +152 -52
- data/lib/vmfloaty/conf.rb +1 -1
- data/lib/vmfloaty/logger.rb +27 -0
- data/lib/vmfloaty/nonstandard_pooler.rb +1 -1
- data/lib/vmfloaty/pooler.rb +33 -3
- data/lib/vmfloaty/service.rb +32 -17
- data/lib/vmfloaty/ssh.rb +11 -5
- data/lib/vmfloaty/utils.rb +127 -33
- data/lib/vmfloaty/version.rb +2 -1
- data/spec/spec_helper.rb +11 -0
- data/spec/vmfloaty/abs_spec.rb +83 -6
- data/spec/vmfloaty/pooler_spec.rb +20 -0
- data/spec/vmfloaty/ssh_spec.rb +49 -0
- data/spec/vmfloaty/utils_spec.rb +436 -73
- metadata +24 -13
data/lib/vmfloaty/service.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
91
|
-
|
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
|
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
|
data/lib/vmfloaty/ssh.rb
CHANGED
@@ -14,21 +14,27 @@ class Ssh
|
|
14
14
|
nil
|
15
15
|
end
|
16
16
|
|
17
|
-
def self.
|
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 =
|
25
|
-
raise "Could not get vm from
|
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 =
|
30
|
-
|
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)
|
data/lib/vmfloaty/utils.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
112
|
-
|
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
|
-
|
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
|
-
|
217
|
+
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
|
156
218
|
end
|
157
219
|
end
|
158
220
|
when 'ABS'
|
159
|
-
|
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
|
-
|
178
|
-
|
179
|
-
|
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
|
data/lib/vmfloaty/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -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
|
|
data/spec/vmfloaty/abs_spec.rb
CHANGED
@@ -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
|
115
|
+
# rubocop:disable Layout/LineLength
|
69
116
|
@active_requests_response = '
|
70
117
|
[
|
71
|
-
|
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
|
-
|
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
|
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
|