corl 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -10,20 +10,28 @@ GEM
10
10
  deep_merge (1.0.1)
11
11
  descendants_tracker (0.0.3)
12
12
  diff-lcs (1.2.5)
13
- excon (0.31.0)
13
+ excon (0.32.1)
14
14
  facter (1.7.5)
15
15
  faraday (0.9.0)
16
16
  multipart-post (>= 1.2, < 3)
17
17
  ffi (1.9.3)
18
- fog (1.20.0)
18
+ fog (1.21.0)
19
+ fog-brightbox
20
+ fog-core (~> 1.21, >= 1.21.1)
21
+ fog-json
22
+ nokogiri (~> 1.5, >= 1.5.11)
23
+ fog-brightbox (0.0.1)
24
+ fog-core
25
+ fog-json
26
+ fog-core (1.21.1)
19
27
  builder
20
- excon (~> 0.31.0)
28
+ excon (~> 0.32)
21
29
  formatador (~> 0.2.0)
22
30
  mime-types
23
- multi_json (~> 1.0)
24
31
  net-scp (~> 1.1)
25
32
  net-ssh (>= 2.1.3)
26
- nokogiri (>= 1.5.11)
33
+ fog-json (1.0.0)
34
+ multi_json (~> 1.0)
27
35
  formatador (0.2.4)
28
36
  git (1.2.6)
29
37
  github_api (0.11.3)
@@ -68,7 +76,7 @@ GEM
68
76
  netrc (0.7.7)
69
77
  nokogiri (1.6.1)
70
78
  mini_portile (~> 0.5.0)
71
- nucleon (0.1.6)
79
+ nucleon (0.1.7)
72
80
  celluloid (~> 0.15)
73
81
  childprocess (~> 0.5.0)
74
82
  deep_merge (~> 1.0)
data/README.rdoc CHANGED
@@ -1,10 +1,10 @@
1
- = CORL (Cluster Orchestration and Research Library)
1
+ === CORL (Coral Orchestration and Research Library)
2
2
 
3
3
  Coming soon!
4
4
 
5
5
  Note: This library is still very early in development!
6
6
 
7
- == Contributing to CORL
7
+ ==== Contributing to CORL
8
8
 
9
9
  * Check out the latest {major}.{minor} branch to make sure the feature hasn't
10
10
  been implemented or the bug hasn't been fixed yet.
@@ -19,9 +19,9 @@ Note: This library is still very early in development!
19
19
  to have your own version, or is otherwise necessary, that is fine, but
20
20
  please isolate to its own commit so I can cherry-pick around it.
21
21
 
22
- == Copyright
22
+ ==== Copyright
23
23
 
24
24
  Licensed under GPLv3. See LICENSE.txt for further details.
25
25
 
26
26
  Copyright (c) 2013 Adrian Webb <adrian.webb@coralnexus.com>
27
- Coral Technology Group LLC
27
+ Coral Technology Group LLC
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.3
1
+ 0.4.4
data/corl.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "corl"
8
- s.version = "0.4.3"
8
+ s.version = "0.4.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Adrian Webb"]
12
- s.date = "2014-03-16"
12
+ s.date = "2014-03-19"
13
13
  s.description = "Framework that provides a simple foundation for growing organically in the cloud"
14
14
  s.email = "adrian.webb@coralnexus.com"
15
15
  s.executables = ["corl"]
@@ -50,6 +50,7 @@ Gem::Specification.new do |s|
50
50
  "lib/CORL/action/exec.rb",
51
51
  "lib/CORL/action/image.rb",
52
52
  "lib/CORL/action/images.rb",
53
+ "lib/CORL/action/keypair.rb",
53
54
  "lib/CORL/action/lookup.rb",
54
55
  "lib/CORL/action/machines.rb",
55
56
  "lib/CORL/action/provision.rb",
