bosh-director 1.5.0.pre.1113
Sign up to get free protection for your applications and to get access to all the features.
- 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,54 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Director
|
4
|
+
class NatsRpc
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@nats = Config.nats
|
8
|
+
@logger = Config.logger
|
9
|
+
@lock = Mutex.new
|
10
|
+
@inbox_name = "director.#{Config.process_uuid}"
|
11
|
+
@requests = {}
|
12
|
+
subscribe_inbox
|
13
|
+
end
|
14
|
+
|
15
|
+
def subscribe_inbox
|
16
|
+
@nats.subscribe("#{@inbox_name}.>") do |message, _, subject|
|
17
|
+
@logger.debug("RECEIVED: #{subject} #{message}")
|
18
|
+
begin
|
19
|
+
request_id = subject.split(".").last
|
20
|
+
callback = @lock.synchronize { @requests.delete(request_id) }
|
21
|
+
if callback
|
22
|
+
message = Yajl::Parser.new.parse(message)
|
23
|
+
callback.call(message)
|
24
|
+
end
|
25
|
+
rescue Exception => e
|
26
|
+
@logger.warn(e.message)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def send_request(client, request, &block)
|
32
|
+
request_id = generate_request_id
|
33
|
+
request["reply_to"] = "#{@inbox_name}.#{request_id}"
|
34
|
+
@lock.synchronize do
|
35
|
+
@requests[request_id] = block
|
36
|
+
end
|
37
|
+
message = Yajl::Encoder.encode(request)
|
38
|
+
@logger.debug("SENT: #{client} #{message}")
|
39
|
+
EM.next_tick do
|
40
|
+
@nats.publish(client, message)
|
41
|
+
end
|
42
|
+
request_id
|
43
|
+
end
|
44
|
+
|
45
|
+
def cancel_request(request_id)
|
46
|
+
@lock.synchronize { @requests.delete(request_id) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_request_id
|
50
|
+
SecureRandom.uuid
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Director
|
4
|
+
##
|
5
|
+
# Network resolution, either existing or one to be fulfilled by {Network}
|
6
|
+
class NetworkReservation
|
7
|
+
include IpUtil
|
8
|
+
|
9
|
+
STATIC = :static
|
10
|
+
DYNAMIC = :dynamic
|
11
|
+
|
12
|
+
USED = :used
|
13
|
+
CAPACITY = :capacity
|
14
|
+
WRONG_TYPE = :wrong_type
|
15
|
+
|
16
|
+
# @return [Integer, nil] ip
|
17
|
+
attr_accessor :ip
|
18
|
+
|
19
|
+
# @return [Symbol, nil] type
|
20
|
+
attr_accessor :type
|
21
|
+
|
22
|
+
# @return [Boolean] reserved
|
23
|
+
attr_accessor :reserved
|
24
|
+
|
25
|
+
# @return [Symbol, nil] reservation error
|
26
|
+
attr_accessor :error
|
27
|
+
|
28
|
+
def self.new_dynamic(ip = nil)
|
29
|
+
new(:type => NetworkReservation::DYNAMIC, :ip => ip)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.new_static(ip = nil)
|
33
|
+
new(:type => NetworkReservation::STATIC, :ip => ip)
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Creates a new network reservation
|
38
|
+
# @param [Hash] options the options to create the reservation from
|
39
|
+
# @option options [Integer, String, NetAddr::CIDR] :ip reservation ip
|
40
|
+
# @option options [Symbol] :type reservation type
|
41
|
+
def initialize(options = {})
|
42
|
+
@ip = options[:ip]
|
43
|
+
@type = options[:type]
|
44
|
+
@reserved = false
|
45
|
+
@error = nil
|
46
|
+
|
47
|
+
@ip = ip_to_i(@ip) if @ip
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# @return [Boolean] returns true if this is a static reservation
|
52
|
+
def static?
|
53
|
+
@type == STATIC
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @return [Boolean] returns true if this is a dynamic reservation
|
58
|
+
def dynamic?
|
59
|
+
@type == DYNAMIC
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# @return [Boolean] returns true if this reservation was fulfilled
|
64
|
+
def reserved?
|
65
|
+
!!@reserved
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Tries to take the provided reservation if it meets the requirements
|
70
|
+
# @return [void]
|
71
|
+
def take(other)
|
72
|
+
if other.reserved?
|
73
|
+
if @type == other.type
|
74
|
+
if dynamic? || (static? && @ip == other.ip)
|
75
|
+
@ip = other.ip
|
76
|
+
@reserved = true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Handles network reservation error and re-raises the proper exception
|
84
|
+
# @param [String] origin Whoever tried to take the reservation
|
85
|
+
# @raise [NetworkReservationAlreadyInUse]
|
86
|
+
# @raise [NetworkReservationWrongType]
|
87
|
+
# @raise [NetworkReservationNotEnoughCapacity]
|
88
|
+
# @raise [NetworkReservationError]
|
89
|
+
# @return void
|
90
|
+
def handle_error(origin)
|
91
|
+
if static?
|
92
|
+
formatted_ip = ip_to_netaddr(@ip).ip
|
93
|
+
case @error
|
94
|
+
when NetworkReservation::USED
|
95
|
+
raise NetworkReservationAlreadyInUse,
|
96
|
+
"#{origin} asked for a static IP #{formatted_ip} " +
|
97
|
+
"but it's already reserved/in use"
|
98
|
+
when NetworkReservation::WRONG_TYPE
|
99
|
+
raise NetworkReservationWrongType,
|
100
|
+
"#{origin} asked for a static IP #{formatted_ip} " +
|
101
|
+
"but it's in the dynamic pool"
|
102
|
+
else
|
103
|
+
raise NetworkReservationError,
|
104
|
+
"#{origin} failed to reserve static IP " +
|
105
|
+
"#{formatted_ip}: #{@error}"
|
106
|
+
end
|
107
|
+
else
|
108
|
+
case @error
|
109
|
+
when NetworkReservation::CAPACITY
|
110
|
+
raise NetworkReservationNotEnoughCapacity,
|
111
|
+
"#{origin} asked for a dynamic IP " +
|
112
|
+
"but there were no more available"
|
113
|
+
else
|
114
|
+
raise NetworkReservationError,
|
115
|
+
"#{origin} failed to reserve dynamic IP " +
|
116
|
+
"#{formatted_ip}: #{@error}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bosh::Director
|
2
|
+
class NextRebaseVersion
|
3
|
+
def initialize(existing_versions)
|
4
|
+
@existing_versions = existing_versions
|
5
|
+
end
|
6
|
+
|
7
|
+
def calculate(current_version)
|
8
|
+
current_version = Bosh::Common::VersionNumber.new(current_version)
|
9
|
+
versions = @existing_versions.map { |item| Bosh::Common::VersionNumber.new(item.version) }
|
10
|
+
|
11
|
+
return current_version.to_s if current_version.final?
|
12
|
+
|
13
|
+
latest = versions.select { |version|
|
14
|
+
version.major == current_version.major
|
15
|
+
}.max
|
16
|
+
|
17
|
+
latest ? latest.next_minor.dev.to_s : "#{current_version.major}.1-dev"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,423 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Director
|
4
|
+
class PackageCompiler
|
5
|
+
include LockHelper
|
6
|
+
|
7
|
+
attr_reader :compilations_performed
|
8
|
+
|
9
|
+
# @param [DeploymentPlan] deployment_plan Deployment plan
|
10
|
+
def initialize(deployment_plan)
|
11
|
+
@deployment_plan = deployment_plan
|
12
|
+
|
13
|
+
@cloud = Config.cloud
|
14
|
+
@event_log = Config.event_log
|
15
|
+
@logger = Config.logger
|
16
|
+
@director_job = Config.current_job
|
17
|
+
|
18
|
+
@tasks_mutex = Mutex.new
|
19
|
+
@network_mutex = Mutex.new
|
20
|
+
@counter_mutex = Mutex.new
|
21
|
+
|
22
|
+
compilation_config = @deployment_plan.compilation
|
23
|
+
|
24
|
+
@network = compilation_config.network
|
25
|
+
@compilation_resources = compilation_config.cloud_properties
|
26
|
+
@compilation_env = compilation_config.env
|
27
|
+
|
28
|
+
@vm_reuser = VmReuser.new
|
29
|
+
|
30
|
+
@compile_tasks = {}
|
31
|
+
@ready_tasks = []
|
32
|
+
@compilations_performed = 0
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Integer] How many compile tasks are present
|
36
|
+
def compile_tasks_count
|
37
|
+
@compile_tasks.size
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Integer] How many compile tasks are ready
|
41
|
+
def ready_tasks_count
|
42
|
+
@tasks_mutex.synchronize { @ready_tasks.size }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generates compilation tasks for all packages in all job templates included
|
46
|
+
# in the current deployment and kicks off compilation.
|
47
|
+
# @return [void]
|
48
|
+
def compile
|
49
|
+
@logger.info("Generating a list of compile tasks")
|
50
|
+
prepare_tasks
|
51
|
+
|
52
|
+
@compile_tasks.each_value do |task|
|
53
|
+
if task.ready_to_compile?
|
54
|
+
@logger.info("Package `#{task.package.desc}' is ready to be " +
|
55
|
+
"compiled for stemcell `#{task.stemcell.desc}'")
|
56
|
+
@ready_tasks << task
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if @ready_tasks.empty?
|
61
|
+
@logger.info("All packages are already compiled")
|
62
|
+
else
|
63
|
+
compile_packages
|
64
|
+
director_job_checkpoint
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Generates all compilation tasks required to compile all packages
|
69
|
+
# in the jobs defined by deployment plan
|
70
|
+
# @return [void]
|
71
|
+
def prepare_tasks
|
72
|
+
@event_log.begin_stage("Preparing package compilation")
|
73
|
+
|
74
|
+
@event_log.track("Finding packages to compile") do
|
75
|
+
@deployment_plan.jobs.each do |job|
|
76
|
+
job_desc = "#{job.release.name}/#{job.name}"
|
77
|
+
stemcell = job.resource_pool.stemcell
|
78
|
+
|
79
|
+
@logger.info("Job `#{job_desc}' needs to run " +
|
80
|
+
"on stemcell `#{stemcell.model.desc}'")
|
81
|
+
|
82
|
+
job.templates.each do |template|
|
83
|
+
template.package_models.each do |package|
|
84
|
+
generate_compile_task(job, package, stemcell.model)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Generates compilation task for a given (package, stemcell) tuple
|
92
|
+
# @param [DeploymentPlan::Job] job Job spec
|
93
|
+
# @param [Models::Package] package Package model
|
94
|
+
# @param [Models::Stemcell] stemcell Stemcell model
|
95
|
+
# @return [CompileTask] Compilation task for this package/stemcell tuple
|
96
|
+
def generate_compile_task(job, package, stemcell)
|
97
|
+
# Our assumption here is that package dependency graph
|
98
|
+
# has no cycles: this is being enforced on release upload.
|
99
|
+
# Other than that it's a vanilla DFS.
|
100
|
+
|
101
|
+
@logger.info("Checking whether package `#{package.desc}' needs " +
|
102
|
+
"to be compiled for stemcell `#{stemcell.desc}'")
|
103
|
+
task_key = [package.id, stemcell.id]
|
104
|
+
task = @compile_tasks[task_key]
|
105
|
+
|
106
|
+
if task # We already visited this task and its dependencies
|
107
|
+
task.add_job(job) # But we still need to register this job with task
|
108
|
+
return task
|
109
|
+
end
|
110
|
+
|
111
|
+
dependencies = package.dependency_set.map do |name|
|
112
|
+
job.release.get_package_model_by_name(name)
|
113
|
+
end
|
114
|
+
|
115
|
+
task = CompileTask.new(package, stemcell, dependencies, job)
|
116
|
+
|
117
|
+
compiled_package = find_compiled_package(task)
|
118
|
+
if compiled_package
|
119
|
+
task.use_compiled_package(compiled_package)
|
120
|
+
end
|
121
|
+
|
122
|
+
@logger.info("Processing package `#{package.desc}' dependencies")
|
123
|
+
dependencies.each do |dependency|
|
124
|
+
@logger.info("Package `#{package.desc}' depends on " +
|
125
|
+
"package `#{dependency.desc}'")
|
126
|
+
dependency_task = generate_compile_task(job, dependency, stemcell)
|
127
|
+
task.add_dependency(dependency_task)
|
128
|
+
end
|
129
|
+
|
130
|
+
@compile_tasks[task_key] = task
|
131
|
+
task
|
132
|
+
end
|
133
|
+
|
134
|
+
def reserve_network
|
135
|
+
reservation = NetworkReservation.new_dynamic
|
136
|
+
|
137
|
+
@network_mutex.synchronize do
|
138
|
+
@network.reserve(reservation)
|
139
|
+
end
|
140
|
+
|
141
|
+
if !reservation.reserved?
|
142
|
+
raise PackageCompilationNetworkNotReserved,
|
143
|
+
"Could not reserve network for package compilation: " +
|
144
|
+
reservation.error.to_s
|
145
|
+
end
|
146
|
+
|
147
|
+
reservation
|
148
|
+
end
|
149
|
+
|
150
|
+
def release_network(reservation)
|
151
|
+
@network_mutex.synchronize do
|
152
|
+
@network.release(reservation)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def compile_packages
|
157
|
+
@event_log.begin_stage("Compiling packages", compilation_count)
|
158
|
+
number_of_workers = @deployment_plan.compilation.workers
|
159
|
+
|
160
|
+
begin
|
161
|
+
ThreadPool.new(:max_threads => number_of_workers).wrap do |pool|
|
162
|
+
loop do
|
163
|
+
# process as many tasks without waiting
|
164
|
+
loop do
|
165
|
+
break if director_job_cancelled?
|
166
|
+
task = @tasks_mutex.synchronize { @ready_tasks.pop }
|
167
|
+
break if task.nil?
|
168
|
+
|
169
|
+
pool.process { process_task(task) }
|
170
|
+
end
|
171
|
+
|
172
|
+
break if !pool.working? && @ready_tasks.empty?
|
173
|
+
sleep(0.1)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
ensure
|
177
|
+
# Delete all of the VMs if we were reusing compilation VMs. This can't
|
178
|
+
# happen until everything was done compiling.
|
179
|
+
if @deployment_plan.compilation.reuse_compilation_vms
|
180
|
+
# Using a new ThreadPool instead of reusing the previous one,
|
181
|
+
# as if there's a failed compilation, the thread pool will stop
|
182
|
+
# processing any new thread.
|
183
|
+
ThreadPool.new(:max_threads => number_of_workers).wrap do |pool|
|
184
|
+
@vm_reuser.each do |vm_data|
|
185
|
+
pool.process { tear_down_vm(vm_data) }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def process_task(task)
|
193
|
+
package_desc = task.package.desc
|
194
|
+
stemcell_desc = task.stemcell.desc
|
195
|
+
task_desc = "package `#{package_desc}' for stemcell `#{stemcell_desc}'"
|
196
|
+
|
197
|
+
with_thread_name("compile_package(#{package_desc}, #{stemcell_desc})") do
|
198
|
+
if director_job_cancelled?
|
199
|
+
@logger.info("Cancelled compiling #{task_desc}")
|
200
|
+
else
|
201
|
+
@event_log.track(package_desc) do
|
202
|
+
@logger.info("Compiling #{task_desc}")
|
203
|
+
compile_package(task)
|
204
|
+
@logger.info("Finished compiling #{task_desc}")
|
205
|
+
enqueue_unblocked_tasks(task)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def compile_package(task)
|
212
|
+
package = task.package
|
213
|
+
stemcell = task.stemcell
|
214
|
+
|
215
|
+
with_compile_lock(package.id, stemcell.id) do
|
216
|
+
# Check if the package was compiled in a parallel deployment
|
217
|
+
compiled_package = find_compiled_package(task)
|
218
|
+
if compiled_package.nil?
|
219
|
+
build = Models::CompiledPackage.generate_build_number(package, stemcell)
|
220
|
+
task_result = nil
|
221
|
+
|
222
|
+
prepare_vm(stemcell) do |vm_data|
|
223
|
+
vm_metadata_updater.update(vm_data.vm, :compiling => package.name)
|
224
|
+
agent_task =
|
225
|
+
vm_data.agent.compile_package(package.blobstore_id,
|
226
|
+
package.sha1, package.name,
|
227
|
+
"#{package.version}.#{build}",
|
228
|
+
task.dependency_spec)
|
229
|
+
task_result = agent_task["result"]
|
230
|
+
end
|
231
|
+
|
232
|
+
compiled_package = Models::CompiledPackage.create do |p|
|
233
|
+
p.package = package
|
234
|
+
p.stemcell = stemcell
|
235
|
+
p.sha1 = task_result["sha1"]
|
236
|
+
p.build = build
|
237
|
+
p.blobstore_id = task_result["blobstore_id"]
|
238
|
+
p.dependency_key = task.dependency_key
|
239
|
+
end
|
240
|
+
|
241
|
+
if Config.use_compiled_package_cache?
|
242
|
+
if BlobUtil.exists_in_global_cache?(package, task.cache_key)
|
243
|
+
@logger.info("Already exists in global package cache, skipping upload")
|
244
|
+
else
|
245
|
+
@logger.info("Uploading to global package cache")
|
246
|
+
BlobUtil.save_to_global_cache(compiled_package, task.cache_key)
|
247
|
+
end
|
248
|
+
else
|
249
|
+
@logger.info("Global blobstore not configured, skipping upload")
|
250
|
+
end
|
251
|
+
|
252
|
+
@counter_mutex.synchronize { @compilations_performed += 1 }
|
253
|
+
end
|
254
|
+
|
255
|
+
task.use_compiled_package(compiled_package)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def enqueue_unblocked_tasks(task)
|
260
|
+
@tasks_mutex.synchronize do
|
261
|
+
@logger.info("Unblocking dependents of " +
|
262
|
+
"`#{task.package.desc}` for `#{task.stemcell.desc}`")
|
263
|
+
task.dependent_tasks.each do |dep_task|
|
264
|
+
if dep_task.ready_to_compile?
|
265
|
+
@logger.info("Package `#{dep_task.package.desc}' now ready to be " +
|
266
|
+
"compiled for `#{dep_task.stemcell.desc}'")
|
267
|
+
@ready_tasks << dep_task
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# This method will create a VM for each stemcell in the stemcells array
|
274
|
+
# passed in. The VMs are yielded and their destruction is ensured.
|
275
|
+
# @param [Models::Stemcell] stemcell The stemcells that need to have
|
276
|
+
# compilation VMs created.
|
277
|
+
# @yield [VmData] Yields a VmData object that contains all the data for the
|
278
|
+
# VM that should be used for compilation. This may be a reused VM or a
|
279
|
+
# freshly created VM.
|
280
|
+
def prepare_vm(stemcell)
|
281
|
+
# If we're reusing VMs, try to just return an already-created VM.
|
282
|
+
if @deployment_plan.compilation.reuse_compilation_vms
|
283
|
+
vm_data = @vm_reuser.get_vm(stemcell)
|
284
|
+
if vm_data
|
285
|
+
@logger.info("Reusing compilation VM `#{vm_data.vm.cid}' for " +
|
286
|
+
"stemcell `#{stemcell.desc}'")
|
287
|
+
begin
|
288
|
+
yield vm_data
|
289
|
+
ensure
|
290
|
+
vm_data.release
|
291
|
+
end
|
292
|
+
return
|
293
|
+
end
|
294
|
+
# This shouldn't happen. If it does there's a bug.
|
295
|
+
if @vm_reuser.get_num_vms(stemcell) >=
|
296
|
+
@deployment_plan.compilation.workers
|
297
|
+
raise PackageCompilationNotEnoughWorkersForReuse,
|
298
|
+
"There should never be more VMs for a stemcell than the " +
|
299
|
+
"number of workers in reuse_compilation_vms mode"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
@logger.info("Creating compilation VM for stemcell `#{stemcell.desc}'")
|
304
|
+
|
305
|
+
reservation = reserve_network
|
306
|
+
|
307
|
+
network_settings = {
|
308
|
+
@network.name => @network.network_settings(reservation)
|
309
|
+
}
|
310
|
+
|
311
|
+
vm = VmCreator.create(@deployment_plan.model, stemcell,
|
312
|
+
@compilation_resources, network_settings,
|
313
|
+
nil, @compilation_env)
|
314
|
+
vm_data = @vm_reuser.add_vm(reservation, vm, stemcell, network_settings)
|
315
|
+
|
316
|
+
@logger.info("Configuring compilation VM: #{vm.cid}")
|
317
|
+
|
318
|
+
begin
|
319
|
+
agent = AgentClient.new(vm.agent_id)
|
320
|
+
agent.wait_until_ready
|
321
|
+
|
322
|
+
configure_vm(vm, agent, network_settings)
|
323
|
+
vm_data.agent = agent
|
324
|
+
yield vm_data
|
325
|
+
rescue RpcTimeout => e
|
326
|
+
# if we time out waiting for the agent, we should clean up the the VM
|
327
|
+
# as it will leave us in an unrecoverable state otherwise
|
328
|
+
@vm_reuser.remove_vm(vm_data)
|
329
|
+
tear_down_vm(vm_data)
|
330
|
+
raise e
|
331
|
+
ensure
|
332
|
+
vm_data.release
|
333
|
+
unless @deployment_plan.compilation.reuse_compilation_vms
|
334
|
+
tear_down_vm(vm_data)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# Tears down a VM and releases the network reservations.
|
340
|
+
# @param [VmData] vm_data The VmData object for the VM to tear down.
|
341
|
+
def tear_down_vm(vm_data)
|
342
|
+
vm = vm_data.vm
|
343
|
+
if vm.exists?
|
344
|
+
reservation = vm_data.reservation
|
345
|
+
@logger.info("Deleting compilation VM: #{vm.cid}")
|
346
|
+
@cloud.delete_vm(vm.cid)
|
347
|
+
vm.destroy
|
348
|
+
release_network(reservation)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# @param [CompileTask] task
|
353
|
+
# @return [Models::CompiledPackage]
|
354
|
+
def find_compiled_package(task)
|
355
|
+
package = task.package
|
356
|
+
stemcell = task.stemcell
|
357
|
+
dependency_key = task.dependency_key
|
358
|
+
|
359
|
+
# Check if this package is already compiled
|
360
|
+
compiled_package = Models::CompiledPackage[
|
361
|
+
:package_id => package.id,
|
362
|
+
:stemcell_id => stemcell.id,
|
363
|
+
:dependency_key => dependency_key
|
364
|
+
]
|
365
|
+
if compiled_package
|
366
|
+
@logger.info("Found compiled version of package `#{package.desc}' " +
|
367
|
+
"for stemcell `#{stemcell.desc}'")
|
368
|
+
else
|
369
|
+
if Config.use_compiled_package_cache?
|
370
|
+
if BlobUtil.exists_in_global_cache?(package, task.cache_key)
|
371
|
+
@event_log.track("Downloading '#{package.desc}' from global cache") do
|
372
|
+
# has side effect of putting CompiledPackage model in db
|
373
|
+
compiled_package = BlobUtil.fetch_from_global_cache(package, stemcell, task.cache_key, dependency_key)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
if compiled_package
|
379
|
+
@logger.info("Package `Found compiled version of package `#{package.desc}'" +
|
380
|
+
"for stemcell `#{stemcell.desc}' in global cache")
|
381
|
+
else
|
382
|
+
@logger.info("Package `#{package.desc}' " +
|
383
|
+
"needs to be compiled on `#{stemcell.desc}'")
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
compiled_package
|
388
|
+
end
|
389
|
+
|
390
|
+
def director_job_cancelled?
|
391
|
+
@director_job && @director_job.task_cancelled?
|
392
|
+
end
|
393
|
+
|
394
|
+
def director_job_checkpoint
|
395
|
+
@director_job.task_checkpoint if @director_job
|
396
|
+
end
|
397
|
+
|
398
|
+
def configure_vm(vm, agent, network_settings)
|
399
|
+
state = {
|
400
|
+
"deployment" => @deployment_plan.name,
|
401
|
+
"resource_pool" => "package_compiler",
|
402
|
+
"networks" => network_settings
|
403
|
+
}
|
404
|
+
|
405
|
+
vm.update(:apply_spec => state)
|
406
|
+
agent.apply(state)
|
407
|
+
end
|
408
|
+
|
409
|
+
def compilation_count
|
410
|
+
counter = 0
|
411
|
+
@compile_tasks.each_value do |task|
|
412
|
+
counter += 1 unless task.compiled?
|
413
|
+
end
|
414
|
+
counter
|
415
|
+
end
|
416
|
+
|
417
|
+
private
|
418
|
+
|
419
|
+
def vm_metadata_updater
|
420
|
+
@vm_metadata_updater ||= VmMetadataUpdater.build
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|