kondate 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38160e964f7ea99cbd0bc387cc9309c27c3a442e
4
- data.tar.gz: 1ea9ea5b11e0e70d80f1894c682c0cd156dcbcba
3
+ metadata.gz: e27ee012dcd65e359a123934dacca0609013fbad
4
+ data.tar.gz: 9f8ccc65a962d95e60836256546f015d9d78e809
5
5
  SHA512:
6
- metadata.gz: 3c1385a0f8868aea7ce912b88cb36576d23fefc3e8a7f6347fa66f0653a495b35f30d456b72a3b810ab397b3f6a19d57bf91084f674e593783bba89b0190015d
7
- data.tar.gz: d7eadd64d34d4842561a4e5659a07048da0574740688a6d939d2d8efc6fa7e0066b9a70fd9b1558b568ca901245e17d7d99c1ef1dde2ccbae3de99a9a8c34794
6
+ metadata.gz: c6cbc270b4b074b9738edece8ccaa6f759729533ae83b108e5ac5922c735a80fe5723ed1628426e09a92da3e2300f97fa4d6cbf231aff09532f5b5c0c3f072c1
7
+ data.tar.gz: 560015c973fcf3d17dbced58d7e37a825b4b5e412aa0af325d4c322c96307c03ba28e66858b9eea8b6c0b4fbe81183ae59ab909233b3f588f036739287d67f1d
@@ -1,3 +1,9 @@
1
+ # 0.4.0 (2016-12-01)
2
+
3
+ Enhancements:
4
+
5
+ * Add a feature to explore possible role files
6
+
1
7
  # 0.3.3 (2016-11-20)
2
8
 
3
9
  Changes:
data/README.md CHANGED
@@ -268,6 +268,28 @@ Configuring following lines for vagrant is also recommended:
268
268
 
269
269
  See [templates/spec/spec_helper.rb](./lib/kondate/templates/spec/spec_helper.rb) for an example.
270
270
 
271
+ ### Exploring role files
272
+
273
+ Available version: >= v0.4.0
274
+
275
+ Assume `role` is delimited with `-` (you can configure the delimiter) such as `myapp-web-staging`, this feature explores role files in order of:
276
+
277
+ 1. myapp-web-staging.yml
278
+ 1. myapp-web-base.yml
279
+ 1. myapp-web.yml
280
+ 1. myapp-base.yml
281
+ 1. myapp.yml
282
+ 1. base.yml
283
+
284
+ This makes it possible to share a property file, for example, `myapp-web.yml` among `myapp-web-staging` and `myapp-web-production` roles.
285
+
286
+ To enable this feature, you need to configure .kondate.conf as:
287
+
288
+ ```
289
+ explore_role_files: true # default is false
290
+ role_delimiter: "-" # default is -
291
+ ```
292
+
271
293
  ## Host Plugin
272
294
 
273
295
  The default reads `hosts.yml` to resolve roles of a host, but
@@ -312,12 +334,12 @@ module Kondate
312
334
  raise ConfigError.new('file: path is not configured') unless config.path
313
335
  @path = config.path
314
336
 
315
- @roles_of = YAML.load_file(@path)
316
- @hosts_of = {}
317
- @roles_of.each do |host, roles|
337
+ @roles_of_host = YAML.load_file(@path)
338
+ @hosts_of_role = {}
339
+ @roles_of_host.each do |host, roles|
318
340
  roles.each do |role|
319
- @hosts_of[role] ||= []
320
- @hosts_of[role] << host
341
+ @hosts_of_role[role] ||= []
342
+ @hosts_of_role[role] << host
321
343
  end
322
344
  end
323
345
  end
@@ -331,7 +353,7 @@ module Kondate
331
353
  # @param [String] host hostname
332
354
  # @return [Array] array of roles
333
355
  def get_roles(host)
334
- @roles_of[host]
356
+ @roles_of_host[host]
335
357
  end
336
358
 
337
359
  # @param [String] role role
@@ -339,7 +361,7 @@ module Kondate
339
361
  #
340
362
  # Available from kondate >= 0.3.0
341
363
  def get_hosts(role)