@@ -0,0 +1,56 @@
1
+
2
+ module CORL
3
+ module Action
4
+ class Keypair < Plugin::CloudAction
5
+
6
+ include Mixin::Action::Keypair
7
+
8
+ #----------------------------------------------------------------------------
9
+ # Settings
10
+
11
+ def configure
12
+ super do
13
+ codes :key_failure
14
+
15
+ register :json, :bool, true
16
+ keypair_config
17
+ end
18
+ end
19
+
20
+ #---
21
+
22
+ def ignore
23
+ node_ignore
24
+ end
25
+
26
+ #-----------------------------------------------------------------------------
27
+ # Operations
28
+
29
+ def execute
30
+ super do |node, network|
31
+ if keys = keypair
32
+ ui.info("\n", { :prefix => false })
33
+ ui_group(Util::Console.cyan("#{keys.type.upcase} SSH keypair")) do |ui|
34
+ ui.info("-----------------------------------------------------")
35
+
36
+ if settings[:json]
37
+ private_key = Util::Console.blue(Util::Data.to_json(keys.encrypted_key, true))
38
+ ssh_key = keys.ssh_key.gsub(/^ssh\-[a-z]+\s+/, '')
39
+ ssh_key = Util::Console.green(Util::Data.to_json(ssh_key, true))
40
+ else
41
+ private_key = Util::Console.blue(keys.encrypted_key)
42
+ ssh_key = Util::Console.green(keys.ssh_key)
43
+ end
44
+
45
+ ui.info("SSH private key:\n#{private_key}")
46
+ ui.info("SSH public key:\n#{ssh_key}")
47
+ ui.info("\n", { :prefix => false })
48
+ end
49
+ else
50
+ myself.status = code.key_failure
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -10,6 +10,9 @@ class Provision < Plugin::CloudAction
10
10
  super do
11
11
  codes :network_failure,
12
12
  :provision_failure
13
+
14
+ register :dry_run, :bool, false
15
+ register :color, :bool, true
13
16
  end
14
17
  end
15
18
 
@@ -36,10 +39,8 @@ class Provision < Plugin::CloudAction
36
39
  profiles = provider_info[:profiles]
37
40
 
38
41
  collection.each do |name, provisioner|
39
- build_profiles = provisioner.build_profiles
40
-
41
42
  if supported_profiles = provisioner.supported_profiles(profiles)
42
- profile_success = provisioner.provision(supported_profiles)
43
+ profile_success = provisioner.provision(supported_profiles, settings)
43
44
  success = false unless profile_success
44
45
  end
45
46
  end
@@ -1,4 +1,4 @@
1
-
1
+
2
2
  module CORL
3
3
  module Provisioner
4
4
  class Puppetnode < CORL.plugin_class(:provisioner)
@@ -12,10 +12,33 @@ class Puppetnode < CORL.plugin_class(:provisioner)
12
12
  super do
13
13
  if CORL.log_level == :debug
14
14
  Puppet.debug = true
15
- end
16
- end
15
+ end
16
+ unless reload
17
+ Puppet::Util::Log.newdesttype id do
18
+ def handle(msg)
19
+ levels = {
20
+ :emerg => { :name => 'emergency', :send => :error },
21
+ :alert => { :name => 'alert', :send => :error },
22
+ :crit => { :name => 'critical', :send => :error },
23
+ :err => { :name => 'error', :send => :error },
24
+ :warning => { :name => 'warning', :send => :warn },
25
+ :notice => { :name => 'notice', :send => :success },
26
+ :info => { :name => 'info', :send => :info },
27
+ :debug => { :name => 'debug', :send => :info }
28
+ }
29
+ str = msg.respond_to?(:multiline) ? msg.multiline : msg.to_s
30
+ str = msg.source == "Puppet" ? str : "#{msg.source}: #{str}"
31
+ level = levels[msg.level]
32
+
33
+ CORL.ui_group("puppetnode::#{name}(#{level[:name]})") do |ui|
34
+ ui.send(level[:send], str)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
17
40
  end
18
-
41
+
19
42
  #---
20
43
 
21
44
  def register(options = {})
@@ -42,12 +65,13 @@ class Puppetnode < CORL.plugin_class(:provisioner)
42
65
  def init_puppet(profiles)
43
66
  locations = build_locations
44
67
 
45
- # Must be in this order!!
46
68
  Puppet.initialize_settings
47
- Puppet::Util::Log.newdestination(:console)
69
+ Puppet::Util::Log.newdestination(id)
48
70
 
49
71
  # TODO: Figure out how to store these damn settings in a specialized
50
72
  # environment without phantom empty environment issues.
73
+
74
+ Puppet[:default_file_terminus] = :file_server
51
75
 
52
76
  node = get_node
53
77
  Puppet[:node_name_value] = id.to_s
