dployr 0.0.1
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.
- 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
|