nomadsl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4f3c9be8c5c4c5293c3faa964df8b2cc49b06f16
4
+ data.tar.gz: aa028437bee6a60e1e04e35cd1f02fdd2fe0aea3
5
+ SHA512:
6
+ metadata.gz: 2d984c2ebd0ceafd1ebc361c68a6d9d0c582f4707bb63f31f7586571728bfd53ec38db2935dee923ed3b9893c7b488da00ffc9552ab222d5c9fd47dbb09fa6ee
7
+ data.tar.gz: '094f041d9f2b4502920e35e09a3d3d3459bbfc157d1f71d4b422e750d0a0270bd23b0bd8952e32ad6f026e53afd11be7c73702ca80bf5514c058a0af15c3bb0d'
data/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ This work is dedicated to the public domain. No rights reserved.
2
+
3
+ I, the copyright holder of this work, hereby release it into the public
4
+ domain. This applies worldwide.
5
+
6
+ I grant any entity the right to use this work for any purpose, without
7
+ any conditions, unless such conditions are required by law.
8
+
9
+ If you require a fuller legal statement, please refer to the Creative
10
+ Commons Zero license:
11
+
12
+ http://creativecommons.org/publicdomain/zero/1.0/
data/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # nomadsl
2
+
3
+ Nomadsl is a Ruby DSL for generating Nomad job specification files.
4
+
5
+ Methods mapping to keys and attributes described in the Nomad Job Specification
6
+ (https://www.nomadproject.io/docs/job-specification/index.html) are defined in
7
+ an includable module.
8
+
9
+ The mapping of key and attribute names to method names is generally one-to-one.
10
+
11
+ ## Example: DSL direct to stdout
12
+
13
+ Simply `require 'nomadsl/dsl` and the DSL methods will be injected into the
14
+ root namespace. For example, this source file:
15
+
16
+ #!/usr/bin/env ruby
17
+
18
+ require 'nomadsl/dsl'
19
+
20
+ job "example" do
21
+ type "batch"
22
+ region "iad"
23
+ datacenters "prod"
24
+ parameterized(payload: "required")
25
+ group "work" do
26
+ task "work" do
27
+ vault(policies: ["example-job"])
28
+ meta(aws_region: "ap-southeast-2")
29
+ dispatch_payload(file: "message.txt")
30
+ preloaded_vault_aws_creds("iam", "iam/sts/example-iam")
31
+ artifact(source: "s3.amazonaws.com/example-bucket/example-job/script.sh")
32
+ config(command: "script.sh")
33
+ end
34
+ end
35
+ end
36
+
37
+ Will generate this output:
38
+
39
+ $ ruby example.nomadsl
40
+ job "example" {
41
+ type = "batch"
42
+ region = "iad"
43
+ datacenters = ["prod"]
44
+
45
+ parameterized {
46
+ payload = "required"
47
+ }
48
+
49
+ group "work" {
50
+ task "work" {
51
+ driver = "exec"
52
+
53
+ vault {
54
+ policies = ["example-job"]
55
+ }
56
+
57
+ meta {
58
+ aws_region = "ap-southeast-2"
59
+ }
60
+
61
+ dispatch_payload {
62
+ file = "message.txt"
63
+ }
64
+
65
+ template {
66
+ destination = "secrets/iam.env"
67
+ data = <<BLOB
68
+ {{with secret "iam/sts/example-iam"}}
69
+ AWS_ACCESS_KEY_ID={{.Data.access_key}}
70
+ AWS_SECRET_ACCESS_KEY={{.Data.secret_key}}
71
+ AWS_SESSION_TOKEN={{.Data.security_token}}
72
+ {{end}}
73
+ BLOB
74
+ env = true
75
+ }
76
+
77
+ artifact {
78
+ source = "s3.amazonaws.com/example-bucket/example-job/script.sh"
79
+ }
80
+
81
+ config {
82
+ command = "script.sh"
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ ## Other uses
89
+
90
+ By requiring only `nomadsl`, you can inject these methods into another class:
91
+
92
+ #!/usr/bin/env ruby
93
+
94
+ require 'nomadsl'
95
+
96
+ class Example
97
+ include Nomadsl
98
+
99
+ def generate
100
+ @result = job "example" do
101
+ # ...
102
+ end
103
+ end
104
+ end
105
+
106
+ puts Example.new.generate
107
+
108
+ ## Roadmap
109
+
110
+ * Make all attributes explicitly callable
111
+ * Make subkeys embeddable in arglists if sensible
112
+ * Allow injecting comments into the rendered file
113
+ * Finish custom config blocks for each task driver
114
+ * Make errors report their correct location
115
+
116
+ ## Contributing
117
+
118
+ I'm happy to accept suggestions, bug reports, and pull requests through Github.
119
+
120
+ ## License
121
+
122
+ This software is public domain. No rights are reserved. See LICENSE for more
123
+ information.
@@ -0,0 +1,4 @@
1
+ require 'nomadsl'
2
+
3
+ include Nomadsl
4
+ nomadsl_print(true)
@@ -0,0 +1,3 @@
1
+ module Nomadsl
2
+ VERSION = "0.1.0"
3
+ end
data/lib/nomadsl.rb ADDED
@@ -0,0 +1,524 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+
5
+ ARTIFACTS = {}
6
+
7
+ module Nomadsl
8
+ def die(err)
9
+ raise err
10
+ end
11
+
12
+ def nomadsl_print(b)
13
+ @nomadsl_print = b
14
+ end
15
+
16
+ def only(*levels)
17
+ unless levels.include? @stack.last
18
+ loc = caller_locations(1,1)[0]
19
+ die "Bad syntax on line #{loc.lineno}! '#{loc.label}' can only appear in #{levels.collect{|x| "'#{x}'" }.join(', ')}"
20
+ end
21
+ end
22
+
23
+ #################################################################
24
+ # rendering methods
25
+
26
+ def str!(k, v)
27
+ die "Value for '#{k}' is nil" if v.nil?
28
+ str(k, v)
29
+ end
30
+
31
+ def str(k, v)
32
+ render "#{k} = #{v.to_s.to_json}" unless v.nil?
33
+ end
34
+
35
+ def list!(k, v)
36
+ die "Value for '#{k}' is nil" if v.nil?
37
+ list(k, v)
38
+ end
39
+
40
+ def list(k, v)
41
+ render "#{k} = #{[v].flatten.to_json}" unless v.nil?
42
+ end
43
+
44
+ def int!(k, v)
45
+ die "Value for '#{k}' is nil" if v.nil?
46
+ int(k, v)
47
+ end
48
+
49
+ def int(k, v)
50
+ render "#{k} = #{v.to_i}" unless v.nil?
51
+ end
52
+
53
+ def bool!(k, v)
54
+ die "Value for '#{k}' is nil" if v.nil?
55
+ bool(k, v)
56
+ end
57
+
58
+ def bool(k, v)
59
+ render "#{k} = #{v ? true : false}" unless v.nil?
60
+ end
61
+
62
+ def blob!(k, v)
63
+ die "Value for '#{k}' is nil" if v.nil?
64
+ blob(k, v)
65
+ end
66
+
67
+ def blob(k, v)
68
+ render "#{k} = <<BLOB"
69
+ @out << "#{v.chomp}\nBLOB\n"
70
+ end
71
+
72
+ # try really hard
73
+ def any(k, v)
74
+ if v.nil?
75
+ return
76
+ elsif v.is_a? Array
77
+ list k, v
78
+ elsif v.is_a? Integer
79
+ int k, v
80
+ elsif v.is_a? TrueClass or v.is_a? FalseClass
81
+ bool k, v
82
+ elsif v.is_a? String
83
+ if v.to_i.to_s == v
84
+ int k, v
85
+ else
86
+ str k, v
87
+ end
88
+ elsif v.is_a? Hash
89
+ v.each do |k, v|
90
+ any k, v
91
+ end
92
+ else
93
+ die "An unexpected type was encountered."
94
+ end
95
+ end
96
+
97
+ def render(s)
98
+ @first = false
99
+ @out << "#{' '*@indent}#{s}\n"
100
+ end
101
+
102
+ def block(t, n=nil)
103
+ unless @first
104
+ @out << "\n"
105
+ end
106
+
107
+ render(n ? "#{t} #{n.to_json} {" : "#{t} {")
108
+
109
+ if block_given?
110
+ @stack.push t
111
+ @first = true
112
+ @indent += 1
113
+ yield
114
+ @indent -= 1
115
+ @first = false
116
+ @stack.pop
117
+ end
118
+ render "}"
119
+ end
120
+
121
+ ################################################
122
+ # real stuff
123
+ # https://www.nomadproject.io/docs/job-specification/
124
+
125
+ # https://www.nomadproject.io/docs/job-specification/job.html#all_at_once
126
+ def all_at_once(v)
127
+ only :job
128
+ bool :all_at_once, v
129
+ end
130
+
131
+ # https://www.nomadproject.io/docs/job-specification/artifact.html
132
+ def artifact(source:, destination: nil, mode: nil, options: nil)
133
+ only :task
134
+ block(:artifact) do
135
+ str! :source, source
136
+ str :destination, destination
137
+ str :mode, mode
138
+ if options
139
+ block(:options) do
140
+ options.each do |k,v|
141
+ str k, v
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ # https://www.nomadproject.io/docs/job-specification/service.html#check-parameters
149
+ def check(address_mode: nil, args: nil, command: nil, grpc_service: nil, grpc_use_tls: nil, initial_status: nil, interval: nil, method: nil, name: nil, path: nil, port: nil, protocol: nil, timeout: nil, type: nil, tls_skip_verify: nil)
150
+ only :service
151
+ block(:check) do
152
+ str :address_mode, address_mode
153
+ list :args, args
154
+ str :command, command
155
+ str :grpc_service, grpc_service
156
+ bool :grpc_use_tls, grpc_use_tls
157
+ str :initial_status, initial_status
158
+ str :interval, interval
159
+ str :method, method
160
+ str :name, name
161
+ str :path, path
162
+ str :port, port
163
+ str :protocol, protocol
164
+ str :timeout, timeout
165
+ str :type, type
166
+ bool :tls_skip_verify, tls_skip_verify
167
+ yield if block_given?
168
+ end
169
+ end
170
+
171
+ # https://www.nomadproject.io/docs/job-specification/check_restart.html
172
+ def check_restart(limit: nil, grace: nil, ignore_warnings: nil)
173
+ only :service, :check
174
+ block(:check_restart) do
175
+ int :limit, limit
176
+ str :grace, grace
177
+ bool :ignore_warnings, ignore_warnings
178
+ end
179
+ end
180
+
181
+ # https://www.nomadproject.io/docs/job-specification/task.html#config
182
+ def config(**opts)
183
+ only :task
184
+ config_method = "__config_#{@driver}".to_sym
185
+ if private_methods.include?(config_method)
186
+ send(config_method, **opts)
187
+ else
188
+ # try to wing it
189
+ block(:config) do
190
+ opts.each do |k,v|
191
+ any k, v
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ def __config_exec(command:, args: nil)
198
+ only :task
199
+ block(:config) do
200
+ str! :command, command
201
+ list :args, args
202
+ end
203
+ end
204
+
205
+
206
+ # https://www.nomadproject.io/docs/job-specification/constraint.html
207
+ def constraint(attribute: nil, operator: nil, value: nil)
208
+ only :job, :group, :task
209
+ block(:constraint) do
210
+ str :attribute, attribute
211
+ str :operator, operator
212
+ str :value, value
213
+ end
214
+ end
215
+
216
+ # https://www.nomadproject.io/docs/job-specification/job.html#datacenters
217
+ def datacenters(*d)
218
+ only :job
219
+ list! :datacenters, d
220
+ end
221
+
222
+ # https://www.nomadproject.io/docs/job-specification/dispatch_payload.html
223
+ def dispatch_payload(file:)
224
+ only :task
225
+ block(:dispatch_payload) do
226
+ str! :file, file
227
+ end
228
+ end
229
+
230
+ # https://www.nomadproject.io/docs/job-specification/env.html
231
+ def env(**opts)
232
+ only :task
233
+ block(:env) do
234
+ opts.each do |k,v|
235
+ str k, v
236
+ end
237
+ end
238
+ end
239
+
240
+ # https://www.nomadproject.io/docs/job-specification/ephemeral_disk.html
241
+ def ephemeral_disk(migrate: nil, size: nil, sticky: nil)
242
+ only :group
243
+ block(:ephemeral_disk) do
244
+ bool :migrate, migrate
245
+ int :size, size
246
+ bool :sticky, sticky
247
+ end
248
+ end
249
+
250
+ # https://www.nomadproject.io/docs/job-specification/group.html
251
+ def group(name, count: nil)
252
+ only :job
253
+ block(:group, name) do
254
+ int :count, count
255
+ yield
256
+ end
257
+ end
258
+
259
+ # https://www.nomadproject.io/docs/job-specification/service.html#header-stanza
260
+ def header(name, values)
261
+ only :check
262
+ block(:header) do
263
+ list! name, values
264
+ end
265
+ end
266
+
267
+ # https://www.nomadproject.io/docs/job-specification/job.html
268
+ def job(j)
269
+ # initialize the variables since this is the actual root
270
+ @out = ""
271
+ @indent = 0
272
+ @first = true
273
+ @stack = [:root]
274
+
275
+ only :root
276
+ result = block(:job, j) { yield }
277
+ if @nomadsl_print
278
+ puts result
279
+ end
280
+ result
281
+ end
282
+
283
+ # https://www.nomadproject.io/docs/job-specification/logs.html
284
+ def logs(max_files: nil, max_file_size: nil)
285
+ only :task
286
+ block(:logs) do
287
+ int :max_files, max_files
288
+ int :max_file_size, max_file_size
289
+ end
290
+ end
291
+
292
+ # https://www.nomadproject.io/docs/job-specification/meta.html
293
+ def meta(**opts)
294
+ only :job, :group, :task
295
+ block(:meta) do
296
+ opts.each do |k,v|
297
+ str k, v
298
+ end
299
+ end
300
+ end
301
+
302
+ # https://www.nomadproject.io/docs/job-specification/migrate.html
303
+ def migrate(max_parallel: nil, health_check: nil, min_healthy_time: nil, healthy_deadline: nil)
304
+ only :job, :group
305
+ block(:migrate) do
306
+ int :max_parallel, max_parallel
307
+ str :health_check, health_check
308
+ str :min_healthy_time, min_healthy_time
309
+ str :healthy_deadline, healthy_deadline
310
+ end
311
+ end
312
+
313
+ # https://www.nomadproject.io/docs/job-specification/job.html#namespace
314
+ # Supported by Nomad Enterprise ONLY
315
+ def namespace(n)
316
+ only :job
317
+ str! :namespace, n
318
+ end
319
+
320
+ # https://www.nomadproject.io/docs/job-specification/network.html
321
+ def network(mbits: nil)
322
+ only :resources
323
+ block(:network) do
324
+ int :mbits, mbits
325
+ yield if block_given?
326
+ end
327
+ end
328
+
329
+ # https://www.nomadproject.io/docs/job-specification/parameterized.html
330
+ def parameterized(payload: "optional", meta_optional: nil, meta_required: nil)
331
+ only :job
332
+ die "Bad option for parameterized.payload: '#{payload}'" unless %w( optional required forbidden ).include?(payload)
333
+ block :parameterized do
334
+ str! :payload, payload
335
+ list :meta_optional, meta_optional
336
+ list :meta_required, meta_required
337
+ end
338
+ end
339
+
340
+ # https://www.nomadproject.io/docs/job-specification/periodic.html
341
+ def periodic(cron: nil, prohibit_overlap: nil, time_zone: nil)
342
+ only :job
343
+ block(:periodic) do
344
+ str :cron, cron
345
+ bool :prohibit_overlap, prohibit_overlap
346
+ str :time_zone, time_zone
347
+ end
348
+ end
349
+
350
+ # https://www.nomadproject.io/docs/job-specification/network.html#port
351
+ def port(n, static: nil)
352
+ only :network
353
+ if static
354
+ block(:port, n) do
355
+ int :static, static
356
+ end
357
+ else
358
+ render "port #{n.to_json} {}"
359
+ end
360
+ end
361
+
362
+ # https://www.nomadproject.io/docs/job-specification/job.html#priority
363
+ def priority(p)
364
+ only :job
365
+ int! :priority, p
366
+ end
367
+
368
+ # https://www.nomadproject.io/docs/job-specification/job.html#region
369
+ def region(r)
370
+ only :job
371
+ str! :region, r
372
+ end
373
+
374
+ # https://www.nomadproject.io/docs/job-specification/reschedule.html
375
+ def reschedule(attempts: nil, interval: nil, delay: nil, delay_function: nil, max_delay: nil, unlimited: nil)
376
+ only :job, :group
377
+ block(:reschedule) do
378
+ int :attempts, attempts
379
+ str :interval, interval
380
+ str :delay, delay
381
+ str :delay_function, delay_function
382
+ str :max_delay, max_delay
383
+ bool :unlimited, unlimited
384
+ end
385
+ end
386
+
387
+ # https://www.nomadproject.io/docs/job-specification/resources.html
388
+ def resources(cpu: nil, iops: nil, memory: nil)
389
+ only :task
390
+ block(:resources) do
391
+ int :cpu, cpu
392
+ int :iops, iops
393
+ int :memory, memory
394
+ yield if block_given?
395
+ end
396
+ end
397
+
398
+ # https://www.nomadproject.io/docs/job-specification/restart.html
399
+ def restart(attempts: nil, delay: nil, interval: nil, mode: nil)
400
+ only :group
401
+ block(:restart)do
402
+ int :attempts, attempts
403
+ str :delay, delay
404
+ str :interval, interval
405
+ str :mode, mode
406
+ end
407
+ end
408
+
409
+ # https://www.nomadproject.io/docs/job-specification/service.html
410
+ def service(address_mode: nil, canary_tags: nil, name: nil, port: nil, tags: nil)
411
+ only :task
412
+ block(:service) do
413
+ str :address_mode, address_mode
414
+ list :canary_tags, canary_tags
415
+ str :name, name
416
+ str :port, port
417
+ list :tags, tags
418
+ yield if block_given?
419
+ end
420
+ end
421
+
422
+ # https://www.nomadproject.io/docs/job-specification/task.html
423
+ def task(t, driver: "exec", kill_signal: nil, kill_timeout: nil, leader: nil, shutdown_delay: nil, user: nil)
424
+ only :group
425
+ @driver = driver
426
+ block(:task, t) do
427
+ str :driver, driver
428
+ str :kill_signal, kill_signal
429
+ str :kill_timeout, kill_timeout
430
+ bool :leader, leader
431
+ str :shutdown_delay, shutdown_delay
432
+ str :user, user
433
+ yield
434
+ end
435
+ end
436
+
437
+ # https://www.nomadproject.io/docs/job-specification/template.html
438
+ def template(change_mode: nil, change_signal: nil, data: nil, destination:, env: nil, left_delimiter: nil, perms: nil, right_delimiter: nil, source: nil, splay: nil, vault_grace: nil)
439
+ only :task
440
+ block(:template) do
441
+ str :change_mode, change_mode
442
+ str :change_signal, change_signal
443
+ str! :destination, destination
444
+ blob :data, data
445
+ bool :env, env
446
+ str :left_delimiter, left_delimiter
447
+ str :perms, perms
448
+ str :right_delimiter, right_delimiter
449
+ str :source, source
450
+ str :splay, splay
451
+ str :vault_grace, vault_grace
452
+ end
453
+ end
454
+
455
+ # https://www.nomadproject.io/docs/job-specification/job.html#type
456
+ def type(t)
457
+ only :job
458
+ die "Bad job type '#{t}'" unless %w( batch service system ).include?(t)
459
+ str! :type, t
460
+ end
461
+
462
+ # https://www.nomadproject.io/docs/job-specification/update.html
463
+ def update(max_parallel: nil, health_check: nil, min_healthy_time: nil, healthy_deadline: nil, progress_deadline: nil, auto_revert: nil, canary: nil, stagger: nil)
464
+ only :job, :group
465
+ block(:update) do
466
+ int :max_parallel, max_parallel
467
+ str :health_check, health_check
468
+ str :min_healthy_time, min_healthy_time
469
+ str :healthy_deadline, healthy_deadline
470
+ str :progress_deadline, progress_deadline
471
+ bool :auto_revert, auto_revert
472
+ int :canary, canary
473
+ str :stagger, stagger
474
+ end
475
+ end
476
+
477
+ # https://www.nomadproject.io/docs/job-specification/vault.html
478
+ def vault(change_mode: nil, change_token: nil, env: nil, policies: nil)
479
+ only :job, :group, :task
480
+ block(:vault) do
481
+ str :change_mode, change_mode
482
+ str :change_token, change_token
483
+ bool :env, env
484
+ list :policies, policies
485
+ end
486
+ end
487
+
488
+ # https://www.nomadproject.io/docs/job-specification/job.html#vault_token
489
+ # NOTE: explicitly unsupported, dangerous
490
+
491
+
492
+ ########################################################
493
+ # shortcuts
494
+
495
+ def package(id)
496
+ if pkg = ARTIFACTS[id.to_sym]
497
+ artifact(**pkg)
498
+ else
499
+ die "Unknown package ID '#{id}'"
500
+ end
501
+ end
502
+
503
+ def preloaded_vault_aws_creds(name, path)
504
+ data = <<DATA
505
+ {{with secret "#{path}"}}
506
+ AWS_ACCESS_KEY_ID={{.Data.access_key}}
507
+ AWS_SECRET_ACCESS_KEY={{.Data.secret_key}}
508
+ AWS_SESSION_TOKEN={{.Data.security_token}}
509
+ {{end}}
510
+ DATA
511
+ template(data: data, destination: "secrets/#{name}.env", env: true)
512
+ end
513
+
514
+ def vault_aws_creds(name, path)
515
+ data = <<DATA
516
+ {{with secret "#{path}"}}
517
+ export AWS_ACCESS_KEY_ID={{.Data.access_key}}
518
+ export AWS_SECRET_ACCESS_KEY={{.Data.secret_key}}
519
+ export AWS_SESSION_TOKEN={{.Data.security_token}}
520
+ {{end}}
521
+ DATA
522
+ template(data: data, destination: "secrets/#{name}.env")
523
+ end
524
+ end
data/nomadsl.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ require_relative 'lib/nomadsl/version.rb'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'nomadsl'
5
+ s.version = Nomadsl::VERSION
6
+ s.authors = ['David Adams']
7
+ s.email = 'daveadams@gmail.com'
8
+ s.date = Time.now.strftime('%Y-%m-%d')
9
+ s.license = 'CC0'
10
+ s.homepage = 'https://github.com/daveadams/nomadsl'
11
+ s.required_ruby_version = '>=2.4.0'
12
+
13
+ s.summary = 'Ruby DSL for generating Nomad job specification files'
14
+
15
+ s.require_paths = ['lib']
16
+ s.files = Dir["lib/**/*.rb"] + [
17
+ 'README.md',
18
+ 'LICENSE',
19
+ 'nomadsl.gemspec'
20
+ ]
21
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nomadsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - David Adams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: daveadams@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENSE
20
+ - README.md
21
+ - lib/nomadsl.rb
22
+ - lib/nomadsl/dsl.rb
23
+ - lib/nomadsl/version.rb
24
+ - nomadsl.gemspec
25
+ homepage: https://github.com/daveadams/nomadsl
26
+ licenses:
27
+ - CC0
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 2.4.0
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.6.13
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Ruby DSL for generating Nomad job specification files
49
+ test_files: []