Skip to content

Commit

Permalink
Add support for YAML templates (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
borsothy authored and askreet committed Sep 28, 2016
1 parent ab988dd commit c45b78c
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 20 deletions.
17 changes: 17 additions & 0 deletions lib/moonshot/json_stack_template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'json'
require_relative 'stack_template'

module Moonshot
# Handles JSON formatted AWS template files.
class JsonStackTemplate < StackTemplate
def body
template_body.to_json
end

private

def template_body
@template_body ||= JSON.parse(File.read(@filename))
end
end
end
42 changes: 39 additions & 3 deletions lib/moonshot/stack.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
require_relative 'creds_helper'
require_relative 'doctor_helper'

require_relative 'stack_template'
require_relative 'yaml_stack_template'
require_relative 'json_stack_template'
require_relative 'stack_parameter_printer'
require_relative 'stack_output_printer'
require_relative 'stack_asg_printer'
Expand Down Expand Up @@ -154,12 +155,20 @@ def default_values
end

def template
@template ||= StackTemplate.new(template_file, log: @log)
@template ||= load_template_file
end

# @return [String] the path to the template file.
def template_file
File.join(Dir.pwd, 'cloud_formation', "#{@app_name}.json")
json = json_template_path
yaml = yaml_template_path

@template_file ||= Dir[json].first || Dir[yaml].first

raise 'CloudFormation template not found at'\
"#{json} or #{yaml}!" unless @template_file

@template_file
end

# @return [String] the path to the parameters file.
Expand Down Expand Up @@ -195,6 +204,33 @@ def load_parameters_file
end
end

def json_template_path
"#{raw_template_file_name}.json"
end

def yaml_template_path
"#{raw_template_file_name}.yml"
end

# @return [String] the path to the template file without extension.
def raw_template_file_name
@raw_template_file_name ||= File.join(Dir.pwd, 'cloud_formation', @app_name)
end

def load_template_file
json_template = JsonStackTemplate.new(json_template_path, log: @log)
yaml_template = YamlStackTemplate.new(yaml_template_path, log: @log)
case
when json_template.exist?
json_template
when yaml_template.exist?
yaml_template
else
raise "CloudFormation template not found at #{json_template_path} "\
"or #{yaml_template_path}!" unless @template_file
end
end

def stack_parameter_overrides
overrides.map do |k, v|
{ parameter_key: k, parameter_value: v.to_s }
Expand Down
25 changes: 8 additions & 17 deletions lib/moonshot/stack_template.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
require 'json'

module Moonshot
# A StackTemplate loads the JSON template from disk and stores information
# A StackTemplate loads the template from disk and stores information
# about it.
class StackTemplate
Parameter = Struct.new(:name, :default) do
Expand All @@ -10,30 +8,23 @@ def required?
end
end

attr_reader :body

def initialize(filename, log:)
@log = log

unless File.exist?(filename)
@log.error("Could not find CloudFormation template at #{filename}")
raise
end

# The maximum TemplateBody length is 51,200 bytes, so we remove
# formatting white space.
@body = JSON.parse(File.read(filename)).to_json
@filename = filename
end

def parameters
JSON.parse(@body).fetch('Parameters', {}).map do |k, v|
template_body.fetch('Parameters', {}).map do |k, v|
Parameter.new(k, v['Default'])
end
end

# Return a list of defined resource names in the template.
def resource_names
JSON.parse(@body).fetch('Resources', {}).keys
template_body.fetch('Resources', {}).keys
end

def exist?
File.exist?(@filename)
end
end
end
17 changes: 17 additions & 0 deletions lib/moonshot/yaml_stack_template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'yaml'
require_relative 'stack_template'

module Moonshot
# Handles YAML formatted AWS template files.
class YamlStackTemplate < StackTemplate
def body
template_body.to_yaml
end

private

def template_body
@template_body ||= YAML.load_file(@filename)
end
end
end
6 changes: 6 additions & 0 deletions spec/fs_fixtures/cloud_formation/rspec-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- Resources:
- Parameters:
- Parent1:
- Type: String
- Description: This is imported from the parent stack on create.
31 changes: 31 additions & 0 deletions spec/moonshot/stack_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,35 @@
expect(subject.parameters_file).to eq(path)
end
end

describe '#template' do
let(:yaml_path) { File.join(Dir.pwd, 'cloud_formation', 'rspec-app.yml') }
let(:json_path) { File.join(Dir.pwd, 'cloud_formation', 'rspec-app.json') }

context 'when there is a template file in both formats' do
it 'should prefer the JSON formatted template file' do
expect(subject.template).to be_an_instance_of(Moonshot::JsonStackTemplate)
end
end

context 'when there is only one kind of template file available' do
it 'should pick the JSON template file by default' do
FakeFS::File.delete(yaml_path)
expect(subject.template).to be_an_instance_of(Moonshot::JsonStackTemplate)
end

it 'should fall back to YAML if no JSON template was found' do
FakeFS::File.delete(json_path)
expect(subject.template).to be_an_instance_of(Moonshot::YamlStackTemplate)
end
end

context 'when there is no template file available' do
it 'should raise RuntimeError' do
[yaml_path, json_path].each { |p| FakeFS::File.delete(p) }

expect { subject.template }.to raise_error(RuntimeError)
end
end
end
end

0 comments on commit c45b78c

Please sign in to comment.