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,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
|