rna 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.
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG +1 -0
- data/Gemfile +3 -0
- data/Guardfile +9 -0
- data/LICENSE +22 -0
- data/README.md +89 -0
- data/Rakefile +9 -0
- data/bin/rna +8 -0
- data/lib/files/rna.rb +34 -0
- data/lib/files/s3.yml +4 -0
- data/lib/rna/cli.rb +29 -0
- data/lib/rna/dsl.rb +129 -0
- data/lib/rna/outputers.rb +46 -0
- data/lib/rna/tasks.rb +31 -0
- data/lib/rna/version.rb +3 -0
- data/lib/rna.rb +12 -0
- data/rna.gemspec +28 -0
- data/spec/lib/rna_spec.rb +192 -0
- data/spec/project/config/rna.rb +47 -0
- data/spec/project/config/s3.example.yml +4 -0
- data/spec/project2/.gitkeep +0 -0
- metadata +201 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0 Initial Release
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Tung Nguyen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
Rna gem
|
2
|
+
===========
|
3
|
+
|
4
|
+
Rna is a ruby gem that provides simple DSL for generating node.json files required by chef-solo.
|
5
|
+
|
6
|
+
Requirements
|
7
|
+
------------
|
8
|
+
|
9
|
+
<pre>
|
10
|
+
$ gem install rna
|
11
|
+
</pre>
|
12
|
+
|
13
|
+
Usage
|
14
|
+
------------
|
15
|
+
|
16
|
+
<pre>
|
17
|
+
$ mkdir rna_project
|
18
|
+
$ cd rna_project
|
19
|
+
$ rna init
|
20
|
+
</pre>
|
21
|
+
|
22
|
+
This will sets starter config/rna.rb and config/s3.yml files.
|
23
|
+
|
24
|
+
Example rna.rb file
|
25
|
+
------------
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# This is starter example rna template.
|
29
|
+
# This is meant be be modified to your needs.
|
30
|
+
###################################
|
31
|
+
# Settings
|
32
|
+
default_inherits 'base'
|
33
|
+
global_attributes(:except => ['base']) do
|
34
|
+
set 'framework_env', 'production'
|
35
|
+
end
|
36
|
+
|
37
|
+
###################################
|
38
|
+
# Post processing rules that run at the end
|
39
|
+
rule do
|
40
|
+
set 'framework_env', 'production' if name =~ /^prod/
|
41
|
+
set 'framework_env', 'staging' if name =~ /^stag/
|
42
|
+
end
|
43
|
+
|
44
|
+
###################################
|
45
|
+
# Roles
|
46
|
+
# base
|
47
|
+
role 'base' do
|
48
|
+
run_list ['base']
|
49
|
+
end
|
50
|
+
# api
|
51
|
+
role 'prod-api-redis', 'stag-api-redis'
|
52
|
+
role 'prod-api-app', 'stag-api-app' do
|
53
|
+
run_list ['base','api_app']
|
54
|
+
set 'application', 'api'
|
55
|
+
set 'deploy_code', true
|
56
|
+
set 'repository', 'git@github.com:br/api.git'
|
57
|
+
end
|
58
|
+
role 'prod-api-resque', 'stag-api-resque' do
|
59
|
+
inherits 'prod-api-app'
|
60
|
+
set 'workers', 8
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
<pre>
|
65
|
+
$ rna build
|
66
|
+
</pre>
|
67
|
+
|
68
|
+
If you're using the starter config/rna.rb, this should build:
|
69
|
+
|
70
|
+
* nodejson/base.json
|
71
|
+
* nodejson/prod-api-app.json
|
72
|
+
* nodejson/prod-api-redis.json
|
73
|
+
* nodejson/prod-api-resque.json
|
74
|
+
* nodejson/stag-api-app.json
|
75
|
+
* nodejson/stag-api-redis.json
|
76
|
+
* nodejson/stag-api-resque.json
|
77
|
+
|
78
|
+
<pre>
|
79
|
+
$ rna build -o s3 # saves s3 based on config/s3.yml settings
|
80
|
+
</pre>
|
81
|
+
|
82
|
+
The config/s3.yml should look like this:
|
83
|
+
|
84
|
+
```yaml
|
85
|
+
access_key_id: hocuspocus
|
86
|
+
secret_access_key: opensesame
|
87
|
+
bucket: my-bucket
|
88
|
+
folder: chef/nodejson
|
89
|
+
```
|
data/Rakefile
ADDED
data/bin/rna
ADDED
data/lib/files/rna.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# This is starter example rna template.
|
2
|
+
# This is meant be be modified to your needs.
|
3
|
+
###################################
|
4
|
+
# Settings
|
5
|
+
default_inherits 'base'
|
6
|
+
global_attributes(:except => ['base']) do
|
7
|
+
set 'framework_env', 'production'
|
8
|
+
end
|
9
|
+
|
10
|
+
###################################
|
11
|
+
# Post processing rules that run at the end
|
12
|
+
rule do
|
13
|
+
set 'framework_env', 'production' if name =~ /^prod/
|
14
|
+
set 'framework_env', 'staging' if name =~ /^stag/
|
15
|
+
end
|
16
|
+
|
17
|
+
###################################
|
18
|
+
# Roles
|
19
|
+
# base
|
20
|
+
role 'base' do
|
21
|
+
run_list ['base']
|
22
|
+
end
|
23
|
+
# api
|
24
|
+
role 'prod-api-redis', 'stag-api-redis'
|
25
|
+
role 'prod-api-app', 'stag-api-app' do
|
26
|
+
run_list ['base','api_app']
|
27
|
+
set 'application', 'api'
|
28
|
+
set 'deploy_code', true
|
29
|
+
set 'repository', 'git@github.com:br/api.git'
|
30
|
+
end
|
31
|
+
role 'prod-api-resque', 'stag-api-resque' do
|
32
|
+
inherits 'prod-api-app'
|
33
|
+
set 'workers', 8
|
34
|
+
end
|
data/lib/files/s3.yml
ADDED
data/lib/rna/cli.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rna
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "init", "Setup rna project"
|
5
|
+
long_desc "Sets up config/rna.rb"
|
6
|
+
def init
|
7
|
+
Rna::Tasks.init
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "build", "Builds node.json files"
|
11
|
+
long_desc <<EOL
|
12
|
+
Examples:
|
13
|
+
|
14
|
+
1. rna build
|
15
|
+
|
16
|
+
Builds the node.json files based on config/rna.rb and writes them to the nodejson folder on the filesystem.
|
17
|
+
|
18
|
+
2. rna --output s3 build
|
19
|
+
|
20
|
+
Builds the node.json files based on config/rna.rb and writes them to s3 based on the s3 settings in config/s3.yml.
|
21
|
+
EOL
|
22
|
+
method_option :output, :aliases => '-o', :desc => "specify where to output the generated files to", :default => 'filesystem'
|
23
|
+
method_option :public_read, :aliases => '-p', :desc => "make s3 files readable by public, default private", :default => false, :type => :boolean
|
24
|
+
def build
|
25
|
+
Rna::Tasks.build(options.dup)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/lib/rna/dsl.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
module Rna
|
2
|
+
class DSL
|
3
|
+
@@default_inherits = nil
|
4
|
+
attr_reader :attributes, :rules, :nodejsons
|
5
|
+
def initialize(config_path='config/rna.rb')
|
6
|
+
@path = config_path
|
7
|
+
@scope = nil
|
8
|
+
@rules = []
|
9
|
+
@roles = []
|
10
|
+
@attributes = {}
|
11
|
+
@nodejsons = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def evaluate
|
15
|
+
instance_eval(File.read(@path), @path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def build
|
19
|
+
# process roles
|
20
|
+
@roles.each do |role|
|
21
|
+
@nodejsons[role] = process_role(role)
|
22
|
+
end
|
23
|
+
@nodejsons
|
24
|
+
end
|
25
|
+
|
26
|
+
# builds node.json
|
27
|
+
# 1. global attributes
|
28
|
+
# 2. parent inherited attributes all the way up the inheritance chain
|
29
|
+
# each descendent role overrides it's parent role
|
30
|
+
# 3. final attributes from the desired role is built last
|
31
|
+
def process_role(role, exclude_global=nil)
|
32
|
+
# only compute exclude_global on on top level call and continue passing down recursive stack call
|
33
|
+
if exclude_global.nil?
|
34
|
+
exclude_global = @attributes['global']['except'].include?(role)
|
35
|
+
end
|
36
|
+
|
37
|
+
inherits = @attributes[role]['inherits']
|
38
|
+
if inherits
|
39
|
+
nodejson = process_role(inherits, exclude_global)
|
40
|
+
else
|
41
|
+
if exclude_global
|
42
|
+
nodejson = {}
|
43
|
+
else
|
44
|
+
attributes = @attributes['global']['attributes'] || {}
|
45
|
+
nodejson = attributes.clone
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# apply each rule to each role's attributes before we do the merge
|
50
|
+
@rules.each do |block|
|
51
|
+
set_scope(role)
|
52
|
+
self.instance_eval(&block)
|
53
|
+
end
|
54
|
+
|
55
|
+
attributes = @attributes[role]['attributes'] || {}
|
56
|
+
nodejson.merge!(attributes)
|
57
|
+
nodejson
|
58
|
+
end
|
59
|
+
|
60
|
+
def output(options={})
|
61
|
+
jsons = {}
|
62
|
+
nodejsons.each do |role,data|
|
63
|
+
jsons[role] = JSON.pretty_generate(data)
|
64
|
+
end
|
65
|
+
|
66
|
+
outputer = options[:output] || 'filesystem'
|
67
|
+
outputer_class = Rna.const_get(outputer.capitalize)
|
68
|
+
outputer_class.new(options).run(jsons)
|
69
|
+
end
|
70
|
+
|
71
|
+
# must be called before every instance_eval of the dsl to set the @scope
|
72
|
+
def set_scope(scope,type=Hash)
|
73
|
+
@scope = scope
|
74
|
+
@attributes[@scope] ||= type.new
|
75
|
+
end
|
76
|
+
|
77
|
+
def global_attributes(options={},&block)
|
78
|
+
set_scope('global')
|
79
|
+
@attributes['global']['except'] = [options[:except]].flatten
|
80
|
+
self.instance_eval(&block)
|
81
|
+
end
|
82
|
+
def default_inherits(role)
|
83
|
+
@@default_inherits = role
|
84
|
+
end
|
85
|
+
# rules are stored in a different place than attributes
|
86
|
+
def rule(name=nil,&block)
|
87
|
+
@rules << block
|
88
|
+
end
|
89
|
+
def role(*names,&block)
|
90
|
+
names.each do |name|
|
91
|
+
evaluate_role(name,&block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
def evaluate_role(name,&block)
|
95
|
+
@roles << name
|
96
|
+
set_scope(name)
|
97
|
+
instance_eval(&default_block)
|
98
|
+
instance_eval(&block) if block_given?
|
99
|
+
end
|
100
|
+
|
101
|
+
def default_block
|
102
|
+
Proc.new do
|
103
|
+
@attributes[@scope]['name'] = @scope
|
104
|
+
set 'role', name
|
105
|
+
inherits @@default_inherits
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# methods in blocks, right now I'm mixing all the methods from role, rule, global_attributes together, because there's not a lot and its simple this way
|
110
|
+
# methods rely on @scope being already via set_scope method
|
111
|
+
def name
|
112
|
+
@attributes[@scope]['name']
|
113
|
+
end
|
114
|
+
def set(key, value)
|
115
|
+
# puts "%%% @scope #{@scope.inspect}"
|
116
|
+
# pp @attributes
|
117
|
+
@attributes[@scope]['attributes'] ||= {}
|
118
|
+
@attributes[@scope]['attributes'][key] = value
|
119
|
+
end
|
120
|
+
def inherits(role)
|
121
|
+
role = nil if role == @scope # can't inherit itself
|
122
|
+
@attributes[@scope]['inherits'] = role
|
123
|
+
end
|
124
|
+
def run_list(list)
|
125
|
+
list = list.collect {|i| "role[#{i}]"}
|
126
|
+
set('run_list', list)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Rna
|
2
|
+
class Outputer
|
3
|
+
attr_reader :options
|
4
|
+
def initialize(options={})
|
5
|
+
@options = options
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Filesystem < Outputer
|
10
|
+
def run(jsons)
|
11
|
+
# options[:output_path] only used for specs
|
12
|
+
output_path = options[:output_path] || "nodejson"
|
13
|
+
FileUtils.mkdir(output_path) unless File.exist?(output_path)
|
14
|
+
jsons.each do |role,json|
|
15
|
+
File.open("#{output_path}/#{role}.json", 'w') {|f| f.write(json) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class S3 < Outputer
|
21
|
+
attr_reader :config, :s3
|
22
|
+
def run(jsons)
|
23
|
+
acl_options = @options[:public_read] ? {:acl => :public_read} : {}
|
24
|
+
# options[:config] only used for specs
|
25
|
+
s3_config_path = options[:s3_config_path] || 'config/s3.yml'
|
26
|
+
@config ||= YAML.load(File.read(s3_config_path))
|
27
|
+
AWS.config(@config)
|
28
|
+
@s3 = AWS::S3.new
|
29
|
+
bucket = @s3.buckets[@config['bucket']]
|
30
|
+
jsons.each do |role,json|
|
31
|
+
bucket.objects.create("#{@config['folder']}/#{role}.json", json, s3_options)
|
32
|
+
end
|
33
|
+
self # return outputer object for specs
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Stdout < Outputer
|
38
|
+
def run(jsons)
|
39
|
+
jsons.each do |role,json|
|
40
|
+
puts "-" * 60
|
41
|
+
puts "#{role}:"
|
42
|
+
puts json
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/rna/tasks.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rna
|
2
|
+
class Tasks
|
3
|
+
def self.init(project_root=".",options={})
|
4
|
+
puts "Settin up rna project" unless options[:quiet]
|
5
|
+
FileUtils.mkdir("#{project_root}/config") unless File.exist?("#{project_root}/config")
|
6
|
+
%w/rna.rb s3.yml/.each do |name|
|
7
|
+
source = File.expand_path("../../files/#{name}", __FILE__)
|
8
|
+
dest = "#{project_root}/config/#{File.basename(source)}"
|
9
|
+
if File.exist?(dest)
|
10
|
+
puts "already exists: #{dest}" unless options[:quiet]
|
11
|
+
else
|
12
|
+
puts "creating: #{dest}" unless options[:quiet]
|
13
|
+
FileUtils.cp(source, dest)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def self.build(options)
|
18
|
+
new(options).build
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(options={})
|
22
|
+
@options = options
|
23
|
+
@dsl = DSL.new
|
24
|
+
end
|
25
|
+
def build
|
26
|
+
@dsl.evaluate
|
27
|
+
@dsl.build
|
28
|
+
@dsl.output(@options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/rna/version.rb
ADDED
data/lib/rna.rb
ADDED
data/rna.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rna/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Tung Nguyen"]
|
6
|
+
gem.email = ["tongueroo@gmail.com"]
|
7
|
+
gem.description = %q{Rna DSL generates chef solo node.json files.}
|
8
|
+
gem.summary = %q{Rna DSL generates chef solo node.json files.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "rna"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Rna::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "json"
|
19
|
+
gem.add_dependency "thor"
|
20
|
+
gem.add_dependency "aws-sdk"
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rspec'
|
23
|
+
gem.add_development_dependency 'guard'
|
24
|
+
gem.add_development_dependency 'guard-rspec'
|
25
|
+
gem.add_development_dependency 'guard-bundler'
|
26
|
+
gem.add_development_dependency 'rb-fsevent'
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'rna'
|
2
|
+
require 'rspec'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
describe Rna do
|
6
|
+
before(:each) do
|
7
|
+
@project_root = File.expand_path("../../project", __FILE__)
|
8
|
+
@project2_root = File.expand_path("../../project2", __FILE__)
|
9
|
+
@dsl = Rna::DSL.new("#{@project_root}/config/rna.rb")
|
10
|
+
@dsl.evaluate
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
FileUtils.rm_rf("#{@project_root}/nodejson")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "evaluate global attributes data to be used later to merge the nodejson structures together" do
|
18
|
+
attributes = @dsl.attributes
|
19
|
+
attributes.should be_a(Hash)
|
20
|
+
# pp attributes
|
21
|
+
attributes['global']['attributes']['application'].should be_nil
|
22
|
+
attributes['global']['attributes']['deploy_code'].should be_false
|
23
|
+
attributes['global']['attributes']['framework_env'].should == 'production'
|
24
|
+
attributes['global']['attributes']['repository'].should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it "evaluate base attributes data that does not include the global attributes" do
|
28
|
+
attributes = @dsl.attributes
|
29
|
+
attributes.should be_a(Hash)
|
30
|
+
attributes['base']['attributes'].keys.should_not include('application')
|
31
|
+
attributes['base']['attributes']['run_list'].should == ["role[base]"]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "evaluate base attributes data should not inherit itself" do
|
35
|
+
attributes = @dsl.attributes
|
36
|
+
attributes.should be_a(Hash)
|
37
|
+
attributes['base']['inherits'].should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "roles without blocks should run the default block" do
|
41
|
+
attributes = @dsl.attributes
|
42
|
+
# running the default block will set inherits attribute
|
43
|
+
attributes['prod-api-redis']['inherits'].should == 'base'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "roles with blocks should run the default block and then their own block" do
|
47
|
+
attributes = @dsl.attributes
|
48
|
+
# hard to read test, but after the default block runs, the passed in role block rusn and overrides the default_blocks inherits attribuute
|
49
|
+
attributes['prod-api-resque']['inherits'].should == 'prod-api-app'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "roles with blocks should override the global attributes" do
|
53
|
+
attributes = @dsl.attributes
|
54
|
+
attributes['prod-masta-android']['attributes']['application'].should == 'masta'
|
55
|
+
attributes['prod-masta-android']['attributes']['deploy_code'].should be_true
|
56
|
+
attributes['prod-masta-android']['attributes']['repository'].should == 'git@github.com:arockwell/masta_blasta.git'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "base node.json should not include global attributes" do
|
60
|
+
@dsl.build
|
61
|
+
@dsl.nodejsons['base']['run_list'].should == ["role[base]"]
|
62
|
+
@dsl.nodejsons['base']['role'].should == 'base'
|
63
|
+
@dsl.nodejsons['base'].keys.should_not include('application')
|
64
|
+
@dsl.nodejsons['base'].keys.should_not include('repository')
|
65
|
+
end
|
66
|
+
|
67
|
+
it "prod-api-redis node.json should include base plus global attributes" do
|
68
|
+
@dsl.build
|
69
|
+
@dsl.nodejsons['prod-api-redis']['run_list'].should == ["role[base]"]
|
70
|
+
@dsl.nodejsons['prod-api-redis']['deploy_code'].should be_false
|
71
|
+
end
|
72
|
+
|
73
|
+
it "prod-api-app node.json should include global attributes plus additional attributes" do
|
74
|
+
@dsl.build
|
75
|
+
@dsl.nodejsons['prod-api-app']['run_list'].should == ["role[base]", "role[api_app]"]
|
76
|
+
@dsl.nodejsons['prod-api-app']['deploy_code'].should be_true
|
77
|
+
@dsl.nodejsons['prod-api-app'].keys.should include('scout')
|
78
|
+
end
|
79
|
+
|
80
|
+
it "prod-api-resque node.json inherit attributes from prod-api-app" do
|
81
|
+
@dsl.build
|
82
|
+
@dsl.nodejsons['prod-api-resque']['run_list'].should == @dsl.nodejsons['prod-api-app']['run_list']
|
83
|
+
@dsl.nodejsons['prod-api-resque']['deploy_code'].should == @dsl.nodejsons['prod-api-app']['deploy_code']
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should respect rules and change framework_env" do
|
87
|
+
@dsl.build
|
88
|
+
@dsl.nodejsons['stag-masta-android']['application'].should == 'masta'
|
89
|
+
@dsl.nodejsons['stag-masta-android']['framework_env'].should == 'staging'
|
90
|
+
@dsl.nodejsons['prod-masta-android']['framework_env'].should == 'production'
|
91
|
+
@dsl.nodejsons
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should write json files to outputs folder" do
|
95
|
+
@dsl.build
|
96
|
+
@dsl.output(:output => 'filesystem', :output_path => "#{@project_root}/nodejson")
|
97
|
+
Dir.glob("#{@project_root}/nodejson/*").size.should > 0
|
98
|
+
end
|
99
|
+
|
100
|
+
# complete end to end tests
|
101
|
+
it "base.json should contain correct attributes" do
|
102
|
+
@dsl.build
|
103
|
+
@dsl.output(:output => 'filesystem', :output_path => "#{@project_root}/nodejson")
|
104
|
+
base = JSON.load(IO.read("#{@project_root}/nodejson/base.json"))
|
105
|
+
base['role'].should == 'base'
|
106
|
+
base['run_list'].should == ["role[base]"]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "base.json should not contain global attributes" do
|
110
|
+
@dsl.build
|
111
|
+
@dsl.output(:output => 'filesystem', :output_path => "#{@project_root}/nodejson")
|
112
|
+
base = JSON.load(IO.read("#{@project_root}/nodejson/base.json"))
|
113
|
+
base['framework_env'].should be_nil
|
114
|
+
base['deploy_code'].should be_nil
|
115
|
+
end
|
116
|
+
|
117
|
+
it "prod-api-redis.json should contain base and global attributes" do
|
118
|
+
@dsl.build
|
119
|
+
@dsl.output(:output => 'filesystem', :output_path => "#{@project_root}/nodejson")
|
120
|
+
json = JSON.load(IO.read("#{@project_root}/nodejson/prod-api-redis.json"))
|
121
|
+
json['role'].should == 'prod-api-redis'
|
122
|
+
json['run_list'].should == ["role[base]"]
|
123
|
+
json['framework_env'].should == 'production'
|
124
|
+
json['deploy_code'].should == false
|
125
|
+
end
|
126
|
+
|
127
|
+
it "stag-api-redis.json should contain base and global attributes and apply rules" do
|
128
|
+
@dsl.build
|
129
|
+
@dsl.output(:output => 'filesystem', :output_path => "#{@project_root}/nodejson")
|
130
|
+
json = JSON.load(IO.read("#{@project_root}/nodejson/stag-api-redis.json"))
|
131
|
+
json['role'].should == 'stag-api-redis'
|
132
|
+
json['run_list'].should == ["role[base]"]
|
133
|
+
json['deploy_code'].should == false
|
134
|
+
json['framework_env'].should == 'staging' # this is tests the rule
|
135
|
+
end
|
136
|
+
|
137
|
+
it "prod-api-app.json should contain base and global attributes" do
|
138
|
+
@dsl.build
|
139
|
+
@dsl.output(:output => 'filesystem', :output_path => "#{@project_root}/nodejson")
|
140
|
+
json = JSON.load(IO.read("#{@project_root}/nodejson/prod-api-app.json"))
|
141
|
+
json['role'].should == 'prod-api-app'
|
142
|
+
json['run_list'].should == ["role[base]","role[api_app]"]
|
143
|
+
json['deploy_code'].should == true
|
144
|
+
json['framework_env'].should == 'production'
|
145
|
+
json['scout'].should be_a(Hash)
|
146
|
+
end
|
147
|
+
|
148
|
+
# only run when S3=1, will need to setup spec/project/config/s3.yml
|
149
|
+
it "should upload to s3" do
|
150
|
+
@dsl.build
|
151
|
+
outputer = @dsl.output(:output => 's3', :s3_config_path => "#{@project_root}/config/s3.yml")
|
152
|
+
|
153
|
+
config = outputer.config
|
154
|
+
s3 = outputer.s3
|
155
|
+
bucket = s3.buckets[config['bucket']]
|
156
|
+
raw = bucket.objects["#{config['folder']}/prod-api-app.json"].read
|
157
|
+
|
158
|
+
json = JSON.load(raw)
|
159
|
+
json['role'].should == 'prod-api-app'
|
160
|
+
json['run_list'].should == ["role[base]","role[api_app]"]
|
161
|
+
json['deploy_code'].should == true
|
162
|
+
json['framework_env'].should == 'production'
|
163
|
+
json['scout'].should be_a(Hash)
|
164
|
+
# clean up
|
165
|
+
tree = bucket.as_tree(:prefix => config['folder'])
|
166
|
+
tree.children.select(&:leaf?).each do |leaf|
|
167
|
+
leaf.object.delete
|
168
|
+
end
|
169
|
+
end if ENV['S3'] == '1'
|
170
|
+
|
171
|
+
it "task init should set up project" do
|
172
|
+
File.exist?("#{@project2_root}/config/s3.yml").should be_false
|
173
|
+
File.exist?("#{@project2_root}/config/rna.rb").should be_false
|
174
|
+
Rna::Tasks.init(@project2_root, :quiet => true)
|
175
|
+
File.exist?("#{@project2_root}/config/s3.yml").should be_true
|
176
|
+
File.exist?("#{@project2_root}/config/rna.rb").should be_true
|
177
|
+
FileUtils.rm_rf("#{@project2_root}/config")
|
178
|
+
end
|
179
|
+
|
180
|
+
it "task build should generate node.json files" do
|
181
|
+
Rna::Tasks.build(
|
182
|
+
:config_path => "#{@project_root}/config/rna.rb",
|
183
|
+
:output_path => "#{@project_root}/nodejson"
|
184
|
+
)
|
185
|
+
json = JSON.load(IO.read("#{@project_root}/nodejson/prod-api-app.json"))
|
186
|
+
json['role'].should == 'prod-api-app'
|
187
|
+
json['run_list'].should == ["role[base]","role[api_app]"]
|
188
|
+
json['deploy_code'].should == true
|
189
|
+
json['framework_env'].should == 'production'
|
190
|
+
json['scout'].should be_a(Hash)
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
###################################
|
2
|
+
# Settings
|
3
|
+
default_inherits 'base'
|
4
|
+
global_attributes(:except => 'base') do
|
5
|
+
set 'application', nil
|
6
|
+
set 'deploy_code', false
|
7
|
+
set 'framework_env', 'production'
|
8
|
+
set 'repository', nil
|
9
|
+
end
|
10
|
+
|
11
|
+
###################################
|
12
|
+
# Post processing rules that run at the end
|
13
|
+
rule do
|
14
|
+
set 'framework_env', 'production' if name =~ /^prod/
|
15
|
+
set 'framework_env', 'staging' if name =~ /^stag/
|
16
|
+
end
|
17
|
+
|
18
|
+
###################################
|
19
|
+
# Roles
|
20
|
+
# base
|
21
|
+
role 'base' do
|
22
|
+
run_list ['base']
|
23
|
+
end
|
24
|
+
# api
|
25
|
+
role 'prod-api-redis', 'stag-api-redis'
|
26
|
+
role 'prod-api-resque', 'stag-api-resque' do
|
27
|
+
inherits 'prod-api-app'
|
28
|
+
end
|
29
|
+
role 'prod-api-app', 'stag-api-app' do
|
30
|
+
run_list ['base','api_app']
|
31
|
+
set 'application', 'api'
|
32
|
+
set 'deploy_code', true
|
33
|
+
set 'repository', 'git@github.com:br/api.git'
|
34
|
+
set 'scout', {
|
35
|
+
'key' => 'abc',
|
36
|
+
'gems' => {
|
37
|
+
'redis' => nil
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
# masta
|
42
|
+
role 'prod-masta-redis', 'stag-masta-redis'
|
43
|
+
role 'prod-masta-android', 'stag-masta-android' do
|
44
|
+
set 'application', 'masta'
|
45
|
+
set 'deploy_code', true
|
46
|
+
set 'repository', 'git@github.com:arockwell/masta_blasta.git'
|
47
|
+
end
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rna
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tung Nguyen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: thor
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: aws-sdk
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: guard-rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: guard-bundler
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rb-fsevent
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: Rna DSL generates chef solo node.json files.
|
143
|
+
email:
|
144
|
+
- tongueroo@gmail.com
|
145
|
+
executables:
|
146
|
+
- rna
|
147
|
+
extensions: []
|
148
|
+
extra_rdoc_files: []
|
149
|
+
files:
|
150
|
+
- .gitignore
|
151
|
+
- .rspec
|
152
|
+
- .travis.yml
|
153
|
+
- CHANGELOG
|
154
|
+
- Gemfile
|
155
|
+
- Guardfile
|
156
|
+
- LICENSE
|
157
|
+
- README.md
|
158
|
+
- Rakefile
|
159
|
+
- bin/rna
|
160
|
+
- lib/files/rna.rb
|
161
|
+
- lib/files/s3.yml
|
162
|
+
- lib/rna.rb
|
163
|
+
- lib/rna/cli.rb
|
164
|
+
- lib/rna/dsl.rb
|
165
|
+
- lib/rna/outputers.rb
|
166
|
+
- lib/rna/tasks.rb
|
167
|
+
- lib/rna/version.rb
|
168
|
+
- rna.gemspec
|
169
|
+
- spec/lib/rna_spec.rb
|
170
|
+
- spec/project/config/rna.rb
|
171
|
+
- spec/project/config/s3.example.yml
|
172
|
+
- spec/project2/.gitkeep
|
173
|
+
homepage: ''
|
174
|
+
licenses: []
|
175
|
+
post_install_message:
|
176
|
+
rdoc_options: []
|
177
|
+
require_paths:
|
178
|
+
- lib
|
179
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
180
|
+
none: false
|
181
|
+
requirements:
|
182
|
+
- - ! '>='
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
187
|
+
requirements:
|
188
|
+
- - ! '>='
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
191
|
+
requirements: []
|
192
|
+
rubyforge_project:
|
193
|
+
rubygems_version: 1.8.24
|
194
|
+
signing_key:
|
195
|
+
specification_version: 3
|
196
|
+
summary: Rna DSL generates chef solo node.json files.
|
197
|
+
test_files:
|
198
|
+
- spec/lib/rna_spec.rb
|
199
|
+
- spec/project/config/rna.rb
|
200
|
+
- spec/project/config/s3.example.yml
|
201
|
+
- spec/project2/.gitkeep
|