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,29 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
class Blobstores
|
|
5
|
+
|
|
6
|
+
attr_reader :blobstore
|
|
7
|
+
|
|
8
|
+
def initialize(config)
|
|
9
|
+
@blobstore = create_client(config.hash.fetch('blobstore'))
|
|
10
|
+
|
|
11
|
+
bd_config = config.hash['backup_destination']
|
|
12
|
+
@backup_destination = create_client(bd_config) if bd_config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def backup_destination
|
|
16
|
+
raise 'No backup destination configured' unless @backup_destination
|
|
17
|
+
@backup_destination
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def create_client(hash)
|
|
23
|
+
provider = hash.fetch('provider')
|
|
24
|
+
options = hash.fetch('options')
|
|
25
|
+
|
|
26
|
+
Bosh::Blobstore::Client.create(provider, options)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
class Client
|
|
5
|
+
|
|
6
|
+
attr_accessor :id
|
|
7
|
+
|
|
8
|
+
def initialize(service_name, client_id, options = {})
|
|
9
|
+
@service_name = service_name
|
|
10
|
+
@client_id = client_id
|
|
11
|
+
@nats_rpc = Config.nats_rpc
|
|
12
|
+
@timeout = options[:timeout] || 45
|
|
13
|
+
@logger = Config.logger
|
|
14
|
+
@retry_methods = options[:retry_methods] || {}
|
|
15
|
+
|
|
16
|
+
if options[:credentials]
|
|
17
|
+
@encryption_handler =
|
|
18
|
+
Bosh::Core::EncryptionHandler.new(@client_id, options[:credentials])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@resource_manager = Api::ResourceManager.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def method_missing(method_name, *args)
|
|
25
|
+
retries = @retry_methods[method_name] || 0
|
|
26
|
+
begin
|
|
27
|
+
handle_method(method_name, args)
|
|
28
|
+
rescue RpcTimeout
|
|
29
|
+
if retries > 0
|
|
30
|
+
retries -= 1
|
|
31
|
+
retry
|
|
32
|
+
end
|
|
33
|
+
raise
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def wait_until_ready(deadline = 600)
|
|
38
|
+
old_timeout = @timeout
|
|
39
|
+
@timeout = 1.0
|
|
40
|
+
@deadline = Time.now.to_i + deadline
|
|
41
|
+
|
|
42
|
+
begin
|
|
43
|
+
ping
|
|
44
|
+
rescue RpcTimeout
|
|
45
|
+
retry if @deadline - Time.now.to_i > 0
|
|
46
|
+
raise RpcTimeout, "Timed out pinging to #{@client_id} after #{deadline} seconds"
|
|
47
|
+
rescue RpcRemoteException => e
|
|
48
|
+
retry if e.message =~ /^restarting agent/ && @deadline - Time.now.to_i > 0
|
|
49
|
+
raise e
|
|
50
|
+
ensure
|
|
51
|
+
@timeout = old_timeout
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def handle_method(method_name, args)
|
|
56
|
+
result = {}
|
|
57
|
+
result.extend(MonitorMixin)
|
|
58
|
+
|
|
59
|
+
cond = result.new_cond
|
|
60
|
+
timeout_time = Time.now.to_f + @timeout
|
|
61
|
+
|
|
62
|
+
request = {:method => method_name, :arguments => args}
|
|
63
|
+
|
|
64
|
+
if @encryption_handler
|
|
65
|
+
@logger.info("Request: #{request}")
|
|
66
|
+
request = {"encrypted_data" => @encryption_handler.encrypt(request)}
|
|
67
|
+
request["session_id"] = @encryption_handler.session_id
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
recipient = "#{@service_name}.#{@client_id}"
|
|
71
|
+
|
|
72
|
+
request_id = @nats_rpc.send_request(recipient, request) do |response|
|
|
73
|
+
if @encryption_handler
|
|
74
|
+
begin
|
|
75
|
+
response = @encryption_handler.decrypt(response["encrypted_data"])
|
|
76
|
+
rescue Bosh::Core::EncryptionHandler::CryptError => e
|
|
77
|
+
response["exception"] = "CryptError: #{e.inspect} #{e.backtrace}"
|
|
78
|
+
end
|
|
79
|
+
@logger.info("Response: #{response}")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
result.synchronize do
|
|
83
|
+
inject_compile_log(response)
|
|
84
|
+
result.merge!(response)
|
|
85
|
+
cond.signal
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
result.synchronize do
|
|
90
|
+
while result.empty?
|
|
91
|
+
timeout = timeout_time - Time.now.to_f
|
|
92
|
+
unless timeout > 0
|
|
93
|
+
@nats_rpc.cancel_request(request_id)
|
|
94
|
+
raise RpcTimeout,
|
|
95
|
+
"Timed out sending `#{method_name}' to #{@client_id} " +
|
|
96
|
+
"after #{@timeout} seconds"
|
|
97
|
+
end
|
|
98
|
+
cond.wait(timeout)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if result.has_key?("exception")
|
|
103
|
+
raise RpcRemoteException, format_exception(result["exception"])
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
result["value"]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Returns formatted exception information
|
|
110
|
+
# @param [Hash|#to_s] exception Serialized exception
|
|
111
|
+
# @return [String]
|
|
112
|
+
def format_exception(exception)
|
|
113
|
+
return exception.to_s unless exception.is_a?(Hash)
|
|
114
|
+
|
|
115
|
+
msg = exception["message"].to_s
|
|
116
|
+
|
|
117
|
+
if exception["backtrace"]
|
|
118
|
+
msg += "\n"
|
|
119
|
+
msg += Array(exception["backtrace"]).join("\n")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
if exception["blobstore_id"]
|
|
123
|
+
blob = download_and_delete_blob(exception["blobstore_id"])
|
|
124
|
+
msg += "\n"
|
|
125
|
+
msg += blob.to_s
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
msg
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
# the blob is removed from the blobstore once we have fetched it,
|
|
134
|
+
# but if there is a crash before it is injected into the response
|
|
135
|
+
# and then logged, there is a chance that we lose it
|
|
136
|
+
def inject_compile_log(response)
|
|
137
|
+
if response["value"] && response["value"].is_a?(Hash) &&
|
|
138
|
+
response["value"]["result"].is_a?(Hash) &&
|
|
139
|
+
blob_id = response["value"]["result"]["compile_log_id"]
|
|
140
|
+
compile_log = download_and_delete_blob(blob_id)
|
|
141
|
+
response["value"]["result"]["compile_log"] = compile_log
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Downloads blob and ensures it's deleted from the blobstore
|
|
146
|
+
# @param [String] blob_id Blob id
|
|
147
|
+
# @return [String] Blob contents
|
|
148
|
+
def download_and_delete_blob(blob_id)
|
|
149
|
+
blob = @resource_manager.get_resource(blob_id)
|
|
150
|
+
blob
|
|
151
|
+
ensure
|
|
152
|
+
@resource_manager.delete_resource(blob_id)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
module CloudcheckHelper
|
|
5
|
+
# Helper functions that come in handy for
|
|
6
|
+
# cloudcheck:
|
|
7
|
+
# 1. VM/agent interactions
|
|
8
|
+
# 2. VM lifecycle operations (from cloudcheck POV)
|
|
9
|
+
# 3. Error handling
|
|
10
|
+
|
|
11
|
+
# This timeout has been made pretty short mainly
|
|
12
|
+
# to avoid long cloudchecks, however 10 seconds should
|
|
13
|
+
# still be pretty generous interval for agent to respond.
|
|
14
|
+
DEFAULT_AGENT_TIMEOUT = 10
|
|
15
|
+
|
|
16
|
+
def cloud
|
|
17
|
+
Bosh::Director::Config.cloud
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def handler_error(message)
|
|
21
|
+
raise Bosh::Director::ProblemHandlerError, message
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def instance_name(vm)
|
|
25
|
+
instance = vm.instance
|
|
26
|
+
return "Unknown VM" if instance.nil?
|
|
27
|
+
|
|
28
|
+
job = instance.job || "unknown job"
|
|
29
|
+
index = instance.index || "unknown index"
|
|
30
|
+
"#{job}/#{index}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def agent_client(vm, timeout = DEFAULT_AGENT_TIMEOUT, retries = 0)
|
|
34
|
+
options = {
|
|
35
|
+
:timeout => timeout,
|
|
36
|
+
:retry_methods => { :get_state => retries }
|
|
37
|
+
}
|
|
38
|
+
@clients ||= {}
|
|
39
|
+
@clients[vm.agent_id] ||= AgentClient.new(vm.agent_id, options)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def agent_timeout_guard(vm, &block)
|
|
43
|
+
yield agent_client(vm)
|
|
44
|
+
rescue Bosh::Director::RpcTimeout
|
|
45
|
+
handler_error("VM `#{vm.cid}' is not responding")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def reboot_vm(vm)
|
|
49
|
+
cloud.reboot_vm(vm.cid)
|
|
50
|
+
begin
|
|
51
|
+
agent_client(vm).wait_until_ready
|
|
52
|
+
rescue Bosh::Director::RpcTimeout
|
|
53
|
+
handler_error("Agent still unresponsive after reboot")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def delete_vm(vm)
|
|
58
|
+
# Paranoia: don't blindly delete VMs with persistent disk
|
|
59
|
+
disk_list = agent_timeout_guard(vm) { |agent| agent.list_disk }
|
|
60
|
+
if disk_list.size != 0
|
|
61
|
+
handler_error("VM has persistent disk attached")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
cloud.delete_vm(vm.cid)
|
|
65
|
+
vm.db.transaction do
|
|
66
|
+
vm.instance.update(:vm => nil) if vm.instance
|
|
67
|
+
vm.destroy
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def delete_vm_reference(vm, options={})
|
|
72
|
+
if vm.cid && !options[:skip_cid_check]
|
|
73
|
+
handler_error("VM has a CID")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
vm.db.transaction do
|
|
77
|
+
vm.instance.update(:vm => nil) if vm.instance
|
|
78
|
+
vm.destroy
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def recreate_vm(vm)
|
|
83
|
+
# Best we can do without any feedback from the agent
|
|
84
|
+
# is to use the spec persisted in the DB at the time
|
|
85
|
+
# of last apply call.
|
|
86
|
+
# This method is somewhat similar in its nature to what
|
|
87
|
+
# InstanceUpdater is doing in case of the stemcell update,
|
|
88
|
+
# however we don't need to handle some advanced scenarios
|
|
89
|
+
# such as disk migration.
|
|
90
|
+
|
|
91
|
+
spec = validate_spec(vm)
|
|
92
|
+
env = validate_env(vm)
|
|
93
|
+
|
|
94
|
+
resource_pool_spec = spec.fetch("resource_pool", {})
|
|
95
|
+
stemcell = find_stemcell(resource_pool_spec.fetch("stemcell", {}))
|
|
96
|
+
|
|
97
|
+
deployment = vm.deployment
|
|
98
|
+
handler_error("VM doesn't belong to any deployment") unless deployment
|
|
99
|
+
|
|
100
|
+
instance = vm.instance
|
|
101
|
+
disk_cid = instance ? instance.persistent_disk_cid : nil
|
|
102
|
+
|
|
103
|
+
# One situation where this handler is actually useful is when
|
|
104
|
+
# VM has already been deleted but something failed after that
|
|
105
|
+
# and it is still referenced in DB. In that case it makes sense
|
|
106
|
+
# to ignore "VM not found" errors in `delete_vm' and let the method
|
|
107
|
+
# proceed creating a new VM. Other errors are not forgiven.
|
|
108
|
+
begin
|
|
109
|
+
cloud.delete_vm(vm.cid)
|
|
110
|
+
rescue Bosh::Clouds::VMNotFound => e
|
|
111
|
+
@logger.warn("VM '#{vm.cid}' might have already been deleted from the cloud")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
vm.db.transaction do
|
|
115
|
+
instance.update(:vm => nil) if instance
|
|
116
|
+
vm.destroy
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
cloud_properties = resource_pool_spec.fetch("cloud_properties", {})
|
|
120
|
+
networks = spec["networks"]
|
|
121
|
+
new_vm = VmCreator.create(deployment, stemcell, cloud_properties, networks, Array(disk_cid), env)
|
|
122
|
+
new_vm.apply_spec = spec
|
|
123
|
+
new_vm.save
|
|
124
|
+
|
|
125
|
+
if instance
|
|
126
|
+
instance.update(:vm => new_vm)
|
|
127
|
+
|
|
128
|
+
# refresh metadata after new instance has been set
|
|
129
|
+
VmMetadataUpdater.build.update(new_vm, {})
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
agent_client(new_vm).wait_until_ready
|
|
133
|
+
|
|
134
|
+
# After this point agent is actually responding to
|
|
135
|
+
# pings, so if the rest of this handler fails
|
|
136
|
+
# bcck won't find this type of problem again
|
|
137
|
+
# but regular deployment will fail with "out-of-sync"
|
|
138
|
+
# error (as we now have an instance that points to
|
|
139
|
+
# VM that reports empty state). This problem
|
|
140
|
+
# should be handled by "out-of-sync VM" problem handler.
|
|
141
|
+
|
|
142
|
+
if disk_cid
|
|
143
|
+
# N.B. attach_disk might fail if disk image is no longer
|
|
144
|
+
# there or for some other reason. Generally it means
|
|
145
|
+
# the data has been lost (e.g. someone deleted VM from vCenter
|
|
146
|
+
# along with the disk.
|
|
147
|
+
cloud.attach_disk(new_vm.cid, disk_cid)
|
|
148
|
+
agent_client(new_vm).mount_disk(disk_cid)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
agent_client(new_vm).apply(spec)
|
|
152
|
+
|
|
153
|
+
if instance && instance.state == "started"
|
|
154
|
+
agent_client(new_vm).start
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def validate_spec(vm)
|
|
161
|
+
handler_error("Unable to look up VM apply spec") unless vm.apply_spec
|
|
162
|
+
|
|
163
|
+
spec = vm.apply_spec
|
|
164
|
+
|
|
165
|
+
unless spec.kind_of?(Hash)
|
|
166
|
+
handler_error("Invalid apply spec format")
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
spec
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def validate_env(vm)
|
|
173
|
+
handler_error("Unable to look up VM environment") unless vm.env
|
|
174
|
+
|
|
175
|
+
env = vm.env
|
|
176
|
+
|
|
177
|
+
unless env.kind_of?(Hash)
|
|
178
|
+
handler_error("Invalid VM environment format")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
env
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def find_stemcell(stemcell_spec)
|
|
185
|
+
stemcell_name = stemcell_spec['name']
|
|
186
|
+
stemcell_version = stemcell_spec['version']
|
|
187
|
+
|
|
188
|
+
unless stemcell_name && stemcell_version
|
|
189
|
+
handler_error('Unknown stemcell name and/or version')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
stemcell = Models::Stemcell.find(:name => stemcell_name, :version => stemcell_version)
|
|
193
|
+
|
|
194
|
+
handler_error("Unable to find stemcell '#{stemcell_name} #{stemcell_version}'") unless stemcell
|
|
195
|
+
|
|
196
|
+
stemcell
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def generate_agent_id
|
|
200
|
+
SecureRandom.uuid
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
class CompileTask
|
|
5
|
+
# @return [Models::Package] What package is being compiled
|
|
6
|
+
attr_reader :package
|
|
7
|
+
|
|
8
|
+
# @return [Models::Stemcell] What stemcell package is compiled for
|
|
9
|
+
attr_reader :stemcell
|
|
10
|
+
|
|
11
|
+
# @return [Array<DeploymentPlan::Job>] Jobs interested in this package
|
|
12
|
+
attr_reader :jobs
|
|
13
|
+
|
|
14
|
+
# @return [Models::CompiledPackage] Compiled package DB model
|
|
15
|
+
attr_reader :compiled_package
|
|
16
|
+
|
|
17
|
+
# @return [String] Dependency key (changing it will trigger recompilation
|
|
18
|
+
# even when package bits haven't changed)
|
|
19
|
+
attr_accessor :dependency_key
|
|
20
|
+
|
|
21
|
+
# @return [Array<CompileTask>] Tasks this task depends on
|
|
22
|
+
attr_reader :dependencies
|
|
23
|
+
|
|
24
|
+
# @return [Array<CompileTask>] Tasks depending on this task
|
|
25
|
+
attr_reader :dependent_tasks
|
|
26
|
+
|
|
27
|
+
# @return [String] A unique checksum based on the dependencies in this task
|
|
28
|
+
attr_reader :cache_key
|
|
29
|
+
|
|
30
|
+
# @param [Models::Package] package What package is being compiled
|
|
31
|
+
# by this task
|
|
32
|
+
# @param [Models::Stemcell] stemcell What stemcell package is compiled for
|
|
33
|
+
# @param [Array<Models::Package>] dependent_packages Package models that this task depends on
|
|
34
|
+
# @param [DeploymentPlan::Job] initial_job The first job that this task is associate with
|
|
35
|
+
def initialize(package, stemcell, dependent_packages, initial_job = nil)
|
|
36
|
+
@package = package
|
|
37
|
+
@stemcell = stemcell
|
|
38
|
+
|
|
39
|
+
@jobs = []
|
|
40
|
+
add_job(initial_job) if initial_job
|
|
41
|
+
@dependencies = []
|
|
42
|
+
@dependent_tasks = []
|
|
43
|
+
|
|
44
|
+
@dependency_key = generate_dependency_key(dependent_packages)
|
|
45
|
+
|
|
46
|
+
@cache_key = generate_cache_key(dependent_packages)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Boolean] Whether this task is ready to be compiled
|
|
50
|
+
def ready_to_compile?
|
|
51
|
+
!compiled? && all_dependencies_compiled?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Boolean]
|
|
55
|
+
def all_dependencies_compiled?
|
|
56
|
+
@dependencies.all? { |task| task.compiled? }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Boolean]
|
|
60
|
+
def compiled?
|
|
61
|
+
!@compiled_package.nil?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Makes compiled package available to all jobs waiting for it
|
|
65
|
+
# @param [Models::CompiledPackage] compiled_package Compiled package
|
|
66
|
+
# @return [void]
|
|
67
|
+
def use_compiled_package(compiled_package)
|
|
68
|
+
@compiled_package = compiled_package
|
|
69
|
+
|
|
70
|
+
@jobs.each do |job|
|
|
71
|
+
job.use_compiled_package(@compiled_package)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Adds job to a list of job requiring this compiled package
|
|
76
|
+
# @note Cycle detection is done elsewhere
|
|
77
|
+
# @param [DeploymentPlan::Job] job Job to be added
|
|
78
|
+
# @return [void]
|
|
79
|
+
def add_job(job)
|
|
80
|
+
return if @jobs.include?(job)
|
|
81
|
+
@jobs << job
|
|
82
|
+
if @compiled_package
|
|
83
|
+
# If package is already compiled we can make it available to job
|
|
84
|
+
# immediately, otherwise it will be done by #use_compiled_package
|
|
85
|
+
job.use_compiled_package(@compiled_package)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Adds a compilation task to the list of dependencies
|
|
90
|
+
# @note Cycle detection performed elsewhere
|
|
91
|
+
# @param [CompileTask] task Compilation task
|
|
92
|
+
# @param [Boolean] reciprocate If true, add self as dependent task to other
|
|
93
|
+
# @return [void]
|
|
94
|
+
def add_dependency(task, reciprocate=true)
|
|
95
|
+
@dependencies << task
|
|
96
|
+
if reciprocate
|
|
97
|
+
task.add_dependent_task(self, false)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Adds a compilation task to the list of dependent tasks
|
|
102
|
+
# @note Cycle detection performed elsewhere
|
|
103
|
+
# @param [CompileTask] task Compilation task
|
|
104
|
+
# @param [Boolean] reciprocate If true, add self as dependency to to other
|
|
105
|
+
# @return [void]
|
|
106
|
+
def add_dependent_task(task, reciprocate=true)
|
|
107
|
+
@dependent_tasks << task
|
|
108
|
+
if reciprocate
|
|
109
|
+
task.add_dependency(self, false)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# This call only makes sense if all dependencies have already been compiled,
|
|
114
|
+
# otherwise it raises an exception
|
|
115
|
+
# @return [Hash] Hash representation of all package dependencies. Agent uses
|
|
116
|
+
# that to download package dependencies before compiling the package on a
|
|
117
|
+
# compilation VM.
|
|
118
|
+
def dependency_spec
|
|
119
|
+
spec = {}
|
|
120
|
+
|
|
121
|
+
@dependencies.each do |dep_task|
|
|
122
|
+
unless dep_task.compiled?
|
|
123
|
+
raise DirectorError,
|
|
124
|
+
"Cannot generate package dependency spec " +
|
|
125
|
+
"for `#{@package.name}', " +
|
|
126
|
+
"`#{dep_task.package.name}' hasn't been compiled yet"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
compiled_package = dep_task.compiled_package
|
|
130
|
+
|
|
131
|
+
spec[compiled_package.name] = {
|
|
132
|
+
"name" => compiled_package.name,
|
|
133
|
+
"version" => "#{compiled_package.version}.#{compiled_package.build}",
|
|
134
|
+
"sha1" => compiled_package.sha1,
|
|
135
|
+
"blobstore_id" => compiled_package.blobstore_id
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
spec
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private
|
|
143
|
+
def generate_dependency_key(packages)
|
|
144
|
+
key = packages.sort { |a, b|
|
|
145
|
+
a.name <=> b.name
|
|
146
|
+
}.map { |p| [p.name, p.version]}
|
|
147
|
+
|
|
148
|
+
Yajl::Encoder.encode(key)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def generate_cache_key(dependent_packages)
|
|
152
|
+
dependency_fingerprints = dependent_packages.sort_by(&:name).map {|p| p.fingerprint }
|
|
153
|
+
hash_input = ([package.fingerprint, stemcell.sha1]+dependency_fingerprints).join("")
|
|
154
|
+
Digest::SHA1.hexdigest(hash_input)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|