Skip to content
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/doc/
/pkg/
/spec/reports/
/spec/support/rendered/*.yml
/spec/support/rendered/*
/tmp/

# rspec failure tracking
Expand Down
5 changes: 5 additions & 0 deletions lib/consult.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Consult

class << self
attr_reader :config, :templates
attr_writer :exception_handler

def load(config_dir: nil)
root directory: config_dir
Expand Down Expand Up @@ -78,6 +79,10 @@ def render!
active_templates.each(&:render)
end

def exception_handler
@exception_handler ||= ->(e) { puts e.message }
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
38 changes: 35 additions & 3 deletions lib/consult/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,31 @@ def initialize(name, config)
end

def render(save: true)
renderer = ERB.new(File.read(path, encoding: 'utf-8'), nil, '-')
# Attempt to render
renderer = ERB.new(contents, nil, '-')
result = renderer.result(binding)

File.open(dest, 'w') { |f| f << result } if save
result
rescue StandardError => e
puts "Error rendering template: #{name}"
raise e
Consult.exception_handler.call(e)
nil
end

def path
return unless @config.key?(:path)
resolve @config.fetch(:path)
end

def paths
return [] unless @config.key?(:paths)
@config.fetch(:paths).map { |path| resolve(path) }
end

def vars
@config[:vars]
end

def dest
resolve @config.fetch(:dest)
end
Expand All @@ -42,5 +53,26 @@ def expired?
return true if !config.key?(:ttl) || !dest.exist?
dest.mtime < (Time.now - @config[:ttl].to_i)
end

private

# Concatenate all the source templates together, in the order provided
# Disk contents go first
def contents
disk_contents + consul_contents
end

def consul_contents
[@config[:consul_key], @config[:consul_keys]].compact.flatten.map do |key|
Diplomat::Kv.get(key, options: nil, not_found: :return, found: :return)
end.join
end

# Concatenate all the source templates together, in the order provided
def disk_contents
[path, paths].compact.flatten.map do |file_path|
File.read file_path, encoding: 'utf-8'
end.join
end
end
end
5 changes: 5 additions & 0 deletions spec/consult_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,10 @@

it 'renders without error' do
expect { Consult.render! }.to_not raise_exception

# Verify text templates rendered correctly
%w[elements.txt more_elements.txt consul_elements.txt more_consul_elements.txt multi_pass.txt].each do |template|
expect(FileUtils.compare_file("spec/support/expected/#{template}", "spec/support/rendered/#{template}")).to be true
end
end
end
32 changes: 32 additions & 0 deletions spec/lib/template_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# frozen_string_literal: true

class Handler
class << self
attr_reader :error
def call(error)
@error = error
end
end
end

RSpec.describe Consult::Template do
let(:name) { 'database.yml' }
let(:config) do
Expand All @@ -11,6 +20,14 @@
end
let(:template) { Consult::Template.new(name, config) }

let(:error_template) { 'Corbin Dallas' }
let(:error_config) do
{
consul_key: 'templates/error_test',
dest: 'rendered/error_test.txt'
}
end

before :all do
Consult.load config_dir: 'spec/support'
end
Expand Down Expand Up @@ -75,4 +92,19 @@
expect(template.indent(colon_separated, 1, ':')).to eq ' hello: world'
end
end

context 'error handling' do
it 'allows custom error handlers' do
Consult.exception_handler = Handler
Diplomat::Kv.put('templates/error_test', error_template)
template = Consult::Template.new('error_template', error_config)
expect(template.render).to eq error_template

Diplomat::Kv.delete('templates/error_test')
expect(template.render).to be nil
expect(Handler.error).to be_instance_of Diplomat::KeyNotFound

expect(File.read(template.dest)).to eq error_template
end
end
end
64 changes: 64 additions & 0 deletions spec/support/config/consult.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,70 @@ shared:
dest: rendered/database.yml
ttl: 10 # seconds

elements:
paths:
- templates/elements/air.txt
- templates/elements/fire.txt
dest: rendered/elements.txt
vars:
air: 1
fire: 2

more_elements:
path: templates/elements/air.txt
paths:
- templates/elements/fire.txt
- templates/elements/water.txt
dest: rendered/more_elements.txt
vars:
air: 1
fire: 2
water: 3

consul_elements:
consul_keys:
- templates/elements/earth
- templates/elements/love
dest: rendered/consul_elements.txt
vars:
earth: 4
love: 5

more_consul_elements:
consul_key: templates/elements/earth
consul_keys:
- templates/elements/love
- templates/elements/aziz
dest: rendered/more_consul_elements.txt
vars:
earth: 4
love: 5
aziz: 'Light!'

multi_pass:
path: templates/elements/air.txt
paths:
- templates/elements/fire.txt
- templates/elements/water.txt
consul_key: templates/elements/earth
consul_keys:
- templates/elements/love
- templates/elements/aziz
dest: rendered/multi_pass.txt
vars:
air: 1
fire: 2
water: 3
earth: 4
love: 5
aziz: 'Light!'

dest_fail:
consul_key: templates/elements/aziz
dest: rendered/nope/dest_fail.keep
vars:
aziz: 'Light!'

test:
templates:
secrets:
Expand Down
2 changes: 2 additions & 0 deletions spec/support/expected/consul_elements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Earth is the 4th element
Love is the 5th element!
2 changes: 2 additions & 0 deletions spec/support/expected/elements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Air is the 1st element
Fire is the 2nd element
3 changes: 3 additions & 0 deletions spec/support/expected/more_consul_elements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Earth is the 4th element
Love is the 5th element!
Aziz! Light!
3 changes: 3 additions & 0 deletions spec/support/expected/more_elements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Air is the 1st element
Fire is the 2nd element
Water is the 3rd element
6 changes: 6 additions & 0 deletions spec/support/expected/multi_pass.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Air is the 1st element
Fire is the 2nd element
Water is the 3rd element
Earth is the 4th element
Love is the 5th element!
Aziz! Light!
15 changes: 15 additions & 0 deletions spec/support/populate_consul.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,18 @@ curl \
--request PUT \
--data 'db1.local.net' \
http://0.0.0.0:8500/v1/kv/infrastructure/db1/dns

curl \
--request PUT \
--data $'Earth is the <%= vars[:earth] %>th element\n' \
http://0.0.0.0:8500/v1/kv/templates/elements/earth

curl \
--request PUT \
--data $'Love is the <%= vars[:love] %>th element!\n' \
http://0.0.0.0:8500/v1/kv/templates/elements/love

curl \
--request PUT \
--data $'Aziz! <%= vars[:aziz] %>\n' \
http://0.0.0.0:8500/v1/kv/templates/elements/aziz
1 change: 1 addition & 0 deletions spec/support/templates/elements/air.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Air is the <%= vars[:air] %>st element
1 change: 1 addition & 0 deletions spec/support/templates/elements/fire.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fire is the <%= vars[:fire] %>nd element
1 change: 1 addition & 0 deletions spec/support/templates/elements/water.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Water is the <%= vars[:water] %>rd element