342
- @hosts_of[role]
364
+ @hosts_of_role[role]
343
365
  end
344
366
 
345
367
  # Optional
@@ -4,6 +4,8 @@ end
4
4
 
5
5
  require "kondate/version"
6
6
  require "kondate/config"
7
+ require "kondate/role_file"
8
+ require "kondate/property_file"
7
9
  require "kondate/property_builder"
8
10
  require "kondate/hash_ext"
9
11
  require "kondate/string_util"
@@ -56,14 +56,7 @@ module Kondate
56
56
  option :profile, :type => :string, :default => nil, :desc => "[EXPERIMENTAL] Save profiling data", :banner => "PATH"
57
57
  option :recipe_graph, :type => :string, :default => nil, :desc => "[EXPERIMENTAL] Write recipe dependency graph in DOT", :banner => "PATH"
58
58
  def itamae(host)
59
- property_files = build_property_files(host)
60
- begin
61
- if proceed?(property_files)
62
- exit(-1) unless do_itamae(host, property_files)
63
- end
64
- ensure
65
- clean_property_files(property_files)
66
- end
59
+ with_host(host) {|property_files| do_itamae(host, property_files) }
67
60
  end
68
61
 
69
62
  desc "itamae-role <role>", "Execute itamae for multiple hosts in the role"
@@ -76,25 +69,7 @@ module Kondate
76
69
  option :recipe_graph, :type => :string, :default => nil, :desc => "[EXPERIMENTAL] Write recipe dependency graph in DOT", :banner => "PATH"
77
70
  option :parallel, :aliases => ["-p"], :type => :numeric, :default => Facter['processorcount'].value.to_i
78
71
  def itamae_role(role)
79
- $stdout.puts "Number of parallels is #{@options[:parallel]}"
80
- hosts = Kondate::Config.host_plugin.get_hosts(role)
81
- if hosts.nil? or hosts.empty?
82
- $stderr.puts 'No host'
83
- exit(1)
84
- end
85
- $stdout.puts "Target hosts are [#{hosts.join(", ")}]"
86
-
87
- property_files_of, summarized_property_files, hosts_of = build_property_files_of(hosts)
88
- begin
89
- if proceed?(summarized_property_files, hosts_of)
90
- successes = Parallel.map(hosts, in_processes: @options[:parallel]) do |host|
91
- do_itamae(host, property_files_of[host])
92
- end
93
- exit(-1) unless successes.all?
94
- end
95
- ensure
96
- property_files_of.values.each {|property_files| clean_property_files(property_files) }
97
- end
72
+ with_role(role) {|host, property_files| do_itamae(host, property_files) }
98
73
  end
99
74
 
100
75
  desc "serverspec <host>", "Execute serverspec"
@@ -104,14 +79,7 @@ module Kondate
104
79
  option :confirm, :type => :boolean, :default => true
105
80
  option :vagrant, :type => :boolean, :default => false
106
81
  def serverspec(host)
107
- property_files = build_property_files(host)
108
- begin
109
- if proceed?(property_files)
110
- exit(-1) unless do_serverspec(host, property_files)
111
- end
112
- ensure
113
- clean_property_files(property_files)
114
- end
82
+ with_host(host) {|property_files| do_serverspec(host, property_files) }
115
83
  end
116
84
 
117
85
  desc "serverspec-role <role>", "Execute serverspec for multiple hosts in the role"
@@ -122,6 +90,24 @@ module Kondate
122
90
  option :vagrant, :type => :boolean, :default => false
123
91
  option :parallel, :aliases => ["-p"], :type => :numeric, :default => Facter['processorcount'].value.to_i
124
92
  def serverspec_role(role)
93
+ with_role(role) {|host, property_files| do_serverspec(host, property_files) }
94
+ end
95
+
96
+ private
97
+
98
+ def with_host(host, &block)
99
+ property_files = build_property_files(host)
100
+ begin
101
+ print_property_files(property_files)
102
+ if proceed?(property_files)
103
+ exit(-1) unless yield(property_files)
104
+ end
105
+ ensure
106
+ clean_property_files(property_files)
107
+ end
108
+ end
109
+
110
+ def with_role(role, &block)
125
111
  $stdout.puts "Number of parallels is #{@options[:parallel]}"
