bosh-director 1.5.0.pre.1113

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. data/CHANGELOG +34 -0
  2. data/bin/bosh-director +36 -0
  3. data/bin/bosh-director-console +84 -0
  4. data/bin/bosh-director-drain-workers +42 -0
  5. data/bin/bosh-director-migrate +58 -0
  6. data/bin/bosh-director-scheduler +27 -0
  7. data/bin/bosh-director-worker +76 -0
  8. data/db/migrations/README +1 -0
  9. data/db/migrations/director/20110209010747_initial.rb +118 -0
  10. data/db/migrations/director/20110406055800_add_task_user.rb +9 -0
  11. data/db/migrations/director/20110518225809_remove_cid_constrain.rb +13 -0
  12. data/db/migrations/director/20110617211923_add_deployments_release_versions.rb +32 -0
  13. data/db/migrations/director/20110622212607_add_task_checkpoint_timestamp.rb +9 -0
  14. data/db/migrations/director/20110628023039_add_state_to_instances.rb +21 -0
  15. data/db/migrations/director/20110709012332_add_disk_size_to_instances.rb +9 -0
  16. data/db/migrations/director/20110906183441_add_log_bundles.rb +11 -0
  17. data/db/migrations/director/20110907194830_add_logs_json_to_templates.rb +9 -0
  18. data/db/migrations/director/20110915205610_add_persistent_disks.rb +51 -0
  19. data/db/migrations/director/20111005180929_add_properties.rb +14 -0
  20. data/db/migrations/director/20111110024617_add_deployment_problems.rb +24 -0
  21. data/db/migrations/director/20111216214145_recreate_support_for_vms.rb +9 -0
  22. data/db/migrations/director/20120102084027_add_credentials_to_vms.rb +7 -0
  23. data/db/migrations/director/20120427235217_allow_multiple_releases_per_deployment.rb +36 -0
  24. data/db/migrations/director/20120524175805_add_task_type.rb +44 -0
  25. data/db/migrations/director/20120614001930_delete_redundant_deployment_release_relation.rb +34 -0
  26. data/db/migrations/director/20120822004528_add_fingerprint_to_templates_and_packages.rb +17 -0
  27. data/db/migrations/director/20120830191244_add_properties_to_templates.rb +9 -0
  28. data/db/migrations/director/20121106190739_persist_vm_env.rb +9 -0
  29. data/db/migrations/director/20130222232131_add_sha1_to_stemcells.rb +9 -0
  30. data/db/migrations/director/20130312211407_add_commit_hash_to_release_versions.rb +19 -0
  31. data/db/migrations/director/20130409235338_snapshot.rb +15 -0
  32. data/db/migrations/director/20130530164918_add_paused_flag_to_instance.rb +14 -0
  33. data/db/migrations/director/20130531172604_add_director_attributes.rb +13 -0
  34. data/db/migrations/dns/20120123234908_initial.rb +27 -0
  35. data/lib/bosh/director.rb +133 -0
  36. data/lib/bosh/director/agent_client.rb +78 -0
  37. data/lib/bosh/director/api.rb +29 -0
  38. data/lib/bosh/director/api/api_helper.rb +81 -0
  39. data/lib/bosh/director/api/backup_manager.rb +15 -0
  40. data/lib/bosh/director/api/controller.rb +639 -0
  41. data/lib/bosh/director/api/controller_helpers.rb +34 -0
  42. data/lib/bosh/director/api/deployment_lookup.rb +13 -0
  43. data/lib/bosh/director/api/deployment_manager.rb +60 -0
  44. data/lib/bosh/director/api/http_constants.rb +16 -0
  45. data/lib/bosh/director/api/instance_lookup.rb +44 -0
  46. data/lib/bosh/director/api/instance_manager.rb +63 -0
  47. data/lib/bosh/director/api/problem_manager.rb +40 -0
  48. data/lib/bosh/director/api/property_manager.rb +69 -0
  49. data/lib/bosh/director/api/release_manager.rb +59 -0
  50. data/lib/bosh/director/api/resource_manager.rb +69 -0
  51. data/lib/bosh/director/api/resurrector_manager.rb +15 -0
  52. data/lib/bosh/director/api/snapshot_manager.rb +94 -0
  53. data/lib/bosh/director/api/stemcell_manager.rb +50 -0
  54. data/lib/bosh/director/api/task_helper.rb +46 -0
  55. data/lib/bosh/director/api/task_manager.rb +64 -0
  56. data/lib/bosh/director/api/user_manager.rb +72 -0
  57. data/lib/bosh/director/api/vm_state_manager.rb +11 -0
  58. data/lib/bosh/director/app.rb +35 -0
  59. data/lib/bosh/director/blob_util.rb +87 -0
  60. data/lib/bosh/director/blobstores.rb +29 -0
  61. data/lib/bosh/director/client.rb +156 -0
  62. data/lib/bosh/director/cloudcheck_helper.rb +204 -0
  63. data/lib/bosh/director/compile_task.rb +157 -0
  64. data/lib/bosh/director/config.rb +370 -0
  65. data/lib/bosh/director/configuration_hasher.rb +114 -0
  66. data/lib/bosh/director/cycle_helper.rb +36 -0
  67. data/lib/bosh/director/db_backup.rb +22 -0
  68. data/lib/bosh/director/db_backup/adapter.rb +3 -0
  69. data/lib/bosh/director/db_backup/adapter/mysql2.rb +27 -0
  70. data/lib/bosh/director/db_backup/adapter/postgres.rb +36 -0
  71. data/lib/bosh/director/db_backup/adapter/sqlite.rb +17 -0
  72. data/lib/bosh/director/db_backup/error.rb +10 -0
  73. data/lib/bosh/director/deployment_plan.rb +26 -0
  74. data/lib/bosh/director/deployment_plan/assembler.rb +430 -0
  75. data/lib/bosh/director/deployment_plan/compilation_config.rb +54 -0
  76. data/lib/bosh/director/deployment_plan/compiled_package.rb +35 -0
  77. data/lib/bosh/director/deployment_plan/dynamic_network.rb +91 -0
  78. data/lib/bosh/director/deployment_plan/idle_vm.rb +109 -0
  79. data/lib/bosh/director/deployment_plan/instance.rb +413 -0
  80. data/lib/bosh/director/deployment_plan/job.rb +470 -0
  81. data/lib/bosh/director/deployment_plan/manual_network.rb +137 -0
  82. data/lib/bosh/director/deployment_plan/network.rb +74 -0
  83. data/lib/bosh/director/deployment_plan/network_subnet.rb +167 -0
  84. data/lib/bosh/director/deployment_plan/planner.rb +288 -0
  85. data/lib/bosh/director/deployment_plan/preparer.rb +52 -0
  86. data/lib/bosh/director/deployment_plan/release.rb +126 -0
  87. data/lib/bosh/director/deployment_plan/resource_pool.rb +143 -0
  88. data/lib/bosh/director/deployment_plan/resource_pools.rb +68 -0
  89. data/lib/bosh/director/deployment_plan/stemcell.rb +56 -0
  90. data/lib/bosh/director/deployment_plan/template.rb +94 -0
  91. data/lib/bosh/director/deployment_plan/update_config.rb +80 -0
  92. data/lib/bosh/director/deployment_plan/updater.rb +55 -0
  93. data/lib/bosh/director/deployment_plan/vip_network.rb +79 -0
  94. data/lib/bosh/director/dns_helper.rb +204 -0
  95. data/lib/bosh/director/download_helper.rb +44 -0
  96. data/lib/bosh/director/duration.rb +36 -0
  97. data/lib/bosh/director/encryption_helper.rb +10 -0
  98. data/lib/bosh/director/errors.rb +198 -0
  99. data/lib/bosh/director/event_log.rb +136 -0
  100. data/lib/bosh/director/ext.rb +64 -0
  101. data/lib/bosh/director/hash_string_vals.rb +13 -0
  102. data/lib/bosh/director/instance_deleter.rb +109 -0
  103. data/lib/bosh/director/instance_updater.rb +506 -0
  104. data/lib/bosh/director/ip_util.rb +67 -0
  105. data/lib/bosh/director/job_queue.rb +16 -0
  106. data/lib/bosh/director/job_runner.rb +162 -0
  107. data/lib/bosh/director/job_updater.rb +121 -0
  108. data/lib/bosh/director/jobs/backup.rb +86 -0
  109. data/lib/bosh/director/jobs/base_job.rb +66 -0
  110. data/lib/bosh/director/jobs/cloud_check/apply_resolutions.rb +46 -0
  111. data/lib/bosh/director/jobs/cloud_check/scan.rb +38 -0
  112. data/lib/bosh/director/jobs/cloud_check/scan_and_fix.rb +73 -0
  113. data/lib/bosh/director/jobs/create_snapshot.rb +23 -0
  114. data/lib/bosh/director/jobs/delete_deployment.rb +183 -0
  115. data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +34 -0
  116. data/lib/bosh/director/jobs/delete_release.rb +219 -0
  117. data/lib/bosh/director/jobs/delete_snapshots.rb +23 -0
  118. data/lib/bosh/director/jobs/delete_stemcell.rb +102 -0
  119. data/lib/bosh/director/jobs/fetch_logs.rb +99 -0
  120. data/lib/bosh/director/jobs/scheduled_backup.rb +38 -0
  121. data/lib/bosh/director/jobs/snapshot_deployment.rb +61 -0
  122. data/lib/bosh/director/jobs/snapshot_deployments.rb +23 -0
  123. data/lib/bosh/director/jobs/snapshot_self.rb +43 -0
  124. data/lib/bosh/director/jobs/ssh.rb +59 -0
  125. data/lib/bosh/director/jobs/update_deployment.rb +110 -0
  126. data/lib/bosh/director/jobs/update_release.rb +672 -0
  127. data/lib/bosh/director/jobs/update_stemcell.rb +109 -0
  128. data/lib/bosh/director/jobs/vm_state.rb +89 -0
  129. data/lib/bosh/director/lock.rb +133 -0
  130. data/lib/bosh/director/lock_helper.rb +92 -0
  131. data/lib/bosh/director/models.rb +29 -0
  132. data/lib/bosh/director/models/compiled_package.rb +33 -0
  133. data/lib/bosh/director/models/deployment.rb +22 -0
  134. data/lib/bosh/director/models/deployment_problem.rb +49 -0
  135. data/lib/bosh/director/models/deployment_property.rb +21 -0
  136. data/lib/bosh/director/models/director_attribute.rb +9 -0
  137. data/lib/bosh/director/models/dns.rb +9 -0
  138. data/lib/bosh/director/models/dns/domain.rb +9 -0
  139. data/lib/bosh/director/models/dns/record.rb +7 -0
  140. data/lib/bosh/director/models/helpers/model_helper.rb +7 -0
  141. data/lib/bosh/director/models/instance.rb +28 -0
  142. data/lib/bosh/director/models/log_bundle.rb +10 -0
  143. data/lib/bosh/director/models/package.rb +30 -0
  144. data/lib/bosh/director/models/persistent_disk.rb +13 -0
  145. data/lib/bosh/director/models/release.rb +17 -0
  146. data/lib/bosh/director/models/release_version.rb +16 -0
  147. data/lib/bosh/director/models/snapshot.rb +13 -0
  148. data/lib/bosh/director/models/stemcell.rb +18 -0
  149. data/lib/bosh/director/models/task.rb +10 -0
  150. data/lib/bosh/director/models/template.rb +44 -0
  151. data/lib/bosh/director/models/user.rb +11 -0
  152. data/lib/bosh/director/models/vm.rb +42 -0
  153. data/lib/bosh/director/nats_rpc.rb +54 -0
  154. data/lib/bosh/director/network_reservation.rb +121 -0
  155. data/lib/bosh/director/next_rebase_version.rb +20 -0
  156. data/lib/bosh/director/package_compiler.rb +423 -0
  157. data/lib/bosh/director/problem_handlers/base.rb +153 -0
  158. data/lib/bosh/director/problem_handlers/inactive_disk.rb +112 -0
  159. data/lib/bosh/director/problem_handlers/invalid_problem.rb +28 -0
  160. data/lib/bosh/director/problem_handlers/missing_vm.rb +34 -0
  161. data/lib/bosh/director/problem_handlers/mount_info_mismatch.rb +62 -0
  162. data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +64 -0
  163. data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +85 -0
  164. data/lib/bosh/director/problem_handlers/unresponsive_agent.rb +78 -0
  165. data/lib/bosh/director/problem_resolver.rb +103 -0
  166. data/lib/bosh/director/problem_scanner.rb +268 -0
  167. data/lib/bosh/director/resource_pool_updater.rb +216 -0
  168. data/lib/bosh/director/scheduler.rb +57 -0
  169. data/lib/bosh/director/sequel.rb +13 -0
  170. data/lib/bosh/director/tar_gzipper.rb +47 -0
  171. data/lib/bosh/director/task_result_file.rb +19 -0
  172. data/lib/bosh/director/thread_pool.rb +8 -0
  173. data/lib/bosh/director/validation_helper.rb +55 -0
  174. data/lib/bosh/director/version.rb +7 -0
  175. data/lib/bosh/director/vm_creator.rb +80 -0
  176. data/lib/bosh/director/vm_data.rb +63 -0
  177. data/lib/bosh/director/vm_metadata_updater.rb +29 -0
  178. data/lib/bosh/director/vm_reuser.rb +63 -0
  179. data/lib/cloud/dummy.rb +149 -0
  180. metadata +664 -0
