bosh-director 1.5.0.pre.1113

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 (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,67 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module IpUtil
5
+
6
+ def each_ip(ranges, &block)
7
+ if ranges.kind_of?(Array)
8
+ ranges.each do |range|
9
+ process_range(range, &block)
10
+ end
11
+ elsif ranges.kind_of?(String)
12
+ process_range(ranges, &block)
13
+ elsif !ranges.nil?
14
+ raise ArgumentError,
15
+ "Unknown range type, must be list or a string: " +
16
+ "#{ranges.class} #{ranges}"
17
+ end
18
+ end
19
+
20
+ def process_range(range)
21
+ parts = range.split("-")
22
+ parts.each { |part| part.strip! }
23
+ if parts.size == 1
24
+ range = NetAddr::CIDR.create(parts[0])
25
+ first_ip = range.first(:Objectify => true).to_i
26
+ last_ip = range.last(:Objectify => true).to_i
27
+ (first_ip .. last_ip).each do |ip|
28
+ yield ip
29
+ end
30
+ elsif parts.size == 2
31
+ first_ip = NetAddr::CIDR.create(parts[0])
32
+ last_ip = NetAddr::CIDR.create(parts[1])
33
+ raise ArgumentError unless first_ip.size == 1
34
+ raise ArgumentError unless last_ip.size == 1
35
+ (first_ip.to_i .. last_ip.to_i).each do |ip|
36
+ yield ip
37
+ end
38
+ else
39
+ raise ArgumentError
40
+ end
41
+ end
42
+
43
+ def ip_to_i(ip)
44
+ unless ip.kind_of?(Integer)
45
+ unless ip.kind_of?(NetAddr::CIDR)
46
+ ip = NetAddr::CIDR.create(ip)
47
+ end
48
+ ip = ip.to_i
49
+ end
50
+ ip
51
+ end
52
+
53
+ def ip_to_netaddr(ip)
54
+ unless ip.kind_of?(NetAddr::CIDR)
55
+ ip = NetAddr::CIDR.create(ip)
56
+ end
57
+ ip
58
+ end
59
+
60
+ # @param [Integer] ip Integer IP representation
61
+ # @return [String] Human-readable IP representation
62
+ def format_ip(ip)
63
+ ip_to_netaddr(ip).ip
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,16 @@
1
+ module Bosh::Director
2
+
3
+ # Abstracts the resque system.
4
+
5
+ class JobQueue
6
+ include Api::TaskHelper
7
+
8
+ def enqueue(user, job_class, description, params)
9
+ task = create_task(user, job_class.job_type, description)
10
+
11
+ Resque.enqueue(job_class, task.id, *params)
12
+
13
+ task
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,162 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ class JobRunner
5
+
6
+ # @param [Class] job_class Job class to instantiate and run
7
+ # @param [Integer] task_id Existing task id
8
+ def initialize(job_class, task_id)
9
+ unless job_class.kind_of?(Class) &&
10
+ job_class <= Jobs::BaseJob
11
+ raise DirectorError, "Invalid director job class `#{job_class}'"
12
+ end
13
+
14
+ task_manager = Bosh::Director::Api::TaskManager.new
15
+
16
+ @job_class = job_class
17
+ @task = task_manager.find_task(task_id)
18
+
19
+ setup_logging
20
+ end
21
+
22
+ # Runs director job
23
+ def run(*args)
24
+ Config.current_job = nil
25
+
26
+ @debug_logger.info("Starting task: #{@task.id}")
27
+ started_at = Time.now
28
+
29
+ with_thread_name("task:#{@task.id}") { perform_job(*args) }
30
+
31
+ duration = Duration.duration(Time.now - started_at)
32
+ @debug_logger.info("Task took #{duration} to process.")
33
+ end
34
+
35
+ # Task checkpoint: updates timestamp so running task isn't marked as
36
+ # timed out.
37
+ # @return [void]
38
+ def checkpoint
39
+ @task.update(:checkpoint_time => Time.now)
40
+ end
41
+
42
+ private
43
+
44
+ # Sets up job logging.
45
+ # @return [void]
46
+ def setup_logging
47
+ # It's up to a caller to set up task output directory
48
+ unless @task.output && File.directory?(@task.output)
49
+ raise DirectorError,
50
+ "Task directory `#{@task.output}' is missing"
51
+ end
52
+
53
+ debug_log = File.join(@task.output, "debug")
54
+ event_log = File.join(@task.output, "event")
55
+ result_log = File.join(@task.output, "result")
56
+
57
+ @debug_logger = Logger.new(debug_log)
58
+ @debug_logger.level = Config.logger.level
59
+ @debug_logger.formatter = ThreadFormatter.new
60
+
61
+ Config.event_log = EventLog.new(event_log)
62
+ Config.result = TaskResultFile.new(result_log)
63
+ Config.logger = @debug_logger
64
+
65
+ Config.db.logger = @debug_logger
66
+
67
+ if Config.dns_enabled?
68
+ Config.dns_db.logger = @debug_logger
69
+ end
70
+
71
+ cpi_log = File.join(@task.output, "cpi")
72
+ Config.cloud_options["properties"] ||= {}
73
+ Config.cloud_options["properties"]["cpi_log"] = cpi_log
74
+ end
75
+
76
+ # Instantiates and performs director job.
77
+ # @param [Array] args Opaque list of job arguments that will be used to
78
+ # instantiate the new job object.
79
+ # @return [void]
80
+ def perform_job(*args)
81
+ @debug_logger.info("Creating job")
82
+
83
+ job = @job_class.new(*args)
84
+ Config.current_job = job
85
+
86
+ job.task_id = @task.id
87
+ job.task_checkpoint # cancelled in the queue?
88
+
89
+ run_checkpointing
90
+
91
+ @debug_logger.info("Performing task: #{@task.id}")
92
+
93
+ @task.state = :processing
94
+ @task.timestamp = Time.now
95
+ @task.checkpoint_time = Time.now
96
+ @task.save
97
+
98
+ result = job.perform
99
+
100
+ @debug_logger.info("Done")
101
+ finish_task(:done, result)
102
+
103
+ rescue Bosh::Director::TaskCancelled => e
104
+ log_exception(e)
105
+ @debug_logger.info("Task #{@task.id} cancelled")
106
+ finish_task(:cancelled, "task cancelled")
107
+ rescue Exception => e
108
+ log_exception(e)
109
+ @debug_logger.error("#{e}\n#{e.backtrace.join("\n")}")
110
+ finish_task(:error, e)
111
+ end
112
+
113
+ # Spawns a thread that periodically updates task checkpoint time.
114
+ # There is no need to kill this thread as job execution lifetime is the
115
+ # same as Resque worker process lifetime.
116
+ # @return [Thread] Checkpoint thread
117
+ def run_checkpointing
118
+ Thread.new do
119
+ with_thread_name("task:#{@task.id}-checkpoint") do
120
+ while true
121
+ sleep(Config.task_checkpoint_interval)
122
+ checkpoint
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ # Truncates string to fit task result length
129
+ # @param [String] string The original string
130
+ # @param [Integer] len Desired string length
131
+ # @return [String] Truncated string
132
+ def truncate(string, len = 128)
133
+ stripped = string.strip[0..len]
134
+ if stripped.length > len
135
+ stripped.gsub(/\s+?(\S+)?$/, "") + "..."
136
+ else
137
+ stripped
138
+ end
139
+ end
140
+
141
+ # Marks task completion
142
+ # @param [Symbol] state Task completion state
143
+ # @param [#to_s] result
144
+ def finish_task(state, result)
145
+ @task.state = state
146
+ @task.result = truncate(result.to_s)
147
+ @task.timestamp = Time.now
148
+ @task.save
149
+ end
150
+
151
+ # Logs the exception in the event log
152
+ # @param [Exception] exception
153
+ def log_exception(exception)
154
+ # Event log is being used here to propagate the error.
155
+ # It's up to event log renderer to find the error and
156
+ # signal it properly.
157
+ director_error = DirectorError.create_from_exception(exception)
158
+ Config.event_log.log_error(director_error)
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,121 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+
5
+ class JobUpdater
6
+
7
+ # @param [Bosh::Director::DeploymentPlan] deployment_plan
8
+ # @param [DeploymentPlan::Job] job
9
+ def initialize(deployment_plan, job)
10
+ @deployment_plan = deployment_plan
11
+ @job = job
12
+ @cloud = Config.cloud
13
+ @logger = Config.logger
14
+ @event_log = Config.event_log
15
+ end
16
+
17
+ def delete_unneeded_instances
18
+ @logger.info("Deleting no longer needed instances")
19
+ unneeded_instances = @job.unneeded_instances
20
+
21
+ return if unneeded_instances.empty?
22
+
23
+ @event_log.begin_stage("Deleting unneeded instances",
24
+ unneeded_instances.size, [@job.name])
25
+ InstanceDeleter.new(@deployment_plan).
26
+ delete_instances(unneeded_instances,
27
+ :max_threads => @job.update.max_in_flight)
28
+
29
+ @logger.info("Deleted no longer needed instances")
30
+ end
31
+
32
+ def update
33
+ delete_unneeded_instances
34
+
35
+ instances = []
36
+ @job.instances.each do |instance|
37
+ instances << instance if instance.changed?
38
+ end
39
+
40
+ if instances.empty?
41
+ @logger.info("No instances to update for `#{@job.name}'")
42
+ return
43
+ end
44
+
45
+ @logger.info("Found #{instances.size} instances to update")
46
+
47
+ @event_log.begin_stage("Updating job", instances.size, [ @job.name ])
48
+
49
+ ThreadPool.new(:max_threads => @job.update.max_in_flight).wrap do |pool|
50
+ num_canaries = [ @job.update.canaries, instances.size ].min
51
+
52
+ @logger.info("Starting canary update")
53
+ # Canaries first
54
+ num_canaries.times do
55
+ instance = instances.shift
56
+
57
+ pool.process do
58
+ desc = "#{@job.name}/#{instance.index}"
59
+ @event_log.track("#{desc} (canary)") do |ticker|
60
+ with_thread_name("canary_update(#{desc})") do
61
+ unless @job.should_halt?
62
+ begin
63
+ InstanceUpdater.new(instance, ticker).
64
+ update(:canary => true)
65
+ rescue Exception => e
66
+ @logger.error("Error updating canary instance: #{e}\n" +
67
+ "#{e.backtrace.join("\n")}")
68
+ @job.record_update_error(e, :canary => true)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ pool.wait
77
+ @logger.info("Finished canary update")
78
+
79
+ if @job.should_halt?
80
+ @logger.warn("Halting deployment due to a canary failure")
81
+ halt
82
+ end
83
+
84
+ # Continue with the rest of the updates
85
+ @logger.info("Continuing the rest of the update")
86
+ instances.each do |instance|
87
+ pool.process do
88
+ desc = "#{@job.name}/#{instance.index}"
89
+ @event_log.track(desc) do |ticker|
90
+ with_thread_name("instance_update(#{desc})") do
91
+ unless @job.should_halt?
92
+ begin
93
+ InstanceUpdater.new(instance, ticker).update
94
+ rescue Exception => e
95
+ @logger.error("Error updating instance: #{e}\n" +
96
+ "#{e.backtrace.join("\n")}")
97
+ @job.record_update_error(e)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ @logger.info("Finished the rest of the update")
107
+
108
+ if @job.should_halt?
109
+ @logger.warn("Halting deployment due to an update failure")
110
+ halt
111
+ end
112
+ end
113
+
114
+ def halt
115
+ error = @job.halt_exception ||
116
+ RuntimeError.new("Deployment has been halted")
117
+ raise error
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,86 @@
1
+ module Bosh::Director
2
+ module Jobs
3
+ class Backup < BaseJob
4
+ @queue = :normal
5
+
6
+ def self.job_type
7
+ :bosh_backup
8
+ end
9
+
10
+ attr_reader :backup_file
11
+
12
+ def initialize(dest, options={})
13
+ @backup_file = dest
14
+ @tar_gzipper = options.fetch(:tar_gzipper) { TarGzipper.new }
15
+ @blobstore_client = options.fetch(:blobstore) { App.instance.blobstores.blobstore }
16
+ @db_adapter = options.fetch(:db_adapter) { Bosh::Director::DbBackup.create(Config.db_config) }
17
+ @base_dir = options.fetch(:base_dir) { Config.base_dir }
18
+ @log_dir = options.fetch(:log_dir) { Config.log_dir }
19
+ end
20
+
21
+ def perform
22
+ Dir.mktmpdir do |tmp_output_dir|
23
+ event_log.begin_stage('Backing up director', 4)
24
+
25
+ files = []
26
+
27
+ if @log_dir
28
+ backup_logs("#{tmp_output_dir}/logs.tgz")
29
+ files << 'logs.tgz'
30
+ end
31
+
32
+ backup_task_logs("#{tmp_output_dir}/task_logs.tgz")
33
+ files << 'task_logs.tgz'
34
+
35
+ backup_database("#{tmp_output_dir}/director_db.sql")
36
+ files << 'director_db.sql'
37
+
38
+ backup_blobstore("#{tmp_output_dir}/blobs.tgz")
39
+ files << 'blobs.tgz'
40
+
41
+ @tar_gzipper.compress(tmp_output_dir, files, @backup_file)
42
+
43
+ "Backup created at #{@backup_file}"
44
+ end
45
+ end
46
+
47
+ private
48
+ def backup_logs(output)
49
+ track_and_log('Backing up logs') do
50
+ @tar_gzipper.compress(File.dirname(@log_dir), [File.basename(@log_dir)], output, copy_first: true)
51
+ end
52
+ end
53
+
54
+ def backup_task_logs(output)
55
+ track_and_log('Backing up task logs') do
56
+ @tar_gzipper.compress(@base_dir, %w(tasks), output, copy_first: true)
57
+ end
58
+ end
59
+
60
+ def backup_database(output)
61
+ track_and_log('Backing up database') do
62
+ @db_adapter.export(output)
63
+ end
64
+ end
65
+
66
+ def backup_blobstore(output)
67
+ Dir.mktmpdir do |tmp_dir|
68
+ Dir.mkdir(File.join(tmp_dir, 'blobs'))
69
+
70
+ track_and_log('Backing up blobstore') do
71
+ [Models::Package.all, Models::CompiledPackage.all, Models::Template.all].each do |packages|
72
+ packages.each do |package|
73
+ File.open(File.join(tmp_dir, 'blobs', package.blobstore_id), 'w') do |file|
74
+ logger.debug("Writing file #{file.path}")
75
+ @blobstore_client.get(package.blobstore_id, file)
76
+ end
77
+ end
78
+ end
79
+
80
+ @tar_gzipper.compress(tmp_dir, 'blobs', output)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end