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.
- data/CHANGELOG +34 -0
- data/bin/bosh-director +36 -0
- data/bin/bosh-director-console +84 -0
- data/bin/bosh-director-drain-workers +42 -0
- data/bin/bosh-director-migrate +58 -0
- data/bin/bosh-director-scheduler +27 -0
- data/bin/bosh-director-worker +76 -0
- data/db/migrations/README +1 -0
- data/db/migrations/director/20110209010747_initial.rb +118 -0
- data/db/migrations/director/20110406055800_add_task_user.rb +9 -0
- data/db/migrations/director/20110518225809_remove_cid_constrain.rb +13 -0
- data/db/migrations/director/20110617211923_add_deployments_release_versions.rb +32 -0
- data/db/migrations/director/20110622212607_add_task_checkpoint_timestamp.rb +9 -0
- data/db/migrations/director/20110628023039_add_state_to_instances.rb +21 -0
- data/db/migrations/director/20110709012332_add_disk_size_to_instances.rb +9 -0
- data/db/migrations/director/20110906183441_add_log_bundles.rb +11 -0
- data/db/migrations/director/20110907194830_add_logs_json_to_templates.rb +9 -0
- data/db/migrations/director/20110915205610_add_persistent_disks.rb +51 -0
- data/db/migrations/director/20111005180929_add_properties.rb +14 -0
- data/db/migrations/director/20111110024617_add_deployment_problems.rb +24 -0
- data/db/migrations/director/20111216214145_recreate_support_for_vms.rb +9 -0
- data/db/migrations/director/20120102084027_add_credentials_to_vms.rb +7 -0
- data/db/migrations/director/20120427235217_allow_multiple_releases_per_deployment.rb +36 -0
- data/db/migrations/director/20120524175805_add_task_type.rb +44 -0
- data/db/migrations/director/20120614001930_delete_redundant_deployment_release_relation.rb +34 -0
- data/db/migrations/director/20120822004528_add_fingerprint_to_templates_and_packages.rb +17 -0
- data/db/migrations/director/20120830191244_add_properties_to_templates.rb +9 -0
- data/db/migrations/director/20121106190739_persist_vm_env.rb +9 -0
- data/db/migrations/director/20130222232131_add_sha1_to_stemcells.rb +9 -0
- data/db/migrations/director/20130312211407_add_commit_hash_to_release_versions.rb +19 -0
- data/db/migrations/director/20130409235338_snapshot.rb +15 -0
- data/db/migrations/director/20130530164918_add_paused_flag_to_instance.rb +14 -0
- data/db/migrations/director/20130531172604_add_director_attributes.rb +13 -0
- data/db/migrations/dns/20120123234908_initial.rb +27 -0
- data/lib/bosh/director.rb +133 -0
- data/lib/bosh/director/agent_client.rb +78 -0
- data/lib/bosh/director/api.rb +29 -0
- data/lib/bosh/director/api/api_helper.rb +81 -0
- data/lib/bosh/director/api/backup_manager.rb +15 -0
- data/lib/bosh/director/api/controller.rb +639 -0
- data/lib/bosh/director/api/controller_helpers.rb +34 -0
- data/lib/bosh/director/api/deployment_lookup.rb +13 -0
- data/lib/bosh/director/api/deployment_manager.rb +60 -0
- data/lib/bosh/director/api/http_constants.rb +16 -0
- data/lib/bosh/director/api/instance_lookup.rb +44 -0
- data/lib/bosh/director/api/instance_manager.rb +63 -0
- data/lib/bosh/director/api/problem_manager.rb +40 -0
- data/lib/bosh/director/api/property_manager.rb +69 -0
- data/lib/bosh/director/api/release_manager.rb +59 -0
- data/lib/bosh/director/api/resource_manager.rb +69 -0
- data/lib/bosh/director/api/resurrector_manager.rb +15 -0
- data/lib/bosh/director/api/snapshot_manager.rb +94 -0
- data/lib/bosh/director/api/stemcell_manager.rb +50 -0
- data/lib/bosh/director/api/task_helper.rb +46 -0
- data/lib/bosh/director/api/task_manager.rb +64 -0
- data/lib/bosh/director/api/user_manager.rb +72 -0
- data/lib/bosh/director/api/vm_state_manager.rb +11 -0
- data/lib/bosh/director/app.rb +35 -0
- data/lib/bosh/director/blob_util.rb +87 -0
- data/lib/bosh/director/blobstores.rb +29 -0
- data/lib/bosh/director/client.rb +156 -0
- data/lib/bosh/director/cloudcheck_helper.rb +204 -0
- data/lib/bosh/director/compile_task.rb +157 -0
- data/lib/bosh/director/config.rb +370 -0
- data/lib/bosh/director/configuration_hasher.rb +114 -0
- data/lib/bosh/director/cycle_helper.rb +36 -0
- data/lib/bosh/director/db_backup.rb +22 -0
- data/lib/bosh/director/db_backup/adapter.rb +3 -0
- data/lib/bosh/director/db_backup/adapter/mysql2.rb +27 -0
- data/lib/bosh/director/db_backup/adapter/postgres.rb +36 -0
- data/lib/bosh/director/db_backup/adapter/sqlite.rb +17 -0
- data/lib/bosh/director/db_backup/error.rb +10 -0
- data/lib/bosh/director/deployment_plan.rb +26 -0
- data/lib/bosh/director/deployment_plan/assembler.rb +430 -0
- data/lib/bosh/director/deployment_plan/compilation_config.rb +54 -0
- data/lib/bosh/director/deployment_plan/compiled_package.rb +35 -0
- data/lib/bosh/director/deployment_plan/dynamic_network.rb +91 -0
- data/lib/bosh/director/deployment_plan/idle_vm.rb +109 -0
- data/lib/bosh/director/deployment_plan/instance.rb +413 -0
- data/lib/bosh/director/deployment_plan/job.rb +470 -0
- data/lib/bosh/director/deployment_plan/manual_network.rb +137 -0
- data/lib/bosh/director/deployment_plan/network.rb +74 -0
- data/lib/bosh/director/deployment_plan/network_subnet.rb +167 -0
- data/lib/bosh/director/deployment_plan/planner.rb +288 -0
- data/lib/bosh/director/deployment_plan/preparer.rb +52 -0
- data/lib/bosh/director/deployment_plan/release.rb +126 -0
- data/lib/bosh/director/deployment_plan/resource_pool.rb +143 -0
- data/lib/bosh/director/deployment_plan/resource_pools.rb +68 -0
- data/lib/bosh/director/deployment_plan/stemcell.rb +56 -0
- data/lib/bosh/director/deployment_plan/template.rb +94 -0
- data/lib/bosh/director/deployment_plan/update_config.rb +80 -0
- data/lib/bosh/director/deployment_plan/updater.rb +55 -0
- data/lib/bosh/director/deployment_plan/vip_network.rb +79 -0
- data/lib/bosh/director/dns_helper.rb +204 -0
- data/lib/bosh/director/download_helper.rb +44 -0
- data/lib/bosh/director/duration.rb +36 -0
- data/lib/bosh/director/encryption_helper.rb +10 -0
- data/lib/bosh/director/errors.rb +198 -0
- data/lib/bosh/director/event_log.rb +136 -0
- data/lib/bosh/director/ext.rb +64 -0
- data/lib/bosh/director/hash_string_vals.rb +13 -0
- data/lib/bosh/director/instance_deleter.rb +109 -0
- data/lib/bosh/director/instance_updater.rb +506 -0
- data/lib/bosh/director/ip_util.rb +67 -0
- data/lib/bosh/director/job_queue.rb +16 -0
- data/lib/bosh/director/job_runner.rb +162 -0
- data/lib/bosh/director/job_updater.rb +121 -0
- data/lib/bosh/director/jobs/backup.rb +86 -0
- data/lib/bosh/director/jobs/base_job.rb +66 -0
- data/lib/bosh/director/jobs/cloud_check/apply_resolutions.rb +46 -0
- data/lib/bosh/director/jobs/cloud_check/scan.rb +38 -0
- data/lib/bosh/director/jobs/cloud_check/scan_and_fix.rb +73 -0
- data/lib/bosh/director/jobs/create_snapshot.rb +23 -0
- data/lib/bosh/director/jobs/delete_deployment.rb +183 -0
- data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +34 -0
- data/lib/bosh/director/jobs/delete_release.rb +219 -0
- data/lib/bosh/director/jobs/delete_snapshots.rb +23 -0
- data/lib/bosh/director/jobs/delete_stemcell.rb +102 -0
- data/lib/bosh/director/jobs/fetch_logs.rb +99 -0
- data/lib/bosh/director/jobs/scheduled_backup.rb +38 -0
- data/lib/bosh/director/jobs/snapshot_deployment.rb +61 -0
- data/lib/bosh/director/jobs/snapshot_deployments.rb +23 -0
- data/lib/bosh/director/jobs/snapshot_self.rb +43 -0
- data/lib/bosh/director/jobs/ssh.rb +59 -0
- data/lib/bosh/director/jobs/update_deployment.rb +110 -0
- data/lib/bosh/director/jobs/update_release.rb +672 -0
- data/lib/bosh/director/jobs/update_stemcell.rb +109 -0
- data/lib/bosh/director/jobs/vm_state.rb +89 -0
- data/lib/bosh/director/lock.rb +133 -0
- data/lib/bosh/director/lock_helper.rb +92 -0
- data/lib/bosh/director/models.rb +29 -0
- data/lib/bosh/director/models/compiled_package.rb +33 -0
- data/lib/bosh/director/models/deployment.rb +22 -0
- data/lib/bosh/director/models/deployment_problem.rb +49 -0
- data/lib/bosh/director/models/deployment_property.rb +21 -0
- data/lib/bosh/director/models/director_attribute.rb +9 -0
- data/lib/bosh/director/models/dns.rb +9 -0
- data/lib/bosh/director/models/dns/domain.rb +9 -0
- data/lib/bosh/director/models/dns/record.rb +7 -0
- data/lib/bosh/director/models/helpers/model_helper.rb +7 -0
- data/lib/bosh/director/models/instance.rb +28 -0
- data/lib/bosh/director/models/log_bundle.rb +10 -0
- data/lib/bosh/director/models/package.rb +30 -0
- data/lib/bosh/director/models/persistent_disk.rb +13 -0
- data/lib/bosh/director/models/release.rb +17 -0
- data/lib/bosh/director/models/release_version.rb +16 -0
- data/lib/bosh/director/models/snapshot.rb +13 -0
- data/lib/bosh/director/models/stemcell.rb +18 -0
- data/lib/bosh/director/models/task.rb +10 -0
- data/lib/bosh/director/models/template.rb +44 -0
- data/lib/bosh/director/models/user.rb +11 -0
- data/lib/bosh/director/models/vm.rb +42 -0
- data/lib/bosh/director/nats_rpc.rb +54 -0
- data/lib/bosh/director/network_reservation.rb +121 -0
- data/lib/bosh/director/next_rebase_version.rb +20 -0
- data/lib/bosh/director/package_compiler.rb +423 -0
- data/lib/bosh/director/problem_handlers/base.rb +153 -0
- data/lib/bosh/director/problem_handlers/inactive_disk.rb +112 -0
- data/lib/bosh/director/problem_handlers/invalid_problem.rb +28 -0
- data/lib/bosh/director/problem_handlers/missing_vm.rb +34 -0
- data/lib/bosh/director/problem_handlers/mount_info_mismatch.rb +62 -0
- data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +64 -0
- data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +85 -0
- data/lib/bosh/director/problem_handlers/unresponsive_agent.rb +78 -0
- data/lib/bosh/director/problem_resolver.rb +103 -0
- data/lib/bosh/director/problem_scanner.rb +268 -0
- data/lib/bosh/director/resource_pool_updater.rb +216 -0
- data/lib/bosh/director/scheduler.rb +57 -0
- data/lib/bosh/director/sequel.rb +13 -0
- data/lib/bosh/director/tar_gzipper.rb +47 -0
- data/lib/bosh/director/task_result_file.rb +19 -0
- data/lib/bosh/director/thread_pool.rb +8 -0
- data/lib/bosh/director/validation_helper.rb +55 -0
- data/lib/bosh/director/version.rb +7 -0
- data/lib/bosh/director/vm_creator.rb +80 -0
- data/lib/bosh/director/vm_data.rb +63 -0
- data/lib/bosh/director/vm_metadata_updater.rb +29 -0
- data/lib/bosh/director/vm_reuser.rb +63 -0
- data/lib/cloud/dummy.rb +149 -0
- 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
|