@@ -70,10 +94,7 @@ class Puppetnode < CORL.plugin_class(:provisioner)
70
94
 
71
95
  @compiler = Puppet::Parser::Compiler.new(node)
72
96
  register
73
-
74
- # Initialize the compiler so we can can lookup and include stuff
75
- # This is ugly but seems to be the only way.
76
- compiler.compile
97
+ node
77
98
  end
78
99
  protected :init_puppet
79
100
 
@@ -158,15 +179,6 @@ class Puppetnode < CORL.plugin_class(:provisioner)
158
179
 
159
180
  #---
160
181
 
161
- def include(resource_name, properties = {}, options = {})
162
- Util::Puppet.include(resource_name, properties, Config.ensure(options).defaults({
163
- :provisioner => :puppetnode,
164
- :puppet_scope => scope
165
- }))
166
- end
167
-
168
- #---
169
-
170
182
  def add_search_path(type, resource_name)
171
183
  Config.set_options([ :all, type ], { :search => [ resource_name.to_s ] })
172
184
  end
@@ -174,81 +186,96 @@ class Puppetnode < CORL.plugin_class(:provisioner)
174
186
  #---
175
187
 
176
188
  def provision(profiles, options = {})
177
- locations = build_locations
178
- success = true
189
+ super do |config|
190
+ locations = build_locations
191
+ success = true
179
192
 
180
- include_location = lambda do |type, add_to_catalog = true, add_search_path = false|
181
- locations[:package].each do |name, package_directory|
182
- gateway = File.join(build_directory, package_directory, "#{type}.pp")
183
- resource_name = concatenate([ name, type ])
193
+ include_location = lambda do |type, parameters = {}, add_search_path = false|
194
+ classes = {}
195
+
196
+ locations[:package].each do |name, package_directory|
197
+ gateway = File.join(build_directory, package_directory, "#{type}.pp")
198
+ resource_name = concatenate([ name, type ])
184
199
 
185
- add_search_path(type, resource_name) if add_search_path
200
+ add_search_path(type, resource_name) if add_search_path
186
201
 
187
- if File.exists?(gateway)
188
- import(gateway)
189
- include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
190
- end
202
+ if File.exists?(gateway)
203
+ import(gateway)
204
+ classes[resource_name] = parameters
205
+ end
191
206
 
192
- directory = File.join(build_directory, package_directory, type.to_s)
193
- Dir.glob(File.join(directory, '*.pp')).each do |file|
194
- resource_name = concatenate([ name, type, File.basename(file).gsub('.pp', '') ])
195
- import(file)
196
- include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
197
- end
198
- end
207
+ directory = File.join(build_directory, package_directory, type.to_s)
208
+ Dir.glob(File.join(directory, '*.pp')).each do |file|
209
+ resource_name = concatenate([ name, type, File.basename(file).gsub('.pp', '') ])
210
+ import(file)
211
+ classes[resource_name] = parameters
212
+ end
213
+ end
199
214
 
200
- gateway = File.join(build_directory, locations[:build], "#{type}.pp")
201
- resource_name = concatenate([ plugin_name, type ])
215
+ gateway = File.join(build_directory, locations[:build], "#{type}.pp")
216
+ resource_name = concatenate([ plugin_name, type ])
202
217
 
203
- add_search_path(type, resource_name) if add_search_path
218
+ add_search_path(type, resource_name) if add_search_path
204
219
 
205
- if File.exists?(gateway)
206
- import(gateway)
207
- include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
208
- end
220
+ if File.exists?(gateway)
221
+ import(gateway)
222
+ classes[resource_name] = parameters
223
+ end
209
224
 
210
- if locations.has_key?(type)
211
- directory = File.join(build_directory, locations[type])
212
- Dir.glob(File.join(directory, '*.pp')).each do |file|
213
- resource_name = concatenate([ plugin_name, type, File.basename(file).gsub('.pp', '') ])
214
- import(file)
215
- include(resource_name, { :before => 'Anchor[gateway_init]' }) if add_to_catalog
225
+ if locations.has_key?(type)
226
+ directory = File.join(build_directory, locations[type])
227
+ Dir.glob(File.join(directory, '*.pp')).each do |file|
228
+ resource_name = concatenate([ plugin_name, type, File.basename(file).gsub('.pp', '') ])
229
+ import(file)
230
+ classes[resource_name] = parameters
231
+ end
216
232
  end