126
112
  hosts = Kondate::Config.host_plugin.get_hosts(role)
127
113
  if hosts.nil? or hosts.empty?
@@ -130,21 +116,20 @@ module Kondate
130
116
  end
131
117
  $stdout.puts "Target hosts are [#{hosts.join(", ")}]"
132
118
 
133
- property_files_of, summarized_property_files, hosts_of = build_property_files_of(hosts)
119
+ property_files_of_host, summarized_property_files, hosts_of_role = build_property_files_of_host(hosts)
134
120
  begin
135
- if proceed?(summarized_property_files, hosts_of)
121
+ print_property_files(summarized_property_files, hosts_of_role)
122
+ if proceed?(summarized_property_files)
136
123
  successes = Parallel.map(hosts, in_processes: @options[:parallel]) do |host|
137
- do_serverspec(host, property_files_of[host])
124
+ yield(host, property_files_of_host[host])
138
125
  end
139
126
  exit(-1) unless successes.all?
140
127
  end
141
128
  ensure
142
- property_files_of.values.each {|files| clean_property_files(files) }
129
+ property_files_of_host.values.each {|property_files| clean_property_files(property_files) }
143
130
  end
144
131
  end
145
132
 
146
- private
147
-
148
133
  def do_itamae(host, property_files)
149
134
  env = {}
150
135
  env['RUBYOPT'] = "-I #{Config.plugin_dir} -r bundler/setup -r ext/itamae/kondate"
@@ -153,7 +138,7 @@ module Kondate
153
138
  command = "bundle exec itamae ssh"
154
139
  command << " -h #{host}"
155
140
 
156
- properties = YAML.load_file(property_file)
141
+ properties = property_file.load
157
142
 
158
143
  if @options[:vagrant]
159
144
  command << " --vagrant"
@@ -164,7 +149,7 @@ module Kondate
164
149
  command << " -p #{properties['ssh_port'] || config[:port] || 22}"
165
150
  end
166
151
 
167
- command << " -y #{property_file}"
152
+ command << " -y #{property_file.path}"
168
153
  command << " -l=debug" if @options[:debug]
169
154
  command << " --dry-run" if @options[:dry_run]
170
155
  command << " --profile=#{@options[:profile]}" if @options[:profile]
@@ -182,14 +167,14 @@ module Kondate
182
167
  env['RUBYOPT'] = "-I #{Config.plugin_dir} -r bundler/setup -r ext/serverspec/kondate"
183
168
  property_files.each do |role, property_file|
184
169
  next if property_file.nil?
