leap_cli 1.2.5

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.
Files changed (72) hide show
  1. data/bin/leap +81 -0
  2. data/lib/core_ext/boolean.rb +14 -0
  3. data/lib/core_ext/hash.rb +35 -0
  4. data/lib/core_ext/json.rb +42 -0
  5. data/lib/core_ext/nil.rb +5 -0
  6. data/lib/core_ext/string.rb +14 -0
  7. data/lib/leap/platform.rb +52 -0
  8. data/lib/leap_cli/commands/ca.rb +430 -0
  9. data/lib/leap_cli/commands/clean.rb +16 -0
  10. data/lib/leap_cli/commands/compile.rb +134 -0
  11. data/lib/leap_cli/commands/deploy.rb +172 -0
  12. data/lib/leap_cli/commands/facts.rb +93 -0
  13. data/lib/leap_cli/commands/inspect.rb +140 -0
  14. data/lib/leap_cli/commands/list.rb +122 -0
  15. data/lib/leap_cli/commands/new.rb +126 -0
  16. data/lib/leap_cli/commands/node.rb +272 -0
  17. data/lib/leap_cli/commands/pre.rb +99 -0
  18. data/lib/leap_cli/commands/shell.rb +67 -0
  19. data/lib/leap_cli/commands/test.rb +55 -0
  20. data/lib/leap_cli/commands/user.rb +140 -0
  21. data/lib/leap_cli/commands/util.rb +50 -0
  22. data/lib/leap_cli/commands/vagrant.rb +201 -0
  23. data/lib/leap_cli/config/macros.rb +369 -0
  24. data/lib/leap_cli/config/manager.rb +369 -0
  25. data/lib/leap_cli/config/node.rb +37 -0
  26. data/lib/leap_cli/config/object.rb +336 -0
  27. data/lib/leap_cli/config/object_list.rb +174 -0
  28. data/lib/leap_cli/config/secrets.rb +43 -0
  29. data/lib/leap_cli/config/tag.rb +18 -0
  30. data/lib/leap_cli/constants.rb +7 -0
  31. data/lib/leap_cli/leapfile.rb +97 -0
  32. data/lib/leap_cli/load_paths.rb +15 -0
  33. data/lib/leap_cli/log.rb +166 -0
  34. data/lib/leap_cli/logger.rb +216 -0
  35. data/lib/leap_cli/markdown_document_listener.rb +134 -0
  36. data/lib/leap_cli/path.rb +84 -0
  37. data/lib/leap_cli/remote/leap_plugin.rb +204 -0
  38. data/lib/leap_cli/remote/puppet_plugin.rb +66 -0
  39. data/lib/leap_cli/remote/rsync_plugin.rb +35 -0
  40. data/lib/leap_cli/remote/tasks.rb +36 -0
  41. data/lib/leap_cli/requirements.rb +19 -0
  42. data/lib/leap_cli/ssh_key.rb +130 -0
  43. data/lib/leap_cli/util/remote_command.rb +110 -0
  44. data/lib/leap_cli/util/secret.rb +54 -0
  45. data/lib/leap_cli/util/x509.rb +32 -0
  46. data/lib/leap_cli/util.rb +431 -0
  47. data/lib/leap_cli/version.rb +9 -0
  48. data/lib/leap_cli.rb +46 -0
  49. data/lib/lib_ext/capistrano_connections.rb +16 -0
  50. data/lib/lib_ext/gli.rb +52 -0
  51. data/lib/lib_ext/markdown_document_listener.rb +122 -0
  52. data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +200 -0
  53. data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +77 -0
  54. data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +97 -0
  55. data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +266 -0
  56. data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +148 -0
  57. data/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb +144 -0
  58. data/vendor/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb +65 -0
  59. data/vendor/certificate_authority/lib/certificate_authority/revocable.rb +14 -0
  60. data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +10 -0
  61. data/vendor/certificate_authority/lib/certificate_authority/signing_entity.rb +16 -0
  62. data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +56 -0
  63. data/vendor/certificate_authority/lib/certificate_authority.rb +21 -0
  64. data/vendor/rsync_command/lib/rsync_command/ssh_options.rb +159 -0
  65. data/vendor/rsync_command/lib/rsync_command/thread_pool.rb +36 -0
  66. data/vendor/rsync_command/lib/rsync_command/version.rb +3 -0
  67. data/vendor/rsync_command/lib/rsync_command.rb +96 -0
  68. data/vendor/rsync_command/test/rsync_test.rb +74 -0
  69. data/vendor/rsync_command/test/ssh_options_test.rb +61 -0
  70. data/vendor/vagrant_ssh_keys/vagrant.key +27 -0
  71. data/vendor/vagrant_ssh_keys/vagrant.pub +1 -0
  72. metadata +345 -0
