nomadsl 0.1.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 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: []