185
- recipes = YAML.load_file(property_file)['attributes'].keys.map {|recipe|
186
- File.join(Config.middleware_recipes_serverspec_dir, recipe)
170
+ spec_files = property_file.load['attributes'].keys.map {|recipe|
171
+ File.join(Config.middleware_recipes_serverspec_dir, "#{recipe}_spec.rb")
187
172
  }.compact
188
- recipes << File.join(Config.roles_recipes_serverspec_dir, role)
189
- spec_files = recipes.map {|recipe| "#{recipe}_spec.rb"}.select! {|spec| File.exist?(spec) }
173
+ spec_files << RoleFile.explore(Config.roles_recipes_serverspec_dir, role, "_spec.rb")
174
+ spec_files.select! {|spec| File.exist?(spec) }
190
175
 
191
176
  env['TARGET_HOST'] = host
192
- env['TARGET_NODE_FILE'] = property_file
177
+ env['TARGET_NODE_FILE'] = property_file.path
193
178
  command = "bundle exec rspec #{spec_files.map{|f| f.shellescape }.join(' ')}"
194
179
  $stdout.puts "env #{env.map {|k, v| "#{k}=#{v.shellescape}" }.join(' ')} #{command}"
195
180
  return false unless system(env, command)
@@ -197,8 +182,7 @@ module Kondate
197
182
  true
198
183
  end
199
184
 
200
- def proceed?(property_files, hosts_of = {})
201
- print_property_files(property_files, hosts_of)
185
+ def proceed?(property_files)
202
186
  if property_files.values.compact.empty?
203
187
  $stderr.puts "Nothing to run"
204
188
  false
@@ -210,7 +194,7 @@ module Kondate
210
194
  end
211
195
  end
212
196
 
213
- def print_property_files(property_files, hosts_of = {})
197
+ def print_property_files(property_files, hosts_of_role = {})
214
198
  roles = property_files.keys
215
199
  if roles.nil? or roles.empty?
216
200
  $stderr.puts 'No role'
@@ -219,17 +203,18 @@ module Kondate
219
203
  $stdout.puts "Show property files for roles: [#{roles.join(", ")}]"
220
204
 
221
205
  property_files.each do |role, property_file|
222
- hosts = hosts_of[role]
206
+ hosts = hosts_of_role[role]
223
207
  if hosts.nil? # itamae
224
208
  $stdout.print "Show property file for role: #{role}"
225
209
  else # itamae_role
226
210
  $stdout.print "Show representative property file for role: #{role}"
227
- $stdout.print " [#{hosts.join(", ")}]"
211
+ $stdout.print " hosts: [#{hosts.join(", ")}]"
228
212
  end
213
+ $stdout.print ", sources: #{property_file.source_files}"
229
214
 
230
215
  if property_file
231
216
  $stdout.puts
232
- $stdout.puts mask_secrets(File.read(property_file))
217
+ $stdout.puts property_file.read
233
218
  else
234
219
  $stdout.puts " (no attribute, skipped)"
235
220
  end
@@ -249,8 +234,8 @@ module Kondate
249
234
 
250
235
  property_files = {}
251
236
  roles.each do |role|
252
- if path = builder.install(role, @options[:recipe])
253
- property_files[role] = path
237
+ if property_file = builder.install(role, @options[:recipe])
238
+ property_files[role] = property_file
254
239
  else
255
240
  property_files[role] = nil
256
241
  end
@@ -259,22 +244,17 @@ module Kondate
259
244
  property_files
260
245
  end
261
246
 
262
- def build_property_files_of(hosts)
247
+ def build_property_files_of_host(hosts)
263
248
  summarized_property_files = {}
264
- property_files_of = {}
265
- hosts_of = {}
249
+ property_files_of_host = {}
250
+ hosts_of_role = {}
266
251
  hosts.each do |host|
267
252
  property_files = build_property_files(host)
268
- property_files_of[host] = property_files
269
- property_files.each {|role, path| summarized_property_files[role] ||= path }
270
- property_files.each {|role, path| (hosts_of[role] ||= []) << host }
253
+ property_files_of_host[host] = property_files
254
+ property_files.each {|role, property_file| summarized_property_files[role] ||= property_file }
255
+ property_files.each {|role, property_file| (hosts_of_role[role] ||= []) << host }
271
256
  end
272
- [property_files_of, summarized_property_files, hosts_of]
273
- end
274
-
275
- def mask_secrets(str)
276
- str.gsub(/(.*key[^:]*): (.*)$/, '\1: *******').
277
- gsub(/(.*password[^:]*): (.*)$/, '\1: *******')
257
+ [property_files_of_host, summarized_property_files, hosts_of_role]
278
258
  end
279
259
  end
280
260
  end
@@ -88,6 +88,14 @@ module Kondate
88
88
  config[:secret_environments_properties_dir] || 'secrets/properties/environments'
89
89
  end
90
90
 
91
+ def explore_role_files?
92
+ !config[:explore_role_files].nil?
93
+ end
94
+
95
+ def role_delimiter
96
+ config[:role_delimiter] || '-'
97
+ end
98
+
91
99
  def plugin_dir
92
100
  File.expand_path(config[:plugin_dir] || 'lib')
93
101
  end
@@ -13,12 +13,12 @@ module Kondate
13
13
  raise ConfigError.new('file: path is not configured') unless config.path
14
14
  @path = config.path
15
15
 
16
- @roles_of = YAML.load_file(@path)
17
- @hosts_of = {}
18
- @roles_of.each do |host, roles|
16
+ @roles_of_host = YAML.load_file(@path)
17
+ @hosts_of_role = {}
18
+ @roles_of_host.each do |host, roles|
19
19
  roles.each do |role|
20
- @hosts_of[role] ||= []
21
- @hosts_of[role] << host
20
+ @hosts_of_role[role] ||= []
21
+ @hosts_of_role[role] << host
22
22
  end
23
23
  end
24
24
  end
@@ -32,7 +32,7 @@ module Kondate
32
32
  # @param [String] host hostname
33
33
  # @return [Array] array of roles
34
34
  def get_roles(host)
35
- @roles_of[host]
35
+ @roles_of_host[host]
36
36
  end
37
37
 
38
38
  # @param [String] role role
@@ -40,7 +40,7 @@ module Kondate
40
40
  #
41
41
  # Available from kondate >= 0.3.0
42
42
  def get_hosts(role)
43
- @hosts_of[role]
43
+ @hosts_of_role[role]
44
44
  end
45
45
  end
46
46
  end
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'tempfile'
3
+ require_relative 'property_file'
3
4
 
4
5
  module Kondate
5
6
  class PropertyBuilder
@@ -49,8 +50,9 @@ module Kondate
49
50
  if roles.empty? # maybe, development (vagrant) env
50
51
  @roles = filters # append specified roles
51
52
  @roles.each do |role|
52
- unless File.exist?(role_file(role))
53
- $stderr.puts "#{role_file(role)} does not exist, possibly typo?"
53
+ file = role_file(role)
54
+ unless File.exist?(file)
55
+ $stderr.puts "#{file} does not exist, possibly typo?"
54
56
  exit(1)
55
57
  end
56
58
  end
@@ -76,11 +78,11 @@ module Kondate
76
78
  end
77
79
 
78
80
  def role_file(role)
79
- File.join(Config.roles_properties_dir, "#{role}.yml")
81
+ RoleFile.explore(Config.roles_properties_dir, role, ".yml")
80
82
  end
81
83
 
82
84
  def secret_role_file(role)
83
- File.join(Config.secret_roles_properties_dir, "#{role}.yml")
85
+ RoleFile.explore(Config.secret_roles_properties_dir, role, ".yml")
84
86
  end
85
87
 
86
88
  def environment_file(environment)
@@ -105,25 +107,24 @@ module Kondate
105
107
  #
106
108
  # This file is automatically created and removed
107
109
  def install(role, filter_recipes = nil)
108
- node_property = get_content(node_file)
109
- secret_node_property = get_content(secret_node_file)
110
- role_property = get_content(role_file(role))
111
- secret_role_property = get_content(secret_role_file(role))
112
- environment_property = get_content(environment_file(environment))
113
- secret_environment_property = get_content(secret_environment_file(environment))
110
+ files = [
111
+ environment_file(environment),
112
+ secret_environment_file(environment),
113
+ role_file(role),
114
+ secret_role_file(role),
115
+ node_file,
116
+ secret_node_file,
117
+ ].compact.select {|f| File.readable?(f) }
114
118
 
115
119
  property = HashExt.new.deep_merge!({
116
120
  'environment' => environment,
117
121
  'role' => role,
118
122
  'roles' => roles,
119
123
  'hostinfo' => hostinfo,
120
- }).
121
- deep_merge!(environment_property).
122
- deep_merge!(secret_environment_property).
123
- deep_merge!(role_property).
124
- deep_merge!(secret_role_property).
125
- deep_merge!(node_property).
126
- deep_merge!(secret_node_property).to_h
124
+ })
125
+ files.each do |file|
126
+ property.deep_merge!(get_content(file))
127
+ end
127
128
  property['attributes'] ||= {}