@@ -0,0 +1,370 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require 'fileutils'
4
+
5
+ module Bosh::Director
6
+
7
+ # We are in the slow painful process of extracting all of this class-level
8
+ # behavior into instance behavior, much of it on the App class. When this
9
+ # process is complete, the Config will be responsible only for maintaining
10
+ # configuration information - not holding the state of the world.
11
+
12
+ class Config
13
+ class << self
14
+ include DnsHelper
15
+
16
+ CONFIG_OPTIONS = [
17
+ :base_dir,
18
+ :cloud_options,
19
+ :db,
20
+ :dns,
21
+ :dns_db,
22
+ :dns_domain_name,
23
+ :event_log,
24
+ :logger,
25
+ :max_tasks,
26
+ :max_threads,
27
+ :name,
28
+ :process_uuid,
29
+ :result,
30
+ :revision,
31
+ :task_checkpoint_interval,
32
+ :uuid,
33
+ :current_job,
34
+ :encryption,
35
+ :fix_stateful_nodes,
36
+ :enable_snapshots
37
+ ]
38
+
39
+ CONFIG_OPTIONS.each do |option|
40
+ attr_accessor option
41
+ end
42
+
43
+ attr_reader :db_config
44
+
45
+ def clear
46
+ CONFIG_OPTIONS.each do |option|
47
+ self.instance_variable_set("@#{option}".to_sym, nil)
48
+ end
49
+
50
+ Thread.list.each do |thr|
51
+ thr[:bosh] = nil
52
+ end
53
+
54
+ @blobstore = nil
55
+ @compiled_package_cache = nil
56
+ @nats = nil
57
+ @nats_rpc = nil
58
+ @cloud = nil
59
+ end
60
+
61
+ def configure(config)
62
+
63
+ @base_dir = config["dir"]
64
+ FileUtils.mkdir_p(@base_dir)
65
+
66
+ # checkpoint task progress every 30 secs
67
+ @task_checkpoint_interval = 30
68
+
69
+ logging = config.fetch('logging', {})
70
+ @log_device = Logger::LogDevice.new(logging.fetch('file', STDOUT))
71
+ @logger = Logger.new(@log_device)
72
+ @logger.level = Logger.const_get(logging.fetch('level', 'debug').upcase)
73
+ @logger.formatter = ThreadFormatter.new
74
+
75
+ # use a separate logger for redis to make it stfu
76
+ redis_logger = Logger.new(@log_device)
77
+ logging = config.fetch('redis', {}).fetch('logging', {})
78
+ redis_logger_level = logging.fetch('level', 'info').upcase
79
+ redis_logger.level = Logger.const_get(redis_logger_level)
80
+
81
+ # Event logger supposed to be overridden per task,
82
+ # the default one does nothing
83
+ @event_log = EventLog.new
84
+
85
+ # by default keep only last 500 tasks in disk
86
+ @max_tasks = config.fetch("max_tasks", 500).to_i
87
+
88
+ @max_threads = config.fetch("max_threads", 32).to_i
89
+
90
+ self.redis_options= {
91
+ :host => config["redis"]["host"],
92
+ :port => config["redis"]["port"],
93
+ :password => config["redis"]["password"],
94
+ :logger => redis_logger
95
+ }
96
+
97
+ @revision = get_revision
98
+
99
+ @logger.info("Starting BOSH Director: #{VERSION} (#{@revision})")
100
+
101
+ @process_uuid = SecureRandom.uuid
102
+ @nats_uri = config["mbus"]
103
+
104
+ @cloud_options = config["cloud"]
105
+ @compiled_package_cache_options = config["compiled_package_cache"]
106
+ @name = config["name"] || ""
107
+
108
+ @compiled_package_cache = nil
109
+
110
+ @db_config = config['db']
111
+ @db = configure_db(config["db"])
112
+ @dns = config["dns"]
113
+ @dns_domain_name = "bosh"
114
+ if @dns
115
+ @dns_db = configure_db(@dns["db"]) if @dns["db"]
116
+ @dns_domain_name = canonical(@dns["domain_name"]) if @dns["domain_name"]
117
+ end
118
+
119
+ @uuid = override_uuid || retrieve_uuid
120
+ @logger.info("Director UUID: #{@uuid}")
121
+
122
+ @encryption = config["encryption"]
123
+ @fix_stateful_nodes = config.fetch("scan_and_fix", {})
124
+ .fetch("auto_fix_stateful_nodes", false)
125
+ @enable_snapshots = config.fetch('snapshots', {}).fetch('enabled', false)
126
+
127
+ Bosh::Clouds::Config.configure(self)
128
+
129
+ @lock = Monitor.new
130
+ end
131
+
132
+ def log_dir
133
+ File.dirname(@log_device.filename) if @log_device.filename
134
+ end
135
+
136
+ def use_compiled_package_cache?
137
+ !@compiled_package_cache_options.nil?
138
+ end
139
+
140
+ def get_revision
141
+ Dir.chdir(File.expand_path("../../../../../..", __FILE__))
142
+ revision_command = "(cat REVISION 2> /dev/null || " +
143
+ "git show-ref --head --hash=8 2> /dev/null || " +
144
+ "echo 00000000) | head -n1"
145
+ `#{revision_command}`.strip
146
+ end
147
+
148
+ def configure_db(db_config)
149
+ patch_sqlite if db_config["adapter"] == "sqlite"
150
+
151
+ connection_options = db_config.delete('connection_options') {{}}
152
+ db_config.delete_if { |_, v| v.to_s.empty? }
153
+ db_config = db_config.merge(connection_options)
154
+
155
+ db = Sequel.connect(db_config)
156
+ if logger
157
+ db.logger = logger
158
+ db.sql_log_level = :debug
159
+ end
160
+
161
+ db
162
+ end
163
+
164
+ def compiled_package_cache_blobstore
165
+ @lock.synchronize do
166
+ if @compiled_package_cache_blobstore.nil? && use_compiled_package_cache?
167
+ provider = @compiled_package_cache_options["provider"]
168
+ options = @compiled_package_cache_options["options"]
169
+ @compiled_package_cache_blobstore = Bosh::Blobstore::Client.create(provider, options)
170
+ end
171
+ end
172
+ @compiled_package_cache_blobstore
173
+ end
174
+
175
+ def compiled_package_cache_provider
176
+ use_compiled_package_cache? ? @compiled_package_cache_options["provider"] : nil
177
+ end
178
+
179
+ def cloud_type
180
+ if @cloud_options
181
+ @cloud_options["plugin"]
182
+ end
183
+ end
184
+
185
+ def cloud
186
+ @lock.synchronize do
187
+ if @cloud.nil?
188
+ plugin = @cloud_options["plugin"]
189
+ properties = @cloud_options["properties"]
190
+ @cloud = Bosh::Clouds::Provider.create(plugin, properties)
191
+ end
192
+ end
193
+ @cloud
194
+ end
195
+
196
+ def logger=(logger)
197
+ @logger = logger
198
+ redis_options[:logger] = @logger
199
+ if redis?
200
+ redis.client.logger = @logger
201
+ end
202
+ end
203
+
204
+ def job_cancelled?
205
+ @current_job.task_checkpoint if @current_job
206
+ end
207
+ alias_method :task_checkpoint, :job_cancelled?
208
+
209
+
210
+ def redis_options
211
+ @redis_options ||= {}
212
+ end
213
+
214
+ def redis_options=(options)
215
+ @redis_options = options
216
+ end
217
+
218
+ def cloud_options=(options)
219
+ @lock.synchronize do
220
+ @cloud_options = options
221
+ @cloud = nil
222
+ end
223
+ end
224
+
225
+ def nats
226
+ @lock.synchronize do
227
+ if @nats.nil?
228
+ @nats = NATS.connect(:uri => @nats_uri, :autostart => false)
229
+ end
230
+ end
231
+ @nats
232
+ end
233
+
234
+ def nats_rpc
235
+ @lock.synchronize do
236
+ if @nats_rpc.nil?
237
+ @nats_rpc = NatsRpc.new
238
+ end
239
+ end
240
+ @nats_rpc
241
+ end
242
+
243
+ def redis
244
+ threaded[:redis] ||= Redis.new(redis_options)
245
+ end
246
+
247
+ def redis?
248
+ !threaded[:redis].nil?
249
+ end
250
+
251
+ def dns_enabled?
252
+ !@dns_db.nil?
253
+ end
254
+
255
+ def encryption?
256
+ @encryption
257
+ end
258
+
259
+ def threaded
260
+ Thread.current[:bosh] ||= {}
261
+ end
262
+
263
+ def patch_sqlite
264
+ return if @patched_sqlite
265
+ @patched_sqlite = true
266
+
267
+ require "sequel"
268
+ require "sequel/adapters/sqlite"
269
+
270
+ Sequel::SQLite::Database.class_eval do
271
+ def connect(server)
272
+ opts = server_opts(server)
273
+ opts[:database] = ':memory:' if blank_object?(opts[:database])
274
+ db = ::SQLite3::Database.new(opts[:database])
275
+ db.busy_handler do |retries|
276
+ Bosh::Director::Config.logger.debug "SQLITE BUSY, retry ##{retries}"
277
+ sleep(0.1)
278
+ retries < 20
279
+ end
280
+
281
+ connection_pragmas.each { |s| log_yield(s) { db.execute_batch(s) } }
282
+
283
+ class << db
284
+ attr_reader :prepared_statements
285
+ end
286
+ db.instance_variable_set(:@prepared_statements, {})
287
+
288
+ db
289
+ end
290
+ end
291
+ end
292
+
293
+ def retrieve_uuid
294
+ directors = Bosh::Director::Models::DirectorAttribute.all
295
+ director = directors.first
296
+
297
+ if directors.size > 1
298
+ @logger.warn("More than one UUID stored in director table, using #{director.uuid}")
299
+ end
300
+
301
+ unless director
302
+ director = Bosh::Director::Models::DirectorAttribute.new
303
+ director.uuid = gen_uuid
304
+ director.save
305
+ @logger.info("Generated director UUID #{director.uuid}")
306
+ end
307
+
308
+ director.uuid
309
+ end
310
+
311
+ def override_uuid
312
+ new_uuid = nil
313
+
314
+ if File.exists?(state_file)
315
+ open(state_file, 'r+') do |file|
316
+
317
+ # lock before read to avoid director/worker race condition
318
+ file.flock(File::LOCK_EX)
319
+ state = Yajl::Parser.parse(file) || {}
320
+ # empty state file to prevent blocked processes from attempting to set UUID
321
+ file.truncate(0)
322
+
323
+ if state["uuid"]
324
+ Bosh::Director::Models::DirectorAttribute.delete
325
+ director = Bosh::Director::Models::DirectorAttribute.new
326
+ director.uuid = state["uuid"]
327
+ director.save
328
+ @logger.info("Using director UUID #{state["uuid"]} from #{state_file}")
329
+ new_uuid = state["uuid"]
330
+ end
331
+
332
+ # unlock after storing UUID
333
+ file.flock(File::LOCK_UN)
334
+ end
335
+
336
+ FileUtils.rm_f(state_file)
337
+ end
338
+
339
+ new_uuid
340
+ end
341
+
342
+ def state_file
343
+ File.join(base_dir, "state.json")
344
+ end
345
+
346
+ def gen_uuid
347
+ SecureRandom.uuid
348
+ end
349
+
350
+ end
351
+
352
+ class << self
353
+ def load_file(path)
354
+ Config.new(Psych.load_file(path))
355
+ end
356
+ def load_hash(hash)
357
+ Config.new(hash)
358
+ end
359
+ end
360
+
361
+ attr_reader :hash
362
+
363
+ private
364
+
365
+ def initialize(hash)
366
+ @hash = hash
367
+ end
368
+
369
+ end
370
+ end
@@ -0,0 +1,114 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ class ConfigurationHasher
5
+ # @param [DeploymentPlan::Job]
6
+ def initialize(job)
7
+ @job = job
8
+ @logger = Config.logger
9
+ end
10
+
11
+ # @param [DeploymentPlan::Template] template Template to extract
12
+ # @return [String] Path to a directory where template has been extracted
13
+ def extract_template(template)
14
+ temp_path = template.download_blob
15
+ template_dir = Dir.mktmpdir("template_dir")
16
+
17
+ output = `tar -C #{template_dir} -xzf #{temp_path} 2>&1`
18
+ if $?.exitstatus != 0
19
+ raise JobTemplateUnpackFailed,
20
+ "Cannot unpack `#{template.name}' job template, " +
21
+ "tar returned #{$?.exitstatus}, " +
22
+ "tar output: #{output}"
23
+ end
24
+
25
+ template_dir
26
+ ensure
27
+ FileUtils.rm_f(temp_path) if temp_path
28
+ end
29
+
30
+ # @param [DeploymentPlan::Template]
31
+ def process_template(job_template)
32
+ template_dir = extract_template(job_template)
33
+ manifest = Psych.load_file(File.join(template_dir, "job.MF"))
34
+
35
+ monit_template = erb(File.join(template_dir, "monit"))
36
+ monit_template.filename = File.join(job_template.name, "monit")
37
+
38
+ templates = {}
39
+
40
+ if manifest["templates"]
41
+ manifest["templates"].each_key do |template_name|
42
+ template = erb(File.join(template_dir, "templates", template_name))
43
+ templates[template_name] = template
44
+ end
45
+ end
46
+
47
+ @cached_templates[job_template.name] = {
48
+ "templates" => templates,
49
+ "monit_template" => monit_template
50
+ }
51
+ ensure
52
+ FileUtils.rm_rf(template_dir) if template_dir
53
+ end
54
+
55
+ def hash
56
+ @cached_templates = {}
57
+ sorted_jobs = @job.templates.sort { |x, y| x.name <=> y.name }
58
+ sorted_jobs.each do |job_template|
59
+ process_template(job_template)
60
+ end
61
+ @job.instances.each do |instance|
62
+ instance_digest = Digest::SHA1.new
63
+ template_digests = {}
64
+ sorted_jobs.each do |job_template|
65
+ templates = @cached_templates[job_template.name]["templates"]
66
+ monit_template =
67
+ @cached_templates[job_template.name]["monit_template"]
68
+
69
+ binding_helper = Bosh::Common::TemplateEvaluationContext.new(
70
+ instance.spec)
71
+
72
+ bound_templates = bind_template(monit_template, binding_helper,
73
+ instance.index)
74
+
75
+ templates.keys.sort.each do |template_name|
76
+ template = templates[template_name]
77
+ template.filename = File.join(job_template.name, template_name)
78
+ bound_templates << bind_template(template, binding_helper,
79
+ instance.index)
80
+ template_digest = Digest::SHA1.new
81
+ template_digest << bound_templates
82
+ instance_digest << bound_templates
83
+ template_digests[job_template.name] = template_digest.hexdigest
84
+ end
85
+ end
86
+ instance.configuration_hash = instance_digest.hexdigest
87
+ instance.template_hashes = template_digests
88
+ end
89
+ end
90
+
91
+ def bind_template(template, binding_helper, index)
92
+ template.result(binding_helper.get_binding)
93
+ rescue Exception => e
94
+ @logger.debug(e.inspect)
95
+ job_desc = "#{@job.name}/#{index}"
96
+ line_index = e.backtrace.index{ |l| l.include?(template.filename) }
97
+ line = line_index ? e.backtrace[line_index] : '(unknown):(unknown)'
98
+ template_name, line = line.split(':')
99
+
100
+ message = "Error filling in template `#{File.basename(template_name)}' " +
101
+ "for `#{job_desc}' (line #{line}: #{e})"
102
+
103
+ @logger.debug("#{message}\n#{e.backtrace.join("\n")}")
104
+ raise JobTemplateBindingFailed, "#{message}"
105
+ end
106
+
107
+ private
108
+
109
+ def erb(path)
110
+ ERB.new(File.read(path))
111
+ end
112
+
113
+ end
114
+ end