@@ -0,0 +1,336 @@
1
+ require 'erb'
2
+ require 'json/pure' # pure ruby implementation is required for our sorted trick to work.
3
+
4
+ if $ruby_version < [1,9]
5
+ $KCODE = 'UTF8'
6
+ end
7
+ require 'ya2yaml' # pure ruby yaml
8
+
9
+ require 'leap_cli/config/macros'
10
+
11
+ module LeapCli
12
+ module Config
13
+ #
14
+ # This class represents the configuration for a single node, service, or tag.
15
+ # Also, all the nested hashes are also of this type.
16
+ #
17
+ # It is called 'object' because it corresponds to an Object in JSON.
18
+ #
19
+ class Object < Hash
20
+
21
+ include Config::Macros
22
+
23
+ attr_reader :node
24
+ attr_reader :manager
25
+ alias :global :manager
26
+
27
+ def initialize(manager=nil, node=nil)
28
+ # keep a global pointer around to the config manager. used a lot in the eval strings and templates
29
+ # (which are evaluated in the context of Config::Object)
30
+ @manager = manager
31
+
32
+ # an object that is a node as @node equal to self, otherwise all the child objects point back to the top level node.
33
+ @node = node || self
34
+ end
35
+
36
+ #
37
+ # We use pure ruby yaml exporter ya2yaml instead of SYCK or PSYCH because it
38
+ # allows us greater compatibility regardless of installed ruby version and
39
+ # greater control over how the yaml is exported (sorted keys, in particular).
40
+ #
41
+ def dump
42
+ evaluate
43
+ ya2yaml(:syck_compatible => true)
44
+ end
45
+
46
+ def dump_json
47
+ evaluate
48
+ JSON.sorted_generate(self)
49
+ end
50
+
51
+ def evaluate
52
+ evaluate_everything
53
+ late_evaluate_everything
54
+ end
55
+
56
+ ##
57
+ ## FETCHING VALUES
58
+ ##
59
+
60
+ def [](key)
61
+ get(key)
62
+ end
63
+
64
+ #
65
+ # make hash addressable like an object (e.g. obj['name'] available as obj.name)
66
+ #
67
+ def method_missing(method, *args, &block)
68
+ get!(method)
69
+ end
70
+
71
+ def get(key)
72
+ begin
73
+ get!(key)
74
+ rescue NoMethodError
75
+ nil
76
+ end
77
+ end
78
+
79
+ # override behavior of #default() from Hash
80
+ def default
81
+ get!('default')
82
+ end
83
+
84
+ #
85
+ # Like a normal Hash#[], except:
86
+ #
87
+ # (1) lazily eval dynamic values when we encounter them. (i.e. strings that start with "= ")
88
+ #
89
+ # (2) support for nested references in a single string (e.g. ['a.b'] is the same as ['a']['b'])
90
+ # the dot path is always absolute, starting at the top-most object.
91
+ #
92
+ def get!(key)
93
+ key = key.to_s
94
+ if key =~ /\./
95
+ # for keys with with '.' in them, we start from the root object (@node).
96
+ keys = key.split('.')
97
+ value = @node.get!(keys.first)
98
+ if value.is_a? Config::Object
99
+ value.get!(keys[1..-1].join('.'))
100
+ else
101
+ value
102
+ end
103
+ elsif self.has_key?(key)
104
+ fetch_value(key)
105
+ else
106
+ raise NoMethodError.new(key, "No method '#{key}' for #{self.class}")
107
+ end
108
+ end
109
+
110
+ ##
111
+ ## COPYING
112
+ ##
113
+
114
+ #
115
+ # A deep (recursive) merge with another Config::Object.
116
+ #
117
+ # If prefer_self is set to true, the value from self will be picked when there is a conflict
118
+ # that cannot be merged.
119
+ #
120
+ # Merging rules:
121
+ #
122
+ # - If a value is a hash, we recursively merge it.
123
+ # - If the value is simple, like a string, the new one overwrites the value.
124
+ # - If the value is an array:
125
+ # - If both old and new values are arrays, the new one replaces the old.
126
+ # - If one of the values is simple but the other is an array, the simple is added to the array.
127
+ #
128
+ def deep_merge!(object, prefer_self=false)
129
+ object.each do |key,new_value|
130
+ old_value = self.fetch key, nil
131
+
132
+ # clean up boolean
133
+ new_value = true if new_value == "true"
134
+ new_value = false if new_value == "false"
135
+ old_value = true if old_value == "true"
136
+ old_value = false if old_value == "false"
137
+
138
+ # merge hashes
139
+ if old_value.is_a?(Hash) || new_value.is_a?(Hash)
140
+ value = Config::Object.new(@manager, @node)
141
+ old_value.is_a?(Hash) ? value.deep_merge!(old_value) : (value[key] = old_value if !old_value.nil?)
142
+ new_value.is_a?(Hash) ? value.deep_merge!(new_value, prefer_self) : (value[key] = new_value if !new_value.nil?)
143
+
144
+ # merge nil
145
+ elsif new_value.nil?
146
+ value = old_value
147
+ elsif old_value.nil?
148
+ value = new_value
149
+
150
+ # merge arrays when one value is not an array
151
+ elsif old_value.is_a?(Array) && !new_value.is_a?(Array)
152
+ (value = (old_value.dup << new_value).compact.uniq).delete('REQUIRED')
153
+ elsif new_value.is_a?(Array) && !old_value.is_a?(Array)
154
+ (value = (new_value.dup << old_value).compact.uniq).delete('REQUIRED')
155
+
156
+ # catch errors
157
+ elsif type_mismatch?(old_value, new_value)
158
+ raise 'Type mismatch. Cannot merge %s (%s) with %s (%s). Key is "%s", name is "%s".' % [
159
+ old_value.inspect, old_value.class,
160
+ new_value.inspect, new_value.class,
161
+ key, self.class
162
+ ]
163
+
164
+ # merge strings, numbers, and sometimes arrays
165
+ else
166
+ if prefer_self
167
+ value = old_value
168
+ else
169
+ value = new_value
170
+ end
171
+ end
172
+
173
+ # save value
174
+ self[key] = value
175
+ end
176
+ self
177
+ end
178
+
179
+ #
180
+ # like a reverse deep merge
181
+ # (self takes precedence)
182
+ #
183
+ def inherit_from!(object)
184
+ self.deep_merge!(object, true)
185
+ end
186
+
187
+ #
188
+ # Make a copy of ourselves, except only including the specified keys.
189
+ #
190
+ # Also, the result is flattened to a single hash, so a key of 'a.b' becomes 'a_b'
191
+ #
192
+ def pick(*keys)
193
+ keys.map(&:to_s).inject(self.class.new(@manager)) do |hsh, key|
194
+ value = self.get(key)
195
+ if !value.nil?
196
+ hsh[key.gsub('.','_')] = value
197
+ end
198
+ hsh
199
+ end
200
+ end
201
+
202
+ protected
203
+
204
+ #
205
+ # walks the object tree, eval'ing all the attributes that are dynamic ruby (e.g. value starts with '= ')
206
+ #
207
+ def evaluate_everything
208
+ keys.each do |key|
209
+ obj = fetch_value(key)
210
+ if is_required_value_not_set?(obj)
211
+ Util::log 0, :warning, "required key \"#{key}\" is not set in node \"#{node.name}\"."
212
+ elsif obj.is_a? Config::Object
213
+ obj.evaluate_everything
214
+ end
215
+ end
216
+ end
217
+
218
+ #
219
+ # some keys need to be evaluated 'late', after all the other keys have been evaluated.
220
+ #
221
+ def late_evaluate_everything
222
+ if @late_eval_list
223
+ @late_eval_list.each do |key, value|
224
+ self[key] = evaluate_now(key, value)
225
+ if is_required_value_not_set?(self[key])
226
+ Util::log 0, :warning, "required key \"#{key}\" is not set in node \"#{node.name}\"."
227
+ end
228
+ end
229
+ end
230
+ values.each do |obj|
231
+ if obj.is_a? Config::Object
232
+ obj.late_evaluate_everything
233
+ end
234
+ end
235
+ end
236
+
237
+ private
238
+
239
+ #
240
+ # fetches the value for the key, evaluating the value as ruby if it begins with '='
241
+ #
242
+ def fetch_value(key)
243
+ value = fetch(key, nil)
244
+ if value.is_a?(String) && value =~ /^=/
245
+ if value =~ /^=> (.*)$/
246
+ value = evaluate_later(key, $1)
247
+ elsif value =~ /^= (.*)$/
248
+ value = evaluate_now(key, $1)
249
+ end
250
+ self[key] = value
251
+ end
252
+ return value
253
+ end
254
+
255
+ def evaluate_later(key, value)
256
+ @late_eval_list ||= []
257
+ @late_eval_list << [key, value]
258
+ '<evaluate later>'
259
+ end
260
+
261
+ def evaluate_now(key, value)
262
+ result = nil
263
+ if LeapCli.log_level >= 2
264
+ result = @node.instance_eval(value)
265
+ else
266
+ begin
267
+ result = @node.instance_eval(value)
268
+ rescue SystemStackError => exc
269
+ Util::log 0, :error, "while evaluating node '#{@node.name}'"
270
+ Util::log 0, "offending key: #{key}", :indent => 1
271
+ Util::log 0, "offending string: #{value}", :indent => 1
272
+ Util::log 0, "STACK OVERFLOW, BAILING OUT. There must be an eval loop of death (variables with circular dependencies).", :indent => 1
273
+ raise SystemExit.new(1)
274
+ rescue FileMissing => exc
275
+ Util::bail! do
276
+ if exc.options[:missing]
277
+ Util::log :missing, exc.options[:missing].gsub('$node', @node.name)
278
+ else
279
+ Util::log :error, "while evaluating node '#{@node.name}'"
280
+ Util::log "offending key: #{key}", :indent => 1
281
+ Util::log "offending string: #{value}", :indent => 1
282
+ Util::log "error message: no file '#{exc}'", :indent => 1
283
+ end
284
+ end
285
+ rescue AssertionFailed => exc
286
+ Util.bail! do
287
+ Util::log :failed, "assertion while evaluating node '#{@node.name}'"
288
+ Util::log 'assertion: %s' % exc.assertion, :indent => 1
289
+ Util::log "offending key: #{key}", :indent => 1
290
+ end
291
+ rescue SyntaxError, StandardError => exc
292
+ Util::bail! do
293
+ Util::log :error, "while evaluating node '#{@node.name}'"
294
+ Util::log "offending key: #{key}", :indent => 1
295
+ Util::log "offending string: #{value}", :indent => 1
296
+ Util::log "error message: #{exc.inspect}", :indent => 1
297
+ end
298
+ end
299
+ end
300
+ return result
301
+ end
302
+
303
+ #
304
+ # when merging, we raise an error if this method returns true for the two values.
305
+ #
306
+ def type_mismatch?(old_value, new_value)
307
+ if old_value.is_a?(Boolean) && new_value.is_a?(Boolean)
308
+ # note: FalseClass and TrueClass are different classes
309
+ # so we can't do old_value.class == new_value.class
310
+ return false
311
+ elsif old_value.is_a?(String) && old_value =~ /^=/
312
+ # pass through macros, since we don't know what the type will eventually be.
313
+ return false
314
+ elsif new_value.is_a?(String) && new_value =~ /^=/
315
+ return false
316
+ elsif old_value.class == new_value.class
317
+ return false
318
+ else
319
+ return true
320
+ end
321
+ end
322
+
323
+ #
324
+ # returns true if the value has not been changed and the default is "REQUIRED"
325
+ #
326
+ def is_required_value_not_set?(value)
327
+ if value.is_a? Array
328
+ value == ["REQUIRED"]
329
+ else
330
+ value == "REQUIRED"
331
+ end
332
+ end
333
+
334
+ end # class
335
+ end # module
336
+ end # module
@@ -0,0 +1,174 @@
1
+ module LeapCli
2
+ module Config
3
+ #
4
+ # A list of Config::Object instances (internally stored as a hash)
5
+ #
6
+ class ObjectList < Hash
7
+
8
+ def initialize(config=nil)
9
+ if config
10
+ self.add(config['name'], config)
11
+ end
12
+ end
13
+
14
+ #
15
+ # If the key is a string, the Config::Object it references is returned.
16
+ #
17
+ # If the key is a hash, we treat it as a condition and filter all the Config::Objects using the condition.
18
+ # A new ObjectList is returned.
19
+ #
20
+ # Examples:
21
+ #
22
+ # nodes['vpn1']
23
+ # node named 'vpn1'
24
+ #
25
+ # nodes[:public_dns => true]
26
+ # all nodes with public dns
27
+ #
28
+ # nodes[:services => 'openvpn', :services => 'tor']
29
+ # nodes with openvpn OR tor service
30
+ #
31
+ # nodes[:services => 'openvpn'][:tags => 'production']
32
+ # nodes with openvpn AND are production
33
+ #
34
+ def [](key)
35
+ if key.is_a? Hash
36
+ results = Config::ObjectList.new
37
+ key.each do |field, match_value|
38
+ field = field.is_a?(Symbol) ? field.to_s : field
39
+ match_value = match_value.is_a?(Symbol) ? match_value.to_s : match_value
40
+ if match_value.is_a?(String) && match_value =~ /^!/
41
+ operator = :not_equal
42
+ match_value = match_value.sub(/^!/, '')
43
+ else
44
+ operator = :equal
45
+ end
46
+ each do |name, config|
47
+ value = config[field]
48
+ if value.is_a? Array
49
+ if value.include?(match_value)
50
+ results[name] = config
51
+ end
52
+ else
53
+ if operator == :equal && value == match_value
54
+ results[name] = config
55
+ elsif operator == :not_equal && value != match_value
56
+ results[name] = config
57
+ end
58
+ end
59
+ end
60
+ end
61
+ results
62
+ else
63
+ super key.to_s
64
+ end
65
+ end
66
+
67
+ def exclude(node)
68
+ list = self.dup
69
+ list.delete(node.name)
70
+ return list
71
+ end
72
+
73
+ def each_node(&block)
74
+ self.keys.sort.each do |node_name|
75
+ yield self[node_name]
76
+ end
77
+ end
78
+
79
+ # def <<(object)
80
+ # if object.is_a? Config::ObjectList
81
+ # self.merge!(object)
82
+ # elsif object['name']
83
+ # self[object['name']] = object
84
+ # else
85
+ # raise ArgumentError.new('argument must be a Config::Object or a Config::ObjectList')
86
+ # end
87
+ # end
88
+
89
+ def add(name, object)
90
+ self[name] = object
91
+ end
92
+
93
+ #
94
+ # converts the hash of configs into an array of hashes, with ONLY the specified fields
95
+ #
96
+ def fields(*fields)
97
+ result = []
98
+ keys.sort.each do |name|
99
+ result << self[name].pick(*fields)
100
+ end
101
+ result
102
+ end
103
+
104
+ #
105
+ # like fields(), but returns an array of values instead of an array of hashes.
106
+ #
107
+ def field(field)
108
+ field = field.to_s
109
+ result = []
110
+ keys.sort.each do |name|
111
+ result << self[name].get(field)
112
+ end
113
+ result
114
+ end
115
+
116
+ #
117
+ # pick_fields(field1, field2, ...)
118
+ #
119
+ # generates a Hash from the object list, but with only the fields that are picked.
120
+ #
121
+ # If there are more than one field, then the result is a Hash of Hashes.
122
+ # If there is just one field, it is a simple map to the value.
123
+ #
124
+ # For example:
125
+ #
126
+ # "neighbors" = "= nodes_like_me[:services => :couchdb].pick_fields('domain.full', 'ip_address')"
127
+ #
128
+ # generates this:
129
+ #
130
+ # neighbors:
131
+ # couch1:
132
+ # domain_full: couch1.bitmask.net
133
+ # ip_address: "10.5.5.44"
134
+ # couch2:
135
+ # domain_full: couch2.bitmask.net
136
+ # ip_address: "10.5.5.52"
137
+ #
138
+ # But this:
139
+ #
140
+ # "neighbors": "= nodes_like_me[:services => :couchdb].pick_fields('domain.full')"
141
+ #
142
+ # will generate this:
143
+ #
144
+ # neighbors:
145
+ # couch1: couch1.bitmask.net
146
+ # couch2: couch2.bitmask.net
147
+ #
148
+ def pick_fields(*fields)
149
+ self.values.inject({}) do |hsh, node|
150
+ value = self[node.name].pick(*fields)
151
+ if fields.size == 1
152
+ value = value.values.first
153
+ end
154
+ hsh[node.name] = value
155
+ hsh
156
+ end
157
+ end
158
+
159
+ #
160
+ # applies inherit_from! to all objects.
161
+ #
162
+ def inherit_from!(object_list)
163
+ object_list.each do |name, object|
164
+ if self[name]
165
+ self[name].inherit_from!(object)
166
+ else
167
+ self[name] = object.dup
168
+ end
169
+ end
170
+ end
171
+
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,43 @@
1
+ #
2
+ #
3
+ # A class for the secrets.json file
4
+ #
5
+ #
6
+
7
+ module LeapCli; module Config
8
+
9
+ class Secrets < Object
10
+ attr_reader :node_list
11
+
12
+ def initialize(manager=nil)
13
+ super(manager)
14
+ @discovered_keys = {}
15
+ end
16
+
17
+ def set(key, value)
18
+ key = key.to_s
19
+ @discovered_keys[key] = true
20
+ self[key] ||= value
21
+ end
22
+
23
+ #
24
+ # if only_discovered_keys is true, then we will only export
25
+ # those secrets that have been discovered and the prior ones will be cleaned out.
26
+ #
27
+ # this should only be triggered when all nodes have been processed, otherwise
28
+ # secrets that are actually in use will get mistakenly removed.
29
+ #
30
+ #
31
+ def dump_json(only_discovered_keys=false)
32
+ if only_discovered_keys
33
+ self.each_key do |key|
34
+ unless @discovered_keys[key]
35
+ self.delete(key)
36
+ end
37
+ end
38
+ end
39
+ super()
40
+ end
41
+ end
42
+
43
+ end; end
@@ -0,0 +1,18 @@
1
+ #
2
+ #
3
+ # A class for node services or node tags.
4
+ #
5
+ #
6
+
7
+ module LeapCli; module Config
8
+
9
+ class Tag < Object
10
+ attr_reader :node_list
11
+
12
+ def initialize(manager=nil)
13
+ super(manager)
14
+ @node_list = Config::ObjectList.new
15
+ end
16
+ end
17
+
18
+ end; end
@@ -0,0 +1,7 @@
1
+ module LeapCli
2
+
3
+ PUPPET_DESTINATION = '/srv/leap'
4
+ INITIALIZED_FILE = "#{PUPPET_DESTINATION}/initialized"
5
+ DEFAULT_TAGS = ['leap_base','leap_service']
6
+
7
+ end
@@ -0,0 +1,97 @@
1
+ #
2
+ # The Leapfile is the bootstrap configuration file for a LEAP provider.
3
+ #
4
+ # It is akin to a Gemfile, Rakefile, or Capfile (e.g. it is a ruby file that gets eval'ed)
5
+ #
6
+
7
+ module LeapCli
8
+ def self.leapfile
9
+ @leapfile ||= Leapfile.new
10
+ end
11
+
12
+ class Leapfile
13
+ attr_accessor :platform_directory_path
14
+ attr_accessor :provider_directory_path
15
+ attr_accessor :custom_vagrant_vm_line
16
+ attr_accessor :leap_version
17
+ attr_accessor :log
18
+ attr_accessor :vagrant_network
19
+ attr_accessor :platform_branch
20
+ attr_accessor :allow_production_deploy
21
+
22
+ def initialize
23
+ @vagrant_network = '10.5.5.0/24'
24
+ end
25
+
26
+ def load(search_directory=nil)
27
+ directory = File.expand_path(find_in_directory_tree('Leapfile', search_directory))
28
+ if directory == '/'
29
+ return nil
30
+ else
31
+ #
32
+ # set up paths
33
+ #
34
+ @provider_directory_path = directory
35
+ read_settings(directory + '/Leapfile')
36
+ read_settings(ENV['HOME'] + '/.leaprc')
37
+ @platform_directory_path = File.expand_path(@platform_directory_path || '../leap_platform', @provider_directory_path)
38
+
39
+ #
40
+ # load the platform
41
+ #
42
+ require "#{@platform_directory_path}/platform.rb"
43
+ if !Leap::Platform.compatible_with_cli?(LeapCli::VERSION)
44
+ Util.bail! "This leap command (v#{LeapCli::VERSION}) " +
45
+ "is not compatible with the platform #{@platform_directory_path} (v#{Leap::Platform.version}). " +
46
+ "You need leap command #{Leap::Platform.compatible_cli.first} to #{Leap::Platform.compatible_cli.last}."
47
+ end
48
+ if !Leap::Platform.version_in_range?(LeapCli::COMPATIBLE_PLATFORM_VERSION)
49
+ Util.bail! "This leap command (v#{LeapCli::VERSION}) " +
50
+ "is not compatible with the platform #{@platform_directory_path} (v#{Leap::Platform.version}). " +
51
+ "You need platform version #{LeapCli::COMPATIBLE_PLATFORM_VERSION.first} to #{LeapCli::COMPATIBLE_PLATFORM_VERSION.last}."
52
+ end
53
+
54
+ #
55
+ # set defaults
56
+ #
57
+ if @allow_production_deploy.nil?
58
+ # by default, only allow production deploys from 'master' or if not a git repo
59
+ @allow_production_deploy = !LeapCli::Util.is_git_directory?(@provider_directory_path) ||
60
+ LeapCli::Util.current_git_branch(@provider_directory_path) == 'master'
61
+ end
62
+ return true
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def read_settings(file)
69
+ if File.exists? file
70
+ Util::log 2, :read, file
71
+ instance_eval(File.read(file), file)
72
+ validate(file)
73
+ end
74
+ end
75
+
76
+ def find_in_directory_tree(filename, directory_tree=nil)
77
+ search_dir = directory_tree || Dir.pwd
78
+ while search_dir != "/"
79
+ Dir.foreach(search_dir) do |f|
80
+ return search_dir if f == filename
81
+ end
82
+ search_dir = File.dirname(search_dir)
83
+ end
84
+ return search_dir
85
+ end
86
+
87
+ PRIVATE_IP_RANGES = /(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/
88
+
89
+ def validate(file)
90
+ Util::assert! vagrant_network =~ PRIVATE_IP_RANGES do
91
+ Util::log 0, :error, "in #{file}: vagrant_network is not a local private network"
92
+ end
93
+ end
94
+
95
+ end
96
+ end
97
+
@@ -0,0 +1,15 @@
1
+ #
2
+ # Bundle and rubygems each have their own way of modifying $LOAD_PATH.
3
+ #
4
+ # We want to make sure that the right paths are loaded, including the
5
+ # vendored gems, regardless of how leap is run.
6
+ #
7
+ #
8
+
9
+ require File.expand_path('../version', __FILE__)
10
+
11
+ base_leap_dir = File.expand_path('../../..', __FILE__)
12
+ LeapCli::LOAD_PATHS.each do |path|
13
+ path = File.expand_path(path, base_leap_dir)
14
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
15
+ end