128
129
 
129
130
  # filter out the recipe
@@ -137,9 +138,9 @@ module Kondate
137
138
  nil
138
139
  else
139
140
  fp = Tempfile.create("kondate_")
140
- YAML.dump(property, fp)
141
+ YAML.dump(property.to_h, fp)
141
142
  fp.close
142
- fp.path
143
+ PropertyFile.new(fp.path, files)
143
144
  end
144
145
  end
145
146
  end
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+
3
+ module Kondate
4
+ class PropertyFile
5
+ attr_reader :path, :source_files
6
+
7
+ def initialize(path, source_files)
8
+ @path = path
9
+ @source_files = source_files
10
+ end
11
+
12
+ def read
13
+ mask_secrets(File.read(path))
14
+ end
15
+
16
+ def load
17
+ YAML.load_file(path)
18
+ end
19
+
20
+ private
21
+
22
+ def mask_secrets(str)
23
+ str.gsub(/(.*key[^:]*): (.*)$/, '\1: *******').
24
+ gsub(/(.*password[^:]*): (.*)$/, '\1: *******')
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ require_relative 'config'
2
+
3
+ module Kondate
4
+ class RoleFile
5
+ attr_reader :dir, :role, :ext
6
+
7
+ def self.explore(dir, role, ext = nil)
8
+ self.new(dir, role, ext).explore
9
+ end
10
+
11
+ def initialize(dir, role, ext = nil)
12
+ @dir = dir
13
+ @role = role
14
+ @ext = ext
15
+ end
16
+
17
+ # Returns readable role file exploring possible role files. For example,
18
+ # if `role` is `myapp-web-staging`, this method explores files as
19
+ #
20
+ # 1. myapp-web-staging.yml
21
+ # 1. myapp-web-base.yml
22
+ # 1. myapp-web.yml
23
+ # 1. myapp-base.yml
24
+ # 1. myapp.yml
25
+ # 1. base.yml
26
+ #
27
+ # @return [String] detected file path or last candidate path
28
+ def explore
29
+ paths = if Config.explore_role_files?
30
+ possible_paths
31
+ else
32
+ [get_path]
33
+ end
34
+ paths.find {|path| File.readable?(path) } || paths.last
35
+ end
36
+
37
+ private
38
+
39
+ def get_path(role = nil)
40
+ "#{File.join(dir, role || @role)}#{ext}"
41
+ end
42
+
43
+ def possible_paths
44
+ possible_roles.map {|role| get_path(role) }
45
+ end
46
+
47
+ def possible_roles
48
+ parts = role.split('-')
49
+ roles = []
50
+ roles << 'base'
51
+ roles << parts.shift
52
+ parts.each do |part|
53
+ last = roles.last
54
+ roles << "#{last}-base"
55
+ roles << "#{last}-#{part}"
56
+ end
57
+ roles
58
+ end
59
+ end
60
+ end
@@ -9,6 +9,8 @@ environments_properties_dir: properties/environments
9
9
  secret_nodes_properties_dir: secrets/properties/nodes
