Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template validation #44

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bin/consult
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby

require_relative '../lib/consult/cli'
require 'bundler/setup'
require 'consult/cli'

cli = Consult::CLI.instance
cli.parse
Expand Down
1 change: 1 addition & 0 deletions consult.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Gem::Specification.new do |spec|

spec.add_dependency 'diplomat', '~> 2.6'
spec.add_dependency 'vault', '>= 0.10.0', '< 1.0.0'
spec.add_dependency 'dry-validation', '<= 1.9.0'

spec.add_development_dependency 'bundler'
spec.add_development_dependency 'guard'
Expand Down
7 changes: 7 additions & 0 deletions lib/consult.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ def render!
active_templates.each(&:render)
end

def validate_templates
active_templates do |t|
t.validate
puts "#{t.name}: #{t.validation.errors}"
end
end

# Map more conventional `token` parameter to Diplomat's `acl_token` configuration.
# Additionally, we support ~/.consul-token, similar to Vault's support for ~/.vault-token
def consul_token
Expand Down
1 change: 1 addition & 0 deletions lib/consult/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def parse(args = ARGV)
end

def render
Consult.validate_templates
Consult.render!
end

Expand Down
18 changes: 17 additions & 1 deletion lib/consult/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'fileutils'
require_relative 'template_functions'
require_relative 'template_schema'
require_relative '../support/hash_extensions'

module Consult
Expand All @@ -24,7 +25,11 @@ def render(save: true)
end

# Attempt to render
renderer = ERB.new(contents, nil, '-')
renderer = if legacy_erb_args?
ERB.new(contents, nil, '-')
else
ERB.new(contents, trim_mode: '-')
end
result = renderer.result(binding)

puts "Consult: Rendering #{name}" + (save ? " to #{dest}" : "...") if verbose?
Expand Down Expand Up @@ -76,8 +81,19 @@ def ordered_locations
@config.keys & LOCATIONS
end

def validate
@validation = TemplateSchema.new.call(@config)
end

private

def legacy_erb_args?
# prior to 2.2.2 ERB.version was a string rather than a Gem::Version-compatible version number, so this will raise an exception
Gem::Version.new(ERB.version) < Gem::Version.new('2.2.0')
rescue
true
end

# Concatenate all the source templates together, in the order provided
def contents
@_contents ||= ordered_locations.map do |location|
Expand Down
30 changes: 30 additions & 0 deletions lib/consult/template_schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string-literal: true

require 'dry-validation'

class TemplateSchema < Dry::Validation::Contract
schema do
# Output destination is required
required(:dest).value(:string)

# At least one of path/paths/consul_key/consul_keys is required
optional(:path).value(:string)
optional(:paths).value(:array)
optional(:consul_key).value(:string)
optional(:consul_keys).value(:array)

# Other configuration
optional(:ttl).value(:integer)
optional(:vars).value(:hash)
end

rule(:path, :paths, :consul_key, :consul_keys) do
unless key?(:path) || key?(:paths) || key?(:consul_key) || key?(:consul_keys)
base.failure("A template source must be specified. Please provide one or more of: path, paths, consul_key, consul_keys")
end
end

rule(:ttl) do
key.failure "A TTL is strongly recommended to avoid rendering templates too often, especially in multi-process environments." if value.to_i == 0
end
end
3 changes: 3 additions & 0 deletions spec/support/config/consult.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ shared:
path: x/y/z.txt
dest: rendered/nope/skip_missing_template

missing_source:
dest: rendered/nowhere.txt

test:
vars:
test_env_override: some value
Expand Down