233
+ classes
217
234
  end
218
- end
219
235
 
220
- @@puppet_lock.synchronize do
221
- begin
222
- start_time = Time.now
223
-
224
- init_puppet(profiles)
236
+ @@puppet_lock.synchronize do
237
+ begin
238
+ ui.info("Starting catalog generation")
239
+
240
+ start_time = Time.now
241
+ node = init_puppet(profiles)
225
242
 
226
- # Include defaults
227
- include_location.call(:default, true, true)
243
+ # Include defaults
244
+ classes = include_location.call(:default, {}, true)
228
245
 
229
- # Import and include needed profiles
230
- include_location.call(:profiles, false)
246
+ # Import needed profiles
247
+ include_location.call(:profiles, {}, false)
231
248
 
232
- profiles.each do |profile|
233
- include(profile, { :require => 'Anchor[gateway_exit]' })
234
- end
249
+ profiles.each do |profile|
250
+ classes[profile.to_s] = { :require => 'Anchor[profile_start]' }
251
+ end
252
+
253
+ # Compile catalog
254
+ node.classes = classes
255
+ compiler.compile
235
256
 
236
- # Start system configuration
237
- catalog = compiler.catalog.to_ral
238
- catalog.finalize
239
- catalog.retrieval_duration = Time.now - start_time
257
+ # Start system configuration
258
+ catalog = compiler.catalog.to_ral
259
+ catalog.finalize
260
+ catalog.retrieval_duration = Time.now - start_time
261
+
262
+ unless config.get(:dry_run, false)
263
+ ui.info("\n", { :prefix => false })
264
+ ui.info("Starting configuration run")
265
+
266
+ configurer = Puppet::Configurer.new
267
+ if ! configurer.run(:catalog => catalog, :pluginsync => false)
268
+ success = false
269
+ end
270
+ end
240
271
 
241
- configurer = Puppet::Configurer.new
242
- if ! configurer.run(:catalog => catalog, :pluginsync => false)
243
- success = false
272
+ rescue Exception => error
273
+ raise error
274
+ Puppet.log_exception(error)
244
275
  end
245
-
246
- rescue Exception => error
247
- raise error
248
- Puppet.log_exception(error)
249
- end
250
- end
251
- success
276
+ end
277
+ success
278
+ end
252
279
  end
253
280
 
254
281
  #-----------------------------------------------------------------------------
@@ -72,7 +72,7 @@ module Keypair
72
72
  :bits => settings[:key_bits],
73
73
  :comment => settings[:key_comment]
74
74
  })
75
- @keypair = Util::SSH.generate(options)
75
+ @keypair = Util::SSH.generate(config)
76
76
  settings.import({ :keypair => @keypair })
77
77
  end
78
78
 
@@ -32,6 +32,8 @@ module Lookup
32
32
  #---
33
33
 
34
34
  def hiera_config
35
+ Kernel.load File.join(File.dirname(__FILE__), '..', 'mod', 'hiera_backend.rb')
36
+
35
37
  config_file = CORL.value(:hiera_config_file, File.join(Hiera::Util.config_dir, 'hiera.yaml'))
36
38
  config = {}
37
39
 
@@ -72,7 +74,8 @@ module Lookup
72
74
 
73
75
  hiera_scope = config.get(:hiera_scope, {})
74
76
  override = config.get(:override, nil)
75
- context = config.get(:context, :priority)
77
+ context = config.get(:context, :priority)
78
+ debug = config.get(:debug, false)
76
79
 
77
80
  return_property = config.get(:return_property, false)
78
81
 
@@ -85,8 +88,18 @@ module Lookup
85
88
  property = property.to_sym
86
89
  first_property = property unless first_property
87
90
 
91
+ if debug
92
+ CORL.ui.info("\n", { :prefix => false })
93
+ CORL.ui_group(Util::Console.purple(property)) do |ui|
94
+ ui.info("-----------------------------------------------------")
95
+ end
96
+ end
97
+
88
98
  # Try to load facts first (these can not be overridden)
89
- unless value = fact(property)
99
+ value = fact(property)
100
+ debug_lookup(config, property, value, "Fact lookup")
101
+
102
+ unless value
90
103
  if CORL.admin?
91
104
  if config_initialized?
92
105
  # Try to find in Hiera data store (these might be security sensitive)