10
10
  secret_roles_properties_dir: secrets/properties/roles
11
11
  secret_environments_properties_dir: secrets/properties/environments
12
+ explore_role_files: true
13
+ role_delimiter: "-"
12
14
  plugin_dir: lib
13
15
  host_plugin:
14
16
  type: file
@@ -5,6 +5,7 @@ recipes = node['attributes'].keys
5
5
  recipes.each do |recipe|
6
6
  include_recipe(File.join(Kondate::Config.middleware_recipes_dir, recipe, "default.rb"))
7
7
  end
8
- if File.exist?(File.join(Kondate::Config.roles_recipes_dir, node[:role], "default.rb"))
9
- include_recipe(File.join(Kondate::Config.roles_recipes_dir, node[:role], "default.rb"))
8
+ role_recipe = Kondate::RoleFile.explore(Kondate::Config.roles_recipes_dir, node[:role], "#{File::SEPARATOR}default.rb")
9
+ if File.exist?(role_recipe)
10
+ include_recipe(role_recipe)
10
11
  end
@@ -1,3 +1,3 @@
1
1
  module Kondate
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kondate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sonots
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-19 00:00:00.000000000 Z
11
+ date: 2016-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: itamae
@@ -177,6 +177,8 @@ files:
177
177
  - lib/kondate/host_plugin/base.rb
178
178
  - lib/kondate/host_plugin/file.rb
179
179
  - lib/kondate/property_builder.rb
180
+ - lib/kondate/property_file.rb
181
+ - lib/kondate/role_file.rb
180
182
  - lib/kondate/string_util.rb
181
183
  - lib/kondate/templates/.kondate.conf
182
184
  - lib/kondate/templates/bootstrap.rb