vanagon 0.16.1 → 0.17.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 +48 -23
- data/lib/vanagon/engine/always_be_scheduling.rb +271 -1
- data/lib/vanagon/engine/pooler.rb +7 -3
- data/lib/vanagon/utilities.rb +30 -8
- data/spec/lib/vanagon/engine/always_be_scheduling_spec.rb +113 -1
- data/spec/lib/vanagon/engine/ec2_spec.rb +2 -0
- data/spec/lib/vanagon/engine/pooler_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +27 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e09a1563ed504da68687d85b7c7a70e62028b7d1ba24568476d5cae338ae1ebf
|
4
|
+
data.tar.gz: 9da1804bfbf40c86ac845ccf60a76c133b217357117dcd22d43d97c35299aa1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19591339a372853aa653311214de761ead6dfd173218d68c0086691ede75da8d981079408afaf04e5fd362e2c9250c72ac9b1cb8cc3fdbeb16006a6510707176
|
7
|
+
data.tar.gz: 74e995f55e05778820809bbed4c2dcd501896a8d4894e1a38921bb8057cee049d62c42e136e8929c84c9609790738d77be356ed55b499974b3399c6a032d724c
|
data/README.md
CHANGED
@@ -45,9 +45,10 @@ Also, Vanagon ships with a number of engines which may include additional option
|
|
45
45
|
|
46
46
|
### Local Host:
|
47
47
|
|
48
|
-
- [Ruby](https://www.ruby-lang.org/en/) (Ruby 2.
|
48
|
+
- [Ruby](https://www.ruby-lang.org/en/) (Ruby 2.3.x is the miniumum supported version)
|
49
49
|
- [fustigit](https://github.com/mckern/fustigit)
|
50
50
|
- [ruby-git](https://github.com/schacon/ruby-git)
|
51
|
+
- [docopt](https://github.com/docopt/docopt.rb)
|
51
52
|
- The command line tool `ssh` ([homepage](https://www.openssh.com/)) available on the local `${PATH}` (any modern version should suffice)
|
52
53
|
- The command line tool `rsync` ([homepage](https://rsync.samba.org/)) available on the local `${PATH}` (At least rsync 2.6.x)
|
53
54
|
- The command line tool `git` ([homepage](https://git-scm.com/)) available on the local `${PATH}` (Vanagon is tested against Git version 1.8.x but should work with any newer version)
|
@@ -84,10 +85,28 @@ wheezy and build my project against it.
|
|
84
85
|
For more detailed examples of the DSLs available, please see the
|
85
86
|
[examples](examples) directory and the YARD documentation for Vanagon.
|
86
87
|
|
87
|
-
###
|
88
|
+
### CLI changes and deprecations (from version 0.16.0)
|
89
|
+
|
90
|
+
Prior to 0.16.0, the vanagon command line contained these commands
|
91
|
+
|
92
|
+
* `build`
|
93
|
+
* `build_host_info`
|
94
|
+
* `build_requirements`
|
95
|
+
* `inspect`
|
96
|
+
* `render`
|
97
|
+
* `repo`
|
98
|
+
* `ship`
|
99
|
+
* `sign`
|
100
|
+
|
101
|
+
With the exception of `repo`, which calls `packaging` methods, the remaining commands
|
102
|
+
have been moved to a git-like pattern of `vanagon <subcommand>`. `vangon build` replaced `build`, `vanagon ship` replaced `ship` and so forth.
|
103
|
+
|
104
|
+
The older calling usage is deprecated.
|
105
|
+
|
106
|
+
### `vanagon build` usage
|
88
107
|
The build command has positional arguments and position independent flags.
|
89
108
|
|
90
|
-
####
|
109
|
+
#### Positional arguments
|
91
110
|
|
92
111
|
##### project name
|
93
112
|
The name of the project to build; a file named `<project_name>.rb` must be
|
@@ -114,7 +133,8 @@ Build machines should be cleaned between builds.
|
|
114
133
|
|
115
134
|
#### Flagged arguments
|
116
135
|
|
117
|
-
**Note:** command flags can be used anywhere in the command.
|
136
|
+
**Note:** command flags currently can be used anywhere in the command. Recommended usages
|
137
|
+
is to use flagged arguments before the positional arguments.
|
118
138
|
|
119
139
|
##### -w DIR, --workdir DIR
|
120
140
|
Specifies a directory on the local host where the sources should be placed and builds performed.
|
@@ -134,9 +154,10 @@ Currently supported engines are:
|
|
134
154
|
* `base` - Pure ssh backend; no teardown currently defined
|
135
155
|
* `local` - Build on the local machine; platform name must match the local machine
|
136
156
|
* `docker` - Builds in a docker container
|
137
|
-
* `pooler` - Selects a vm from Puppet
|
157
|
+
* `pooler` - Selects a vm from Puppet's internal vmpooler to build on
|
138
158
|
* `hardware` - Build on a specific taget and lock it in redis
|
139
159
|
* `ec2` - Build on a specific AWS instance.
|
160
|
+
* `ABS` - Selects a vm from Puppet's internal Always-be-scheduling service to build on
|
140
161
|
|
141
162
|
#### Flags
|
142
163
|
|
@@ -147,9 +168,6 @@ Indicates that the host used for building the project should be left intact
|
|
147
168
|
after the build instead of destroyed. The host is usually destroyed after a
|
148
169
|
successful build, or left after a failed build.
|
149
170
|
|
150
|
-
##### -v, --verbose
|
151
|
-
(Reserved for future implementation) Will increase the verbosity of output, when implemented.
|
152
|
-
|
153
171
|
##### -h, --help
|
154
172
|
Display command-line help.
|
155
173
|
|
@@ -195,16 +213,16 @@ integer value these components to fail after the `VANAGON_TIMEOUT` count is reac
|
|
195
213
|
Note that this value is expected to be in seconds.
|
196
214
|
|
197
215
|
#### Example usage
|
198
|
-
`build --preserve puppet-agent el-6-i386` will build the puppet-agent project
|
216
|
+
`vanagon build --preserve puppet-agent el-6-i386` will build the puppet-agent project
|
199
217
|
on the el-6-i386 platform and leave the host intact afterward.
|
200
218
|
|
201
|
-
`build --engine=docker puppet-agent el-6-i386` will build the puppet-agent
|
219
|
+
`vanagon build --engine=docker puppet-agent el-6-i386` will build the puppet-agent
|
202
220
|
project on the el-6-i386 platform using the docker engine (the platform must
|
203
221
|
have a docker\_image defined in its config).
|
204
222
|
|
205
223
|
---
|
206
224
|
|
207
|
-
### `inspect` usage
|
225
|
+
### `vanagon inspect` usage
|
208
226
|
|
209
227
|
The `inspect` command has positional arguments and position independent flags. It
|
210
228
|
mirrors the `build` command, but exits with success after loading and interpolating
|
@@ -212,7 +230,7 @@ all of the components in the given project. No attempt is made to actually build
|
|
212
230
|
the given project; instead, a JSON formatted array of hashes is returned and printed
|
213
231
|
to `stdout`. This JSON array can be further processed by external tooling, such as `jq`.
|
214
232
|
|
215
|
-
####
|
233
|
+
#### Positional arguments
|
216
234
|
|
217
235
|
##### project name
|
218
236
|
The name of the project to build, and a file named \<project\_name\>.rb must be
|
@@ -227,7 +245,8 @@ Platform can also be a comma separated list of platforms such as platform1,platf
|
|
227
245
|
|
228
246
|
#### Flagged arguments
|
229
247
|
|
230
|
-
**Note:** command flags can be used anywhere in the command.
|
248
|
+
**Note:** command flags currently can be used anywhere in the command. Recommended usages
|
249
|
+
is to use flagged arguments before the positional arguments.
|
231
250
|
|
232
251
|
##### -w DIR, --workdir DIR
|
233
252
|
Specifies a directory where the sources should be placed and builds performed.
|
@@ -239,29 +258,24 @@ Specifies where project configuration is found. Defaults to $pwd/configs.
|
|
239
258
|
##### -e ENGINE, --engine ENGINE
|
240
259
|
Choose a different virtualization engine to use to select the build target.
|
241
260
|
Engines are respected, but only insofar as components and projects are
|
242
|
-
rendered -- the `inspect` command performs no compilation.
|
261
|
+
rendered -- the `vanagon inspect` command performs no compilation.
|
243
262
|
|
244
|
-
Supported engines are the same as the `build` command.
|
263
|
+
Supported engines are the same as the `vanagon build` command.
|
245
264
|
|
246
265
|
#### Flags
|
247
266
|
|
248
|
-
**Note:** command flags can be used anywhere in the command.
|
249
|
-
|
250
|
-
##### -v, --verbose (not yet implemented)
|
251
|
-
Increase verbosity of output.
|
252
|
-
|
253
267
|
##### -h, --help
|
254
268
|
Display command-line help.
|
255
269
|
|
256
270
|
#### Environment variables
|
257
271
|
|
258
272
|
Environment variables are respected, but only insofar as components and projects are
|
259
|
-
rendered -- the `inspect` command has no behavior to alter.
|
273
|
+
rendered -- the `vanagon inspect` command has no behavior to alter.
|
260
274
|
|
261
|
-
Supported environment variables are the same as the `build` command.
|
275
|
+
Supported environment variables are the same as the `vanagon build` command.
|
262
276
|
|
263
277
|
#### Example usage
|
264
|
-
`inspect puppet-agent el-6-i386` will load the puppet-agent project
|
278
|
+
`vanagon inspect puppet-agent el-6-i386` will load the puppet-agent project
|
265
279
|
on the el-6-i386 platform and print the resulting list of dependencies,
|
266
280
|
build-time configuration, environment variables, and expected artifacts.
|
267
281
|
|
@@ -297,6 +311,16 @@ platform "el-7-x86_64" do |plat|
|
|
297
311
|
end
|
298
312
|
```
|
299
313
|
|
314
|
+
### ABS (internal)
|
315
|
+
When using the ABS engine, there is a variety of ways you can specify your token:
|
316
|
+
- the environment variable ABS_TOKEN
|
317
|
+
- or vanagon token file ~/.vanagon-token (note this is the same file read by the pooler engine)
|
318
|
+
- or [vmfloaty](https://github.com/puppetlabs/vmfloaty)'s config file ~/.vmfloaty.yml
|
319
|
+
|
320
|
+
In order to modify or track the VM via floaty or bit-bar you can optionally add the vmpooler token (different from the ABS token) via
|
321
|
+
- VMPOOLER_TOKEN
|
322
|
+
- or as a second line to the file ~/.vanagon-token
|
323
|
+
- or by using the existing mechanism in floaty using a vmpooler_fallback
|
300
324
|
|
301
325
|
Contributing
|
302
326
|
---
|
@@ -310,3 +334,4 @@ See [LICENSE](LICENSE) file.
|
|
310
334
|
|
311
335
|
## Maintainers
|
312
336
|
See [MAINTAINERS](MAINTAINERS) file.
|
337
|
+
|
@@ -1,5 +1,6 @@
|
|
1
|
-
require 'vanagon/engine/base'
|
2
1
|
require 'json'
|
2
|
+
require 'vanagon/engine/base'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
class Vanagon
|
5
6
|
class Engine
|
@@ -82,9 +83,15 @@ class Vanagon
|
|
82
83
|
# {"name":"aix-53-ppc","engine":"always_be_scheduling"}
|
83
84
|
# ```
|
84
85
|
class AlwaysBeScheduling < Base
|
86
|
+
attr_reader :token
|
87
|
+
attr_reader :token_vmpooler
|
88
|
+
|
85
89
|
def initialize(platform, target, **opts)
|
86
90
|
super
|
87
91
|
|
92
|
+
@available_abs_endpoint = "https://abs-prod.k8s.infracore.puppet.net/api/v2"
|
93
|
+
@token_vmpooler = ENV['VMPOOLER_TOKEN']
|
94
|
+
@token = load_token
|
88
95
|
Vanagon::Driver.logger.debug "AlwaysBeScheduling engine invoked."
|
89
96
|
end
|
90
97
|
|
@@ -94,6 +101,7 @@ class Vanagon
|
|
94
101
|
end
|
95
102
|
|
96
103
|
# return the platform name as the "host" name
|
104
|
+
# order of preference: abs_resource_name, vmpooler_template or name
|
97
105
|
def build_host_name
|
98
106
|
if @platform.abs_resource_name
|
99
107
|
@platform.abs_resource_name
|
@@ -103,6 +111,268 @@ class Vanagon
|
|
103
111
|
@platform.name
|
104
112
|
end
|
105
113
|
end
|
114
|
+
|
115
|
+
# Retrieve the ABS token from an environment variable
|
116
|
+
# ("ABS_TOKEN") or from a number of potential configuration
|
117
|
+
# files (~/.vanagon-token or ~/.vmfloaty.yml).
|
118
|
+
# @return [String, nil] token for use with the vmpooler
|
119
|
+
def load_token
|
120
|
+
ENV['ABS_TOKEN'] || token_from_file
|
121
|
+
end
|
122
|
+
|
123
|
+
# a wrapper method around retrieving a token,
|
124
|
+
# with an explicitly ordered preference for a Vanagon-specific
|
125
|
+
# token file or a preexisting vmfoaty yaml file.
|
126
|
+
#
|
127
|
+
# @return [String, nil] token for use with the vmpooler
|
128
|
+
def token_from_file
|
129
|
+
read_vanagon_token || read_vmfloaty_token
|
130
|
+
end
|
131
|
+
private :token_from_file
|
132
|
+
|
133
|
+
# Read an ABS/vmpooler token from the plaintext vanagon-token file,
|
134
|
+
# as outlined in the project README.
|
135
|
+
# The first line should be the ABS token
|
136
|
+
# and the second (optional) line should be the vmpooler token
|
137
|
+
# Saves the second line into the @token_vmpooler variable
|
138
|
+
#
|
139
|
+
# @return [String, nil] the vanagon vmpooler token value
|
140
|
+
def read_vanagon_token(path = "~/.vanagon-token")
|
141
|
+
absolute_path = File.expand_path(path)
|
142
|
+
return nil unless File.exist?(absolute_path)
|
143
|
+
|
144
|
+
warn "Reading ABS token from: #{path}"
|
145
|
+
contents = File.read(absolute_path).chomp
|
146
|
+
lines = contents.each_line.map(&:chomp)
|
147
|
+
|
148
|
+
abs = lines.shift
|
149
|
+
@token_vmpooler = lines.shift
|
150
|
+
|
151
|
+
warn "Please add a second line with the vmpooler token to be able to modify or see the VM in floaty/bit-bar" if @token_vmpooler.nil?
|
152
|
+
return abs
|
153
|
+
end
|
154
|
+
private :read_vanagon_token
|
155
|
+
|
156
|
+
# Read a vmpooler token from the yaml formatted vmfloaty config,
|
157
|
+
# as outlined by the vmfloaty project:
|
158
|
+
# https://github.com/puppetlabs/vmfloaty
|
159
|
+
#
|
160
|
+
# It returns the top-level token value or the first 'abs' service
|
161
|
+
# token value it finds in the services list
|
162
|
+
# it sets @token_vmpooler with the optional vmpooler token
|
163
|
+
# if the abs services has a vmpooler_fallback, and that service
|
164
|
+
# has a token eg
|
165
|
+
#
|
166
|
+
# TOP-LEVEL DEFINED => would get only the abs token
|
167
|
+
# user: 'jdoe'
|
168
|
+
# url: 'https://abs.example.net'
|
169
|
+
# token: '456def789'
|
170
|
+
#
|
171
|
+
# MULTIPLE SERVICES DEFINED => would get the abs token in 'abs-prod' and the vmpooler token in 'vmpooler-prod'
|
172
|
+
# user: 'jdoe'
|
173
|
+
# services:
|
174
|
+
# abs-prod:
|
175
|
+
# type: 'abs'
|
176
|
+
# url: 'https://abs.example.net/api/v2'
|
177
|
+
# token: '123abc456'
|
178
|
+
# vmpooler_fallback: 'vmpooler-prod'
|
179
|
+
# vmpooler-dev:
|
180
|
+
# type: 'vmpooler'
|
181
|
+
# url: 'https://vmpooler-dev.example.net'
|
182
|
+
# token: '987dsa654'
|
183
|
+
# vmpooler-prod:
|
184
|
+
# type: 'vmpooler'
|
185
|
+
# url: 'https://vmpooler.example.net'
|
186
|
+
# token: '456def789'
|
187
|
+
#
|
188
|
+
# @return [String, nil] the vmfloaty vmpooler token value
|
189
|
+
def read_vmfloaty_token(path = "~/.vmfloaty.yml") # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
190
|
+
absolute_path = File.expand_path(path)
|
191
|
+
return nil unless File.exist?(absolute_path)
|
192
|
+
|
193
|
+
yaml_config = YAML.load_file(absolute_path)
|
194
|
+
abs_token = nil
|
195
|
+
abs_service_name = nil
|
196
|
+
if yaml_config['token'] # top level
|
197
|
+
abs_token = yaml_config['token']
|
198
|
+
elsif yaml_config['services']
|
199
|
+
yaml_config['services'].each do |name, value|
|
200
|
+
if value['type'] == "abs" && value['token']
|
201
|
+
abs_token = value['token']
|
202
|
+
abs_service_name = name
|
203
|
+
vmpooler_fallback = value['vmpooler_fallback']
|
204
|
+
unless vmpooler_fallback.nil? || yaml_config['services'][vmpooler_fallback].nil? || yaml_config['services'][vmpooler_fallback]['token'].nil?
|
205
|
+
@token_vmpooler = yaml_config['services'][vmpooler_fallback]['token']
|
206
|
+
end
|
207
|
+
break
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
message = "Reading ABS token from: #{path}"
|
212
|
+
if abs_service_name
|
213
|
+
message.concat(" for service named #{abs_service_name}")
|
214
|
+
if @token_vmpooler.nil?
|
215
|
+
message.concat(" but there was no vmpooler_fallback value, please add one if you want to be able to modify the VM via bit-bar/floaty")
|
216
|
+
else
|
217
|
+
message.concat(" with a vmpooler_fallback token")
|
218
|
+
end
|
219
|
+
end
|
220
|
+
warn message
|
221
|
+
return abs_token
|
222
|
+
end
|
223
|
+
private :read_vmfloaty_token
|
224
|
+
|
225
|
+
# This method is used to obtain a vm to build upon using Puppet's internal
|
226
|
+
# ABS (https://github.com/puppetlabs/always-be-scheduling) which is a level of abstraction for other
|
227
|
+
# engines using similar APIs
|
228
|
+
# @raise [Vanagon::Error] if a target cannot be obtained
|
229
|
+
def select_target
|
230
|
+
@pooler = select_target_from(@available_abs_endpoint)
|
231
|
+
raise Vanagon::Error, "Something went wrong getting a target vm to build on" if @pooler.empty?
|
232
|
+
end
|
233
|
+
|
234
|
+
# Attempt to provision a host from a specific pooler.
|
235
|
+
def select_target_from(pooler) # rubocop:disable Metrics/AbcSize
|
236
|
+
request_object = build_request_object
|
237
|
+
|
238
|
+
warn "Requesting VMs with job_id: #{@saved_job_id}. Will poll for up to an hour."
|
239
|
+
#the initial request is always replied with "come back again"
|
240
|
+
response = Vanagon::Utilities.http_request_generic(
|
241
|
+
"#{pooler}/request",
|
242
|
+
'POST',
|
243
|
+
request_object.to_json,
|
244
|
+
{ 'X-AUTH-TOKEN' => @token }
|
245
|
+
)
|
246
|
+
|
247
|
+
unless response.code == "202"
|
248
|
+
warn "failed to request ABS with code #{response.code}"
|
249
|
+
if valid_json?(response.body)
|
250
|
+
response_json = JSON.parse(response.body)
|
251
|
+
warn "reason: #{response_json['reason']}"
|
252
|
+
end
|
253
|
+
return ''
|
254
|
+
end
|
255
|
+
response_body = check_queue(pooler, request_object)
|
256
|
+
|
257
|
+
return '' unless response_body["ok"]
|
258
|
+
@target = response_body[build_host_name]['hostname']
|
259
|
+
Vanagon::Driver.logger.info "Reserving #{@target} (#{build_host_name}) [#{@token ? 'token used' : 'no token used'}]"
|
260
|
+
return pooler
|
261
|
+
end
|
262
|
+
|
263
|
+
# main loop where the status of the request is checked, to see if the request
|
264
|
+
# has been allocated
|
265
|
+
def check_queue(pooler, request_object)
|
266
|
+
retries = 360 # ~ one hour
|
267
|
+
response_body = nil
|
268
|
+
begin
|
269
|
+
(1..retries).each do |i|
|
270
|
+
response = Vanagon::Utilities.http_request_generic(
|
271
|
+
"#{pooler}/request",
|
272
|
+
'POST',
|
273
|
+
request_object.to_json,
|
274
|
+
{ 'X-AUTH-TOKEN' => @token }
|
275
|
+
)
|
276
|
+
response_body = validate_queue_status_response(response.code, response.body)
|
277
|
+
break if response_body
|
278
|
+
|
279
|
+
sleep_seconds = 10 if i >= 10
|
280
|
+
sleep_seconds = i if i < 10
|
281
|
+
warn "Waiting #{sleep_seconds} seconds to check if ABS request has been filled. (x#{i})"
|
282
|
+
|
283
|
+
sleep(sleep_seconds)
|
284
|
+
end
|
285
|
+
rescue SystemExit, Interrupt
|
286
|
+
warn "\nVanagon interrupted during mains ABS polling. Make sure you delete the requested job_id #{@saved_job_id}"
|
287
|
+
raise
|
288
|
+
end
|
289
|
+
response_body = translated(response_body, @saved_job_id)
|
290
|
+
response_body
|
291
|
+
end
|
292
|
+
|
293
|
+
def validate_queue_status_response(status_code, body)
|
294
|
+
case status_code
|
295
|
+
when "200"
|
296
|
+
return JSON.parse(body) unless body.empty? || !valid_json?(body)
|
297
|
+
when "202"
|
298
|
+
return nil
|
299
|
+
when "401"
|
300
|
+
raise Vanagon::Error, "HTTP #{status_code}: The token provided could not authenticate.\n#{body}"
|
301
|
+
when "503"
|
302
|
+
return nil
|
303
|
+
else
|
304
|
+
raise Vanagon::Error, "HTTP #{status_code}: request to ABS failed!\n#{body}"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# This method is used to tell the ABS to delete the job_id requested
|
309
|
+
# otherwise the resources will eventually get allocated asynchronously
|
310
|
+
# and will keep running until the end of their lifetime.
|
311
|
+
def teardown # rubocop:disable Metrics/AbcSize
|
312
|
+
request_object = {
|
313
|
+
'job_id' => @saved_job_id,
|
314
|
+
}
|
315
|
+
|
316
|
+
response = Vanagon::Utilities.http_request_generic(
|
317
|
+
"#{@available_abs_endpoint}/return",
|
318
|
+
"POST",
|
319
|
+
request_object.to_json,
|
320
|
+
{ 'X-AUTH-TOKEN' => @token }
|
321
|
+
)
|
322
|
+
if response && response.body == 'OK'
|
323
|
+
Vanagon::Driver.logger.info "#{@saved_job_id} has been scheduled for removal"
|
324
|
+
warn "#{@saved_job_id} has been scheduled for removal"
|
325
|
+
else
|
326
|
+
Vanagon::Driver.logger.info "#{@saved_job_id} could not be scheduled for removal: #{response.body}"
|
327
|
+
warn "#{@saved_job_id} could not be scheduled for removal"
|
328
|
+
end
|
329
|
+
rescue Vanagon::Error => e
|
330
|
+
Vanagon::Driver.logger.info "#{@saved_job_id} could not be scheduled for removal (#{e.message})"
|
331
|
+
warn "#{@saved_job_id} could not be scheduled for removal (#{e.message})"
|
332
|
+
end
|
333
|
+
|
334
|
+
private
|
335
|
+
|
336
|
+
def translated(response_body, job_id)
|
337
|
+
vmpooler_formatted_body = { 'job_id' => job_id }
|
338
|
+
|
339
|
+
response_body.each do |host| # in this context there should be only one host
|
340
|
+
vmpooler_formatted_body[host['type']] = { 'hostname' => host['hostname'] }
|
341
|
+
end
|
342
|
+
vmpooler_formatted_body['ok'] = true
|
343
|
+
|
344
|
+
vmpooler_formatted_body
|
345
|
+
end
|
346
|
+
|
347
|
+
def build_request_object
|
348
|
+
user = ENV['USER'] || ENV['USERNAME'] || 'unknown'
|
349
|
+
|
350
|
+
@saved_job_id = user + "-" + DateTime.now.strftime('%Q')
|
351
|
+
request_object = {
|
352
|
+
:resources => { build_host_name => 1 },
|
353
|
+
:job => {
|
354
|
+
:id => @saved_job_id,
|
355
|
+
:tags => {
|
356
|
+
:jenkins_build_url => ENV['BUILD_URL'],
|
357
|
+
:project => ENV['JOB_NAME'] || 'vanagon',
|
358
|
+
:created_by => user,
|
359
|
+
:user => user
|
360
|
+
},
|
361
|
+
},
|
362
|
+
:priority => 1, # DO NOT use priority 1 in automated CI runs
|
363
|
+
}
|
364
|
+
unless @token_vmpooler.nil?
|
365
|
+
request_object[:vm_token] = @token_vmpooler
|
366
|
+
end
|
367
|
+
request_object
|
368
|
+
end
|
369
|
+
|
370
|
+
def valid_json?(json)
|
371
|
+
JSON.parse(json)
|
372
|
+
return true
|
373
|
+
rescue TypeError, JSON::ParserError
|
374
|
+
return false
|
375
|
+
end
|
106
376
|
end
|
107
377
|
end
|
108
378
|
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'vanagon/engine/base'
|
2
2
|
require 'yaml'
|
3
3
|
|
4
|
+
### Note this class is deprecated in favor of using the ABS Engine. The pooler has changed it's API with regards to
|
5
|
+
# getting VMs for ondemand provisioning and would need to be updated here.
|
6
|
+
# See DIO-1066
|
7
|
+
|
4
8
|
class Vanagon
|
5
9
|
class Engine
|
6
10
|
class Pooler < Base
|
@@ -10,7 +14,7 @@ class Vanagon
|
|
10
14
|
def initialize(platform, target = nil, **opts)
|
11
15
|
super
|
12
16
|
|
13
|
-
@available_poolers = ["
|
17
|
+
@available_poolers = ["https://vmpooler.delivery.puppetlabs.net", "https://nspooler-service-prod-1.delivery.puppetlabs.net"]
|
14
18
|
@token = load_token
|
15
19
|
@required_attributes << "vmpooler_template"
|
16
20
|
end
|
@@ -63,7 +67,7 @@ class Vanagon
|
|
63
67
|
|
64
68
|
# Read a vmpooler token from the yaml formatted vmfloaty config,
|
65
69
|
# as outlined by the vmfloaty project:
|
66
|
-
# https://github.com/
|
70
|
+
# https://github.com/puppetlabs/vmfloaty
|
67
71
|
#
|
68
72
|
# @return [String, nil] the vmfloaty vmpooler token value
|
69
73
|
def read_vmfloaty_token(path = "~/.vmfloaty.yml")
|
@@ -75,7 +79,7 @@ class Vanagon
|
|
75
79
|
end
|
76
80
|
private :read_vmfloaty_token
|
77
81
|
|
78
|
-
# This method is used to obtain a vm to build upon using
|
82
|
+
# This method is used to obtain a vm to build upon using Puppet's internal
|
79
83
|
# vmpooler (https://github.com/puppetlabs/vmpooler) or other pooler technologies
|
80
84
|
# leveraging the same API
|
81
85
|
# @raise [Vanagon::Error] if a target cannot be obtained
|
data/lib/vanagon/utilities.rb
CHANGED
@@ -39,17 +39,16 @@ class Vanagon
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# Simple wrapper around Net::HTTP. Will make a request of the given type to
|
42
|
-
# the given url and return the
|
42
|
+
# the given url and return the response object
|
43
43
|
#
|
44
44
|
# @param url [String] The url to make the request against (needs to be parsable by URI
|
45
45
|
# @param type [String] One of the supported request types (currently 'get', 'post', 'delete')
|
46
46
|
# @param payload [String] The request body data payload used for POST and PUT
|
47
47
|
# @param header [Hash] Send additional information in the HTTP request header
|
48
|
-
# @return [
|
48
|
+
# @return [Net::HTTPAccepted] The response object
|
49
49
|
# @raise [RuntimeError, Vanagon::Error] an exception is raised if the
|
50
|
-
# action is not supported, or if there is a problem with the http request
|
51
|
-
|
52
|
-
def http_request(url, type, payload = {}.to_json, header = nil) # rubocop:disable Metrics/AbcSize
|
50
|
+
# action is not supported, or if there is a problem with the http request
|
51
|
+
def http_request_generic(url, type, payload = {}.to_json, header = nil) # rubocop:disable Metrics/AbcSize
|
53
52
|
uri = URI.parse(url)
|
54
53
|
http = Net::HTTP.new(uri.host, uri.port)
|
55
54
|
http.use_ssl = true if uri.scheme == 'https'
|
@@ -77,14 +76,37 @@ class Vanagon
|
|
77
76
|
end
|
78
77
|
|
79
78
|
response = http.request(request)
|
80
|
-
|
81
|
-
JSON.parse(response.body)
|
79
|
+
response
|
82
80
|
rescue Errno::ETIMEDOUT, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
83
81
|
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
84
82
|
Net::ProtocolError => e
|
85
83
|
raise Vanagon::Error.wrap(e, "Problem reaching #{url}. Is #{uri.host} down?")
|
84
|
+
end
|
85
|
+
|
86
|
+
# uses http_request_generic and returns the body as parsed by JSON.
|
87
|
+
# @param url [String] The url to make the request against (needs to be parsable by URI
|
88
|
+
# @param type [String] One of the supported request types (currently 'get', 'post', 'delete')
|
89
|
+
# @param payload [String] The request body data payload used for POST and PUT
|
90
|
+
# @param header [Hash] Send additional information in the HTTP request header
|
91
|
+
# @return [Hash] The response in JSON format
|
92
|
+
# @raise [RuntimeError, Vanagon::Error] an exception is raised if the response
|
93
|
+
# body cannot be parsed as JSON
|
94
|
+
def http_request(url, type, payload = {}.to_json, header = nil)
|
95
|
+
response = http_request_generic(url, type, payload, header)
|
96
|
+
JSON.parse(response.body)
|
86
97
|
rescue JSON::ParserError => e
|
87
|
-
raise Vanagon::Error.wrap(e, "#{
|
98
|
+
raise Vanagon::Error.wrap(e, "#{url} handed us a response that doesn't look like JSON.")
|
99
|
+
end
|
100
|
+
|
101
|
+
# uses http_request_generic and returns the response code.
|
102
|
+
# @param url [String] The url to make the request against (needs to be parsable by URI
|
103
|
+
# @param type [String] One of the supported request types (currently 'get', 'post', 'delete')
|
104
|
+
# @param payload [String] The request body data payload used for POST and PUT
|
105
|
+
# @param header [Hash] Send additional information in the HTTP request header
|
106
|
+
# @return [String] The response code eg 202, 200 etc
|
107
|
+
def http_request_code(url, type, payload = {}.to_json, header = nil)
|
108
|
+
response = http_request_generic(url, type, payload, header)
|
109
|
+
response.code
|
88
110
|
end
|
89
111
|
|
90
112
|
# Similar to rake's sh, the passed command will be executed and an
|
@@ -2,6 +2,7 @@ require 'vanagon/engine/always_be_scheduling'
|
|
2
2
|
require 'vanagon/driver'
|
3
3
|
require 'vanagon/platform'
|
4
4
|
require 'logger'
|
5
|
+
require 'spec_helper'
|
5
6
|
|
6
7
|
class Vanagon
|
7
8
|
class Driver
|
@@ -45,6 +46,8 @@ describe 'Vanagon::Engine::AlwaysBeScheduling' do
|
|
45
46
|
end")
|
46
47
|
plat._platform
|
47
48
|
}
|
49
|
+
let(:pooler_token_file) { File.expand_path('~/.vanagon-token') }
|
50
|
+
let(:floaty_config) { File.expand_path('~/.vmfloaty.yml') }
|
48
51
|
|
49
52
|
describe '#validate_platform' do
|
50
53
|
it 'returns true if the platform has the required attributes' do
|
@@ -81,4 +84,113 @@ describe 'Vanagon::Engine::AlwaysBeScheduling' do
|
|
81
84
|
.to eq('always_be_scheduling')
|
82
85
|
end
|
83
86
|
end
|
84
|
-
|
87
|
+
|
88
|
+
describe '#read_vanagon_token' do
|
89
|
+
it 'takes the first line for abs token, second line is optional' do
|
90
|
+
token_value = 'decade'
|
91
|
+
allow(File).to receive(:exist?)
|
92
|
+
.with(pooler_token_file)
|
93
|
+
.and_return(true)
|
94
|
+
|
95
|
+
allow(File).to receive(:read)
|
96
|
+
.with(pooler_token_file)
|
97
|
+
.and_return(token_value)
|
98
|
+
|
99
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
100
|
+
expect(abs_service.token).to eq('decade')
|
101
|
+
expect(abs_service.token_vmpooler).to eq(nil)
|
102
|
+
end
|
103
|
+
it 'takes the second line as vmpooler token' do
|
104
|
+
token_value = "decade\nanddaycade"
|
105
|
+
allow(File).to receive(:exist?)
|
106
|
+
.with(pooler_token_file)
|
107
|
+
.and_return(true)
|
108
|
+
|
109
|
+
allow(File).to receive(:read)
|
110
|
+
.with(pooler_token_file)
|
111
|
+
.and_return(token_value)
|
112
|
+
|
113
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
114
|
+
expect(abs_service.token).to eq('decade')
|
115
|
+
expect(abs_service.token_vmpooler).to eq('anddaycade')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#read_vmfloaty_token' do
|
120
|
+
before :each do
|
121
|
+
allow(File).to receive(:exist?)
|
122
|
+
.with(pooler_token_file)
|
123
|
+
.and_return(false)
|
124
|
+
|
125
|
+
allow(File).to receive(:exist?)
|
126
|
+
.with(floaty_config)
|
127
|
+
.and_return(true)
|
128
|
+
end
|
129
|
+
token_value = 'decade'
|
130
|
+
it %(reads a token from '~/.vmfloaty.yml at the top level') do
|
131
|
+
allow(YAML).to receive(:load_file)
|
132
|
+
.with(floaty_config)
|
133
|
+
.and_return({'token' => token_value})
|
134
|
+
|
135
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
136
|
+
expect(abs_service.token).to eq(token_value)
|
137
|
+
expect(abs_service.token_vmpooler).to eq(nil)
|
138
|
+
end
|
139
|
+
it %(reads a token from '~/.vmfloaty.yml in the abs service') do
|
140
|
+
allow(YAML).to receive(:load_file)
|
141
|
+
.with(floaty_config)
|
142
|
+
.and_return({'services' =>
|
143
|
+
{'MYabs' => {'type'=>'abs', 'token'=>token_value, 'url'=>'foo'}}
|
144
|
+
})
|
145
|
+
|
146
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
147
|
+
expect(abs_service.token).to eq(token_value)
|
148
|
+
expect(abs_service.token_vmpooler).to eq(nil)
|
149
|
+
end
|
150
|
+
it %(reads a token from '~/.vmfloaty.yml in the abs service and includes the vmpooler token') do
|
151
|
+
vmp_token_value = 'deecade'
|
152
|
+
allow(YAML).to receive(:load_file)
|
153
|
+
.with(floaty_config)
|
154
|
+
.and_return({'services' =>
|
155
|
+
{'MYabs' => {'type'=>'abs', 'token'=>token_value, 'url'=>'foo', 'vmpooler_fallback' => 'myvmp'},
|
156
|
+
'myvmp' => {'token'=>vmp_token_value, 'url'=>'bar'}}
|
157
|
+
})
|
158
|
+
|
159
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
160
|
+
expect(abs_service.token).to eq(token_value)
|
161
|
+
expect(abs_service.token_vmpooler).to eq(vmp_token_value)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
describe '#select_target_from' do
|
165
|
+
it 'runs successfully' do
|
166
|
+
hostname = 'faint-whirlwind.puppet.com'
|
167
|
+
stub_request(:post, "https://foobar/request").
|
168
|
+
to_return({status: 202, body: "", headers: {}},{status: 200, body: '[{"hostname":"'+hostname+'","type":"aix-6.1-ppc","engine":"nspooler"}]', headers: {}})
|
169
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
170
|
+
abs_service.select_target_from("https://foobar")
|
171
|
+
expect(abs_service.target).to eq(hostname)
|
172
|
+
end
|
173
|
+
it 'returns a warning if the first request is not a 202' do
|
174
|
+
hostname = 'fainter-whirlwind.puppet.com'
|
175
|
+
stub_request(:post, "https://foobar/request").
|
176
|
+
to_return({status: 404, body: "", headers: {}},{status: 200, body: '[{"hostname":"'+hostname+'","type":"aix-6.1-ppc","engine":"nspooler"}]', headers: {}})
|
177
|
+
allow_any_instance_of(Object).to receive(:warn)
|
178
|
+
expect_any_instance_of(Object).to receive(:warn).with("failed to request ABS with code 404")
|
179
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
180
|
+
pooler = abs_service.select_target_from("https://foobar")
|
181
|
+
expect(pooler).to eq('')
|
182
|
+
end
|
183
|
+
it 'returns a warning and retries until request is a 200' do
|
184
|
+
hostname = 'faintest-whirlwind.puppet.com'
|
185
|
+
stub_request(:post, "https://foobar/request").
|
186
|
+
to_return({status: 202, body: "", headers: {}},
|
187
|
+
{status: 503, body: "", headers: {}},
|
188
|
+
{status: 200, body: '[{"hostname":"'+hostname+'","type":"aix-6.1-ppc","engine":"nspooler"}]', headers: {}})
|
189
|
+
allow_any_instance_of(Object).to receive(:warn)
|
190
|
+
expect_any_instance_of(Object).to receive(:warn).with(/Waiting 1 seconds to check if ABS request has been filled/)
|
191
|
+
abs_service = Vanagon::Engine::AlwaysBeScheduling.new(platform, nil)
|
192
|
+
abs_service.select_target_from("https://foobar")
|
193
|
+
expect(abs_service.target).to eq(hostname)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -27,6 +27,8 @@ if defined? ::Aws
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'returns "ec2" name' do
|
30
|
+
stub_request(:get, "http://169.254.169.254/latest/meta-data/iam/security-credentials/").
|
31
|
+
to_return(status: 200, body: "", headers: {})
|
30
32
|
expect(Vanagon::Engine::Ec2.new(platform_ec2).name).to eq('ec2')
|
31
33
|
end
|
32
34
|
end
|
@@ -6,7 +6,7 @@ describe 'Vanagon::Engine::Pooler' do
|
|
6
6
|
let (:platform_with_vcloud_name) {
|
7
7
|
plat = Vanagon::Platform::DSL.new('debian-6-i386')
|
8
8
|
plat.instance_eval("platform 'debian-6-i386' do |plat|
|
9
|
-
plat.
|
9
|
+
plat.vmpooler_template 'debian-6-i386'
|
10
10
|
end")
|
11
11
|
plat._platform
|
12
12
|
}
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vanagon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet Labs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: docopt
|
@@ -288,41 +288,41 @@ signing_key:
|
|
288
288
|
specification_version: 3
|
289
289
|
summary: All of your packages will fit into this van with this one simple trick.
|
290
290
|
test_files:
|
291
|
+
- spec/lib/vanagon/project/dsl_spec.rb
|
292
|
+
- spec/lib/vanagon/extensions/string_spec.rb
|
293
|
+
- spec/lib/vanagon/extensions/ostruct/json_spec.rb
|
294
|
+
- spec/lib/vanagon/extensions/set/json_spec.rb
|
295
|
+
- spec/lib/vanagon/platform/solaris_11_spec.rb
|
296
|
+
- spec/lib/vanagon/platform/dsl_spec.rb
|
291
297
|
- spec/lib/vanagon/platform/rpm/aix_spec.rb
|
292
|
-
- spec/lib/vanagon/platform/osx_spec.rb
|
293
298
|
- spec/lib/vanagon/platform/windows_spec.rb
|
299
|
+
- spec/lib/vanagon/platform/osx_spec.rb
|
300
|
+
- spec/lib/vanagon/platform/solaris_10_spec.rb
|
294
301
|
- spec/lib/vanagon/platform/rpm_spec.rb
|
295
302
|
- spec/lib/vanagon/platform/deb_spec.rb
|
296
|
-
- spec/lib/vanagon/
|
297
|
-
- spec/lib/vanagon/
|
298
|
-
- spec/lib/vanagon/platform/dsl_spec.rb
|
299
|
-
- spec/lib/vanagon/driver_spec.rb
|
300
|
-
- spec/lib/vanagon/project/dsl_spec.rb
|
301
|
-
- spec/lib/vanagon/utilities_spec.rb
|
302
|
-
- spec/lib/vanagon/cli_spec.rb
|
303
|
-
- spec/lib/vanagon/environment_spec.rb
|
304
|
-
- spec/lib/vanagon/component/rules_spec.rb
|
305
|
-
- spec/lib/vanagon/component/source_spec.rb
|
306
|
-
- spec/lib/vanagon/component/source/local_spec.rb
|
303
|
+
- spec/lib/vanagon/project_spec.rb
|
304
|
+
- spec/lib/vanagon/component/source/rewrite_spec.rb
|
307
305
|
- spec/lib/vanagon/component/source/git_spec.rb
|
306
|
+
- spec/lib/vanagon/component/source/local_spec.rb
|
308
307
|
- spec/lib/vanagon/component/source/http_spec.rb
|
309
|
-
- spec/lib/vanagon/component/
|
308
|
+
- spec/lib/vanagon/component/rules_spec.rb
|
310
309
|
- spec/lib/vanagon/component/dsl_spec.rb
|
311
|
-
- spec/lib/vanagon/
|
312
|
-
- spec/lib/vanagon/
|
313
|
-
- spec/lib/vanagon/
|
314
|
-
- spec/lib/vanagon/extensions/ostruct/json_spec.rb
|
310
|
+
- spec/lib/vanagon/component/source_spec.rb
|
311
|
+
- spec/lib/vanagon/common/user_spec.rb
|
312
|
+
- spec/lib/vanagon/common/pathname_spec.rb
|
315
313
|
- spec/lib/vanagon/component_spec.rb
|
316
|
-
- spec/lib/vanagon/platform_spec.rb
|
317
|
-
- spec/lib/vanagon/engine/local_spec.rb
|
318
314
|
- spec/lib/vanagon/engine/hardware_spec.rb
|
319
|
-
- spec/lib/vanagon/engine/always_be_scheduling_spec.rb
|
320
|
-
- spec/lib/vanagon/engine/pooler_spec.rb
|
321
|
-
- spec/lib/vanagon/engine/base_spec.rb
|
322
315
|
- spec/lib/vanagon/engine/ec2_spec.rb
|
316
|
+
- spec/lib/vanagon/engine/local_spec.rb
|
323
317
|
- spec/lib/vanagon/engine/docker_spec.rb
|
324
|
-
- spec/lib/vanagon/
|
325
|
-
- spec/lib/vanagon/
|
326
|
-
- spec/lib/vanagon/
|
318
|
+
- spec/lib/vanagon/engine/pooler_spec.rb
|
319
|
+
- spec/lib/vanagon/engine/base_spec.rb
|
320
|
+
- spec/lib/vanagon/engine/always_be_scheduling_spec.rb
|
321
|
+
- spec/lib/vanagon/environment_spec.rb
|
322
|
+
- spec/lib/vanagon/cli_spec.rb
|
323
|
+
- spec/lib/vanagon/driver_spec.rb
|
324
|
+
- spec/lib/vanagon/utilities_spec.rb
|
325
|
+
- spec/lib/vanagon/platform_spec.rb
|
326
|
+
- spec/lib/vanagon/utilities/shell_utilities_spec.rb
|
327
327
|
- spec/lib/makefile_spec.rb
|
328
328
|
- spec/lib/git/rev_list_spec.rb
|