@@ -94,23 +107,33 @@ module Lookup
94
107
  hiera_scope = Hiera::Scope.new(hiera_scope)
95
108
  end
96
109
  value = hiera.lookup(property.to_s, nil, hiera_scope, override, context)
110
+ debug_lookup(config, property, value, "Hiera lookup")
97
111
  end
98
112
 
99
113
  if provisioner && Util::Data.undef?(value)
100
114
  # Search the provisioner scope (only admins can provision a machine)
101
115
  value = CORL.provisioner({ :name => :lookup }, provisioner).lookup(property, default, config)
116
+ debug_lookup(config, property, value, "Provisioner lookup")
102
117
  end
103
118
  end
104
119
  end
105
120
  end
106
- value = default if Util::Data.undef?(value) # Resort to default
107
- value = Util::Data.value(value)
121
+ if Util::Data.undef?(value) # Resort to default
122
+ value = default
123
+ debug_lookup(config, first_property, value, "Default value")
124
+ end
125
+ value = Util::Data.value(value, config.get(:undefined_value, :undefined))
108
126
 
109
127
  if ! Config.get_property(first_property) || ! Util::Data.undef?(value)
110
128
  Config.set_property(first_property.to_s, value)
111
129
  end
112
130
 
113
- return value, first_property if return_property
131
+ debug_lookup(config, first_property, value, 'Internalized value')
132
+
133
+ if return_property
134
+ return value, first_property
135
+ end
136
+ CORL.ui.info("\n", { :prefix => false }) if debug
114
137
  value
115
138
  end
116
139
 
@@ -122,18 +145,24 @@ module Lookup
122
145
 
123
146
  if Util::Data.undef?(value)
124
147
  value = default
148
+ debug_lookup(config, property, value, "Array default value")
125
149
 
126
150
  elsif ! Util::Data.empty?(default)
127
151
  if config.get(:merge, false)
128
152
  value = Util::Data.merge([default, value], config)
153
+ debug_lookup(config, property, value, "Merged array value with default")
129
154
  end
130
155
  end
131
156
 
132
157
  unless value.is_a?(Array)
133
158
  value = ( Util::Data.empty?(value) ? [] : [ value ] )
134
159
  end
160
+
161
+ value = Util::Data.value(value, config.get(:undefined_value, :undefined))
162
+ debug_lookup(config, property, value, "Final array value")
135
163
 
136
164
  Config.set_property(property.to_s, value)
165
+ CORL.ui.info("\n", { :prefix => false }) if config.get(:debug, false)
137
166
  value
138
167
  end
139
168
 
@@ -145,10 +174,12 @@ module Lookup
145
174
 
146
175
  if Util::Data.undef?(value)
147
176
  value = default
177
+ debug_lookup(config, property, value, "Hash default value")
148
178
 
149
179
  elsif ! Util::Data.empty?(default)
150
180
  if config.get(:merge, false)
151
181
  value = Util::Data.merge([default, value], config)
182
+ debug_lookup(config, property, value, "Merged hash value with default")
152
183
  end
153
184
  end
154
185
 
@@ -156,7 +187,11 @@ module Lookup
156
187
  value = ( Util::Data.empty?(value) ? {} : { :value => value } )
157
188
  end
158
189
 
190
+ value = Util::Data.value(value, config.get(:undefined_value, :undefined))
191
+ debug_lookup(config, property, value, "Final hash value")
192
+
159
193
  Config.set_property(property.to_s, value)
194
+ CORL.ui.info("\n", { :prefix => false }) if config.get(:debug, false)
160
195
  value
161
196
  end
162
197
 
@@ -196,6 +231,22 @@ module Lookup
196
231
  end
197
232
  results
198
233
  end
234
+
235
+ #---
236
+
237
+ def debug_lookup(config, property, value, label)
238
+ if config.get(:debug, false)
239
+ CORL.ui_group(Util::Console.cyan(property.to_s)) do |ui|
240
+ dump = Util::Console.green(Util::Data.to_json(value, true))
241
+
242
+ if dump.match(/\n+/)
243
+ ui.info("#{label}:\n#{dump}")
244
+ else
245
+ ui.info("#{label}: #{dump}")
246
+ end
247
+ end
248
+ end
249
+ end
199
250
  end
200
251
  end
201
252
  end