dployr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +9 -0
- data/.gitignore +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +294 -0
- data/Rakefile +11 -0
- data/bin/dployr +4 -0
- data/dployr.gemspec +33 -0
- data/lib/dployr/cli/cli.rb +77 -0
- data/lib/dployr/cli/commands/config.rb +66 -0
- data/lib/dployr/cli/commands.rb +1 -0
- data/lib/dployr/compute/client.rb +28 -0
- data/lib/dployr/config/constants.rb +10 -0
- data/lib/dployr/config/create.rb +54 -0
- data/lib/dployr/config/file_utils.rb +36 -0
- data/lib/dployr/config/instance.rb +99 -0
- data/lib/dployr/configuration.rb +163 -0
- data/lib/dployr/init.rb +72 -0
- data/lib/dployr/logger.rb +11 -0
- data/lib/dployr/utils.rb +127 -0
- data/lib/dployr/version.rb +3 -0
- data/lib/dployr.rb +8 -0
- data/spec/config_file_utils_spec.rb +61 -0
- data/spec/config_instance_spec.rb +60 -0
- data/spec/configuration_spec.rb +516 -0
- data/spec/fixtures/Dployrfile +59 -0
- data/spec/fixtures/Dployrfile.yml +91 -0
- data/spec/fog_spec_.rb +44 -0
- data/spec/init_spec.rb +27 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/utils_spec.rb +317 -0
- metadata +146 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'dployr/utils'
|
2
|
+
|
3
|
+
module Dployr
|
4
|
+
module Config
|
5
|
+
class Instance
|
6
|
+
|
7
|
+
include Dployr::Utils
|
8
|
+
|
9
|
+
attr_reader :attributes, :providers, :authentication, :scripts, :parents
|
10
|
+
attr_accessor :name
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@name = 'unnamed'
|
14
|
+
@attributes = {}
|
15
|
+
@authentication = {}
|
16
|
+
@scripts = []
|
17
|
+
@providers = {}
|
18
|
+
@parents = []
|
19
|
+
yield self if block_given?
|
20
|
+
end
|
21
|
+
|
22
|
+
def configure(config)
|
23
|
+
if config.is_a? Hash
|
24
|
+
set_attributes get_by_key config, :attributes if has config, :attributes
|
25
|
+
set_providers get_by_key config, :providers if has config, :providers
|
26
|
+
set_auth get_by_key config, :authentication if has config, :authentication
|
27
|
+
set_scripts get_by_key config, :scripts if has config, :scripts
|
28
|
+
set_parents get_by_key config, :extends if has config, :extends
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_values
|
33
|
+
deep_copy({
|
34
|
+
attributes: @attributes,
|
35
|
+
authentication: @authentication,
|
36
|
+
scripts: @scripts,
|
37
|
+
providers: @providers,
|
38
|
+
parents: @parents
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_attribute(key, value)
|
43
|
+
@attributes[key] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_attribute(key)
|
47
|
+
@attributes[key]
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_attribute(key)
|
51
|
+
@attributes.remove key
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_script(script)
|
55
|
+
@scripts << script if script.is_a? Hash
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_auth(key, value)
|
59
|
+
@authentication[key] = value if key
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_provider(name, provider)
|
63
|
+
@providers[name] = provider if provider.is_a? Hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_provider(index)
|
67
|
+
@providers[index]
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_provider(provider)
|
71
|
+
@providers.delete provider
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def set_auth(auth)
|
77
|
+
@authentication = auth if auth.is_a? Hash
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_providers(providers)
|
81
|
+
@providers = providers if providers.is_a? Hash
|
82
|
+
end
|
83
|
+
|
84
|
+
def set_scripts(scripts)
|
85
|
+
@scripts = scripts if scripts.is_a? Array
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_attributes(attrs)
|
89
|
+
@attributes = attrs if attrs.is_a? Hash
|
90
|
+
end
|
91
|
+
|
92
|
+
def set_parents(parents)
|
93
|
+
parents = [ parents ] if parents.is_a? String
|
94
|
+
@parents.concat parents if parents.is_a? Array
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'dployr/utils'
|
2
|
+
|
3
|
+
module Dployr
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
include Dployr::Utils
|
7
|
+
|
8
|
+
attr_reader :default, :instances
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@default = nil
|
12
|
+
@config = nil
|
13
|
+
@instances = []
|
14
|
+
@merged = false
|
15
|
+
yield self if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
def exists?
|
19
|
+
(!@default.nil? or @instances.length >= 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_default(config)
|
23
|
+
@default = create_instance('default', config) if config.is_a? Hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_instance(name, config)
|
27
|
+
@instances << create_instance(name, config) if config.is_a? Hash
|
28
|
+
@instances.last
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_instance(name)
|
32
|
+
@instances.each { |i| return i if i.name.to_s == name.to_s }
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_config(name, attributes = {})
|
37
|
+
instance = get_instance name
|
38
|
+
raise ArgumentError.new "Instance '#{name.to_s}' do not exists" if instance.nil?
|
39
|
+
replace_variables merge_config(instance), replace_variables(attributes)
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_config_all(attributes = {})
|
43
|
+
config = []
|
44
|
+
@instances.each do |i|
|
45
|
+
config << get_config(i.name, attributes)
|
46
|
+
end
|
47
|
+
puts config
|
48
|
+
config
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_provider(name, provider, attributes = {})
|
52
|
+
config = get_config name, attributes
|
53
|
+
if config.is_a? Hash
|
54
|
+
config = config[get_real_key(config, :providers)]
|
55
|
+
if config.is_a? Hash
|
56
|
+
return config[get_real_key(config, provider)]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_region(name, provider, region, attributes = {})
|
62
|
+
provider = get_provider name, provider, attributes
|
63
|
+
if provider.is_a? Hash
|
64
|
+
regions = get_by_key provider, :regions
|
65
|
+
return get_by_key regions, region
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def each(type = :providers)
|
70
|
+
config = get_config_all
|
71
|
+
config.each { |i| yield i if block_given? }
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def create_instance(name = 'unnamed', config)
|
77
|
+
Dployr::Config::Instance.new do |i|
|
78
|
+
i.name = name
|
79
|
+
i.configure config
|
80
|
+
end if config.is_a? Hash
|
81
|
+
end
|
82
|
+
|
83
|
+
def replace_variables(config, attributes = {})
|
84
|
+
if config.is_a? Hash
|
85
|
+
attrs = get_all_attributes config
|
86
|
+
attrs.merge! attributes if attributes.is_a? Hash
|
87
|
+
traverse_map config do |str, key|
|
88
|
+
replace_env_vars template(str, attrs)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
config
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_all_attributes(config)
|
95
|
+
attrs = {}
|
96
|
+
config.each do |key, value|
|
97
|
+
if key.to_sym == :attributes
|
98
|
+
attrs.merge! value if value.is_a? Hash
|
99
|
+
elsif value.is_a? Hash
|
100
|
+
attrs.merge! get_all_attributes value
|
101
|
+
end
|
102
|
+
end if config.is_a? Hash
|
103
|
+
attrs
|
104
|
+
end
|
105
|
+
|
106
|
+
def merge_config(instance)
|
107
|
+
merge_providers merge_parents merge_defaults instance.get_values
|
108
|
+
end
|
109
|
+
|
110
|
+
def merge_defaults(config)
|
111
|
+
config = deep_merge @default.get_values, config if @default
|
112
|
+
config
|
113
|
+
end
|
114
|
+
|
115
|
+
def merge_providers(config)
|
116
|
+
key = get_real_key config, :providers
|
117
|
+
if config[key].is_a? Hash
|
118
|
+
config[key].each do |name, provider|
|
119
|
+
provider = replace_keywords 'provider', name, inherit_config(provider, config)
|
120
|
+
regions = get_by_key provider, get_real_key(provider, :regions)
|
121
|
+
regions.each do |name, region|
|
122
|
+
regions[name] = replace_keywords 'region', name, inherit_config(region, provider)
|
123
|
+
end if regions
|
124
|
+
end
|
125
|
+
end
|
126
|
+
config
|
127
|
+
end
|
128
|
+
|
129
|
+
def replace_keywords(keyword, value, hash)
|
130
|
+
traverse_map hash do |str|
|
131
|
+
str.gsub "${#{keyword.to_s}}", value.to_s
|
132
|
+
end if hash.is_a? Hash
|
133
|
+
end
|
134
|
+
|
135
|
+
def inherit_config(child, parent)
|
136
|
+
keys = [ :attributes, :scripts, :authentication ]
|
137
|
+
keys.each do |type|
|
138
|
+
current = deep_copy get_by_key(parent, type)
|
139
|
+
source = get_by_key child, type
|
140
|
+
if type == :scripts
|
141
|
+
current = [] unless current.is_a? Array
|
142
|
+
current.concat source if source.is_a? Array
|
143
|
+
current = current.compact.uniq
|
144
|
+
else
|
145
|
+
current = {} unless current.is_a? Hash
|
146
|
+
current = deep_merge current, source
|
147
|
+
end
|
148
|
+
child[type] = current if current.length
|
149
|
+
end
|
150
|
+
child
|
151
|
+
end
|
152
|
+
|
153
|
+
def merge_parents(child)
|
154
|
+
parents = get_by_key child, :parents
|
155
|
+
parents = [ parents ] if parents.is_a? String
|
156
|
+
parents.each do |parent|
|
157
|
+
parent = get_instance parent
|
158
|
+
child = deep_merge parent.get_values, child unless parent.nil?
|
159
|
+
end if parents.is_a? Array
|
160
|
+
child
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/lib/dployr/init.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'dployr/configuration'
|
2
|
+
require 'dployr/config/file_utils'
|
3
|
+
|
4
|
+
module Dployr
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def configure(attributes = {})
|
9
|
+
dployr = Init::instance
|
10
|
+
yield dployr if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def config
|
14
|
+
dployr = Init::instance
|
15
|
+
dployr.config if dployr
|
16
|
+
end
|
17
|
+
|
18
|
+
def load(file_path)
|
19
|
+
if Dployr::Config::FileUtils.yaml_file? file_path
|
20
|
+
Dployr::Config::FileUtils.read_yaml file_path
|
21
|
+
else
|
22
|
+
load file_path
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Init
|
27
|
+
|
28
|
+
include Dployr::Config::FileUtils
|
29
|
+
|
30
|
+
attr_reader :file_path, :config
|
31
|
+
|
32
|
+
@@instance = nil
|
33
|
+
|
34
|
+
def initialize(attributes = {})
|
35
|
+
@@instance = self
|
36
|
+
@attributes = attributes
|
37
|
+
@config = Dployr::Configuration.new
|
38
|
+
@file_path = discover
|
39
|
+
load_file @file_path
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.instance
|
43
|
+
@@instance
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def load_file(file_path)
|
49
|
+
if file_path.is_a? String
|
50
|
+
if yaml_file? file_path
|
51
|
+
load_yaml file_path
|
52
|
+
else
|
53
|
+
load file_path
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def load_yaml(file_path)
|
59
|
+
config = read_yaml file_path
|
60
|
+
if config.is_a? Hash
|
61
|
+
config.each do |name, config|
|
62
|
+
if name == 'default'
|
63
|
+
@config.set_default config
|
64
|
+
else
|
65
|
+
@config.add_instance name, config
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/lib/dployr/utils.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
module Dployr
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
MERGE_OPTIONS = { merge_hash_arrays: false, knockout_prefix: false }
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def has(hash, key)
|
9
|
+
(hash.is_a? Hash and
|
10
|
+
(hash.key? key or hash.key? key.to_sym or hash.key? key.to_s))
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_by_key(hash, key)
|
14
|
+
if hash.is_a? Hash
|
15
|
+
hash[key] or hash[key.to_sym] or hash[key.to_s]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_real_key(hash, key)
|
20
|
+
if hash.is_a? Hash
|
21
|
+
if hash.key? key
|
22
|
+
key
|
23
|
+
elsif hash.key? key.to_sym
|
24
|
+
key.to_sym
|
25
|
+
elsif hash.key? key.to_s
|
26
|
+
key.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def merge(target, *origins)
|
32
|
+
origins.each { |h| target = target.merge h }
|
33
|
+
target
|
34
|
+
end
|
35
|
+
|
36
|
+
def deep_merge(target = {}, *origins)
|
37
|
+
origins.each do |h|
|
38
|
+
target.deep_merge! h, MERGE_OPTIONS if h.is_a? Hash
|
39
|
+
end
|
40
|
+
target
|
41
|
+
end
|
42
|
+
|
43
|
+
def deep_copy(o)
|
44
|
+
Marshal.load Marshal.dump o
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_matrix(str)
|
48
|
+
hash = {}
|
49
|
+
str.split(';').each do |val|
|
50
|
+
val = val.split '='
|
51
|
+
hash[val.first.strip] = val.last.strip
|
52
|
+
end if str.is_a? String
|
53
|
+
hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_flags(str)
|
57
|
+
hash = {}
|
58
|
+
str.gsub(/\s+/, ' ').strip.split(' ').each_slice(2) do |val|
|
59
|
+
key = val.first
|
60
|
+
if val.first.is_a? String
|
61
|
+
key = key.gsub(/^\-+/, '').strip
|
62
|
+
hash[key] = (val.last or '').strip
|
63
|
+
end
|
64
|
+
end if str.is_a? String
|
65
|
+
hash
|
66
|
+
end
|
67
|
+
|
68
|
+
def replace_vars(str)
|
69
|
+
str.gsub(/\%\{(\w+)\}/) { yield $1 }
|
70
|
+
end
|
71
|
+
|
72
|
+
def template(str, data)
|
73
|
+
raise ArgumentError.new 'Data must be a hash' unless data.is_a? Hash
|
74
|
+
replace_vars str do |match|
|
75
|
+
key = get_real_key data, match
|
76
|
+
if key
|
77
|
+
data[key]
|
78
|
+
else
|
79
|
+
raise ArgumentError.new "Missing template variable: #{match}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def replace_env_vars(str)
|
85
|
+
str.gsub(/\$\{(\w+)\}/) do
|
86
|
+
if ENV.key? $1
|
87
|
+
ENV[$1]
|
88
|
+
else
|
89
|
+
''
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def replace_placeholders(str, data)
|
95
|
+
str % data if data.is_a? Hash or data.is_a? Array
|
96
|
+
end
|
97
|
+
|
98
|
+
def traverse_map(hash, &block)
|
99
|
+
traverse_mapper hash, nil, &block
|
100
|
+
end
|
101
|
+
|
102
|
+
def traverse_mapper(hash, key, &block)
|
103
|
+
case hash
|
104
|
+
when String
|
105
|
+
hash = yield hash, key
|
106
|
+
when Array
|
107
|
+
hash.map! { |item| traverse_mapper item, nil, &block }
|
108
|
+
when Hash
|
109
|
+
buf = {}
|
110
|
+
hash.each do |k, v|
|
111
|
+
if k.is_a? String
|
112
|
+
new_key = yield k, k
|
113
|
+
if new_key != k
|
114
|
+
hash.delete k
|
115
|
+
buf[new_key] = traverse_mapper v, new_key, &block
|
116
|
+
next
|
117
|
+
end
|
118
|
+
end
|
119
|
+
hash[k] = traverse_mapper v, k, &block
|
120
|
+
end
|
121
|
+
hash.merge! buf
|
122
|
+
end
|
123
|
+
hash
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
data/lib/dployr.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dployr::Config::FileUtils do
|
4
|
+
|
5
|
+
describe :read_yaml do
|
6
|
+
it "should expose the read method" do
|
7
|
+
Dployr::Config::FileUtils.respond_to?(:read_yaml).should be_true
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a valid number of items" do
|
11
|
+
Dployr::Config::FileUtils.read_yaml(File.dirname(__FILE__) + '/fixtures/Dployrfile.yml').should have(2).item
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe :discover do
|
16
|
+
let(:pwd) { Dir.pwd }
|
17
|
+
let(:filename) { Dployr::Config::FileUtils::FILENAME }
|
18
|
+
let(:tmpdir) { File.join File.dirname(__FILE__), 'fixtures', '.tmp' }
|
19
|
+
let(:fixtures) { File.join File.dirname(__FILE__), 'fixtures' }
|
20
|
+
|
21
|
+
describe "current directory" do
|
22
|
+
context "when cannot discover" do
|
23
|
+
it { Dployr::Config::FileUtils.discover.should eql nil }
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when discover" do
|
27
|
+
let(:expected) { File.join fixtures, filename }
|
28
|
+
|
29
|
+
before do
|
30
|
+
Dir.chdir fixtures
|
31
|
+
end
|
32
|
+
|
33
|
+
it { Dployr::Config::FileUtils.discover.should_not be_empty }
|
34
|
+
|
35
|
+
it { Dployr::Config::FileUtils.discover.should eql expected }
|
36
|
+
|
37
|
+
after do
|
38
|
+
Dir.chdir pwd
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "higher directories" do
|
44
|
+
context "when discover" do
|
45
|
+
let(:expected) { File.join fixtures, filename }
|
46
|
+
|
47
|
+
before do
|
48
|
+
FileUtils.mkdir_p File.join tmpdir, 'sample'
|
49
|
+
Dir.chdir File.join tmpdir, 'sample'
|
50
|
+
end
|
51
|
+
|
52
|
+
after do
|
53
|
+
Dir.chdir pwd
|
54
|
+
FileUtils.rm_rf tmpdir
|
55
|
+
end
|
56
|
+
|
57
|
+
it { Dployr::Config::FileUtils.discover.should eql expected }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dployr::Config::Instance do
|
4
|
+
describe "Instance" do
|
5
|
+
describe "instance configuration" do
|
6
|
+
let(:instance) {
|
7
|
+
Dployr::Config::Instance.new
|
8
|
+
}
|
9
|
+
|
10
|
+
describe "setting attributes" do
|
11
|
+
context "when created" do
|
12
|
+
subject { instance.attributes }
|
13
|
+
it { should be_a Hash }
|
14
|
+
it { should have(0).items }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when add attributes" do
|
18
|
+
before do
|
19
|
+
instance.set_attribute :key, "value"
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { instance.attributes }
|
23
|
+
it { should have_key(:key) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "setting providers" do
|
28
|
+
context "when created" do
|
29
|
+
subject { instance.providers }
|
30
|
+
it { should be_a Hash }
|
31
|
+
it { should have(0).items }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "setting providers" do
|
35
|
+
let(:provider) do
|
36
|
+
{
|
37
|
+
attributes: {
|
38
|
+
instance_type: "m1.small"
|
39
|
+
},
|
40
|
+
scripts: [],
|
41
|
+
regions: {}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when add a provider" do
|
46
|
+
before do
|
47
|
+
instance.add_provider :aws, provider
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { instance.get_provider :aws }
|
51
|
+
it { should be_a Hash }
|
52
|
+
it { should have_key(:attributes) }
|
53
|
+
it { should have_key(:scripts) }
|
54
|
+
it { should have_key(:regions) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|