bosh-director 1.2941.0 → 1.2949.0
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.
- checksums.yaml +4 -4
- data/lib/bosh/director.rb +0 -1
- data/lib/bosh/director/api/controllers/deployments_controller.rb +1 -1
- data/lib/bosh/director/config.rb +4 -8
- data/lib/bosh/director/deployment_plan.rb +4 -2
- data/lib/bosh/director/deployment_plan/assembler.rb +3 -2
- data/lib/bosh/director/deployment_plan/deployment_spec_parser.rb +30 -17
- data/lib/bosh/director/deployment_plan/planner.rb +30 -4
- data/lib/bosh/director/deployment_plan/steps/package_compile_step.rb +340 -0
- data/lib/bosh/director/deployment_plan/steps/prepare_step.rb +56 -0
- data/lib/bosh/director/deployment_plan/steps/update_step.rb +70 -0
- data/lib/bosh/director/errand/deployment_preparer.rb +5 -8
- data/lib/bosh/director/jobs/run_errand.rb +1 -1
- data/lib/bosh/director/jobs/update_deployment.rb +62 -86
- data/lib/bosh/director/lock_helper.rb +3 -44
- data/lib/bosh/director/models/cloud_config.rb +8 -0
- data/lib/bosh/director/models/deployment.rb +1 -1
- data/lib/bosh/director/version.rb +1 -1
- metadata +24 -24
- data/lib/bosh/director/deployment_plan/preparer.rb +0 -54
- data/lib/bosh/director/deployment_plan/updater.rb +0 -50
- data/lib/bosh/director/package_compiler.rb +0 -339
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2d58f426d00ab34e503324a356f32419e8ec589
|
|
4
|
+
data.tar.gz: 50c33061600de723b450e53aee4234e0f84f98b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b4108244748cffa5cd372f29faddc1504f6859904bb95b6eb6ce1a86531f832e6dab33dfa2070e3df9455a3be29716512dce4b4c3b68ea2bdbaa2ded74ac8bd
|
|
7
|
+
data.tar.gz: aa4dddfd9fd057e4e62f5835e85487bbb4ae18ab4f926acc852cd5eb1cee6ac9f591cfd027067265ef7fef948b3e03e765a482edcf472ea897a87449c841c9c0
|
data/lib/bosh/director.rb
CHANGED
|
@@ -81,7 +81,6 @@ require 'bosh/director/job_queue'
|
|
|
81
81
|
require 'bosh/director/lock'
|
|
82
82
|
require 'bosh/director/nats_rpc'
|
|
83
83
|
require 'bosh/director/network_reservation'
|
|
84
|
-
require 'bosh/director/package_compiler'
|
|
85
84
|
require 'bosh/director/problem_scanner/scanner'
|
|
86
85
|
require 'bosh/director/problem_resolver'
|
|
87
86
|
require 'bosh/director/resource_pool_updater'
|
|
@@ -294,7 +294,7 @@ module Bosh::Director
|
|
|
294
294
|
deployment = @deployment_manager.find_by_name(params[:deployment_name])
|
|
295
295
|
|
|
296
296
|
manifest = Psych.load(deployment.manifest)
|
|
297
|
-
deployment_plan = DeploymentPlan::Planner.parse(manifest, {}, Config.event_log, Config.logger)
|
|
297
|
+
deployment_plan = DeploymentPlan::Planner.parse(manifest, deployment.cloud_config, {}, Config.event_log, Config.logger)
|
|
298
298
|
|
|
299
299
|
errands = deployment_plan.jobs.select(&:can_run_as_errand?)
|
|
300
300
|
|
data/lib/bosh/director/config.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Bosh::Director
|
|
|
10
10
|
class << self
|
|
11
11
|
include DnsHelper
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
attr_accessor(
|
|
14
14
|
:base_dir,
|
|
15
15
|
:cloud_options,
|
|
16
16
|
:db,
|
|
@@ -33,17 +33,13 @@ module Bosh::Director
|
|
|
33
33
|
:enable_snapshots,
|
|
34
34
|
:max_vm_create_tries,
|
|
35
35
|
:nats_uri,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
CONFIG_OPTIONS.each do |option|
|
|
39
|
-
attr_accessor option
|
|
40
|
-
end
|
|
36
|
+
)
|
|
41
37
|
|
|
42
38
|
attr_reader :db_config, :redis_logger_level
|
|
43
39
|
|
|
44
40
|
def clear
|
|
45
|
-
|
|
46
|
-
self.instance_variable_set(
|
|
41
|
+
self.instance_variables.each do |ivar|
|
|
42
|
+
self.instance_variable_set(ivar, nil)
|
|
47
43
|
end
|
|
48
44
|
|
|
49
45
|
Thread.list.each do |thr|
|
|
@@ -10,11 +10,9 @@ require 'bosh/director/deployment_plan/job'
|
|
|
10
10
|
require 'bosh/director/deployment_plan/network'
|
|
11
11
|
require 'bosh/director/deployment_plan/network_subnet'
|
|
12
12
|
require 'bosh/director/deployment_plan/compiled_package'
|
|
13
|
-
require 'bosh/director/deployment_plan/preparer'
|
|
14
13
|
require 'bosh/director/deployment_plan/resource_pools'
|
|
15
14
|
require 'bosh/director/deployment_plan/instance_vm_binder'
|
|
16
15
|
require 'bosh/director/deployment_plan/multi_job_updater'
|
|
17
|
-
require 'bosh/director/deployment_plan/updater'
|
|
18
16
|
require 'bosh/director/deployment_plan/release_version'
|
|
19
17
|
require 'bosh/director/deployment_plan/resource_pool'
|
|
20
18
|
require 'bosh/director/deployment_plan/stemcell'
|
|
@@ -26,3 +24,7 @@ require 'bosh/director/deployment_plan/vip_network'
|
|
|
26
24
|
require 'bosh/director/deployment_plan/planner'
|
|
27
25
|
require 'bosh/director/deployment_plan/dns_binder'
|
|
28
26
|
require 'bosh/director/deployment_plan/notifier'
|
|
27
|
+
require 'bosh/director/deployment_plan/steps/prepare_step'
|
|
28
|
+
require 'bosh/director/deployment_plan/steps/update_step'
|
|
29
|
+
require 'bosh/director/deployment_plan/steps/package_compile_step'
|
|
30
|
+
|
|
@@ -23,8 +23,9 @@ module Bosh::Director
|
|
|
23
23
|
# Binds release DB record(s) to a plan
|
|
24
24
|
# @return [void]
|
|
25
25
|
def bind_releases
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
releases = @deployment_plan.releases
|
|
27
|
+
with_release_locks(releases.map(&:name)) do
|
|
28
|
+
releases.each do |release|
|
|
28
29
|
release.bind_model
|
|
29
30
|
end
|
|
30
31
|
end
|
|
@@ -13,13 +13,17 @@ module Bosh::Director
|
|
|
13
13
|
|
|
14
14
|
# @param [Hash] manifest Raw deployment manifest
|
|
15
15
|
# @return [DeploymentPlan::Planner] Deployment as build from deployment_spec
|
|
16
|
-
def parse(manifest, options = {})
|
|
17
|
-
@
|
|
16
|
+
def parse(manifest, cloud_config, options = {})
|
|
17
|
+
@deployment_manifest = manifest
|
|
18
|
+
if cloud_config.nil?
|
|
19
|
+
@cloud_manifest = cloud_manifest_from_deployment_manifest @deployment_manifest
|
|
20
|
+
else
|
|
21
|
+
@cloud_manifest = cloud_config.manifest
|
|
22
|
+
end
|
|
18
23
|
|
|
19
|
-
@job_states = safe_property(options, 'job_states',
|
|
20
|
-
:class => Hash, :default => {})
|
|
24
|
+
@job_states = safe_property(options, 'job_states', :class => Hash, :default => {})
|
|
21
25
|
|
|
22
|
-
@deployment = Planner.new(parse_name, options)
|
|
26
|
+
@deployment = Planner.new(parse_name, manifest, cloud_config, options)
|
|
23
27
|
|
|
24
28
|
parse_properties
|
|
25
29
|
parse_releases
|
|
@@ -35,27 +39,36 @@ module Bosh::Director
|
|
|
35
39
|
|
|
36
40
|
private
|
|
37
41
|
|
|
42
|
+
CLOUD_MANIFEST_KEYS = ['resource_pools','compilation','disk_pools','networks']
|
|
43
|
+
def cloud_manifest_from_deployment_manifest(deployment_manifest)
|
|
44
|
+
cloud_manifest = {}
|
|
45
|
+
CLOUD_MANIFEST_KEYS.each do |key|
|
|
46
|
+
cloud_manifest[key] = deployment_manifest[key] if deployment_manifest.has_key? key
|
|
47
|
+
end
|
|
48
|
+
cloud_manifest
|
|
49
|
+
end
|
|
50
|
+
|
|
38
51
|
def parse_name
|
|
39
|
-
safe_property(@
|
|
52
|
+
safe_property(@deployment_manifest, 'name', :class => String)
|
|
40
53
|
end
|
|
41
54
|
|
|
42
55
|
def parse_properties
|
|
43
|
-
@deployment.properties = safe_property(@
|
|
56
|
+
@deployment.properties = safe_property(@deployment_manifest, 'properties',
|
|
44
57
|
:class => Hash, :default => {})
|
|
45
58
|
end
|
|
46
59
|
|
|
47
60
|
def parse_releases
|
|
48
61
|
release_specs = []
|
|
49
62
|
|
|
50
|
-
if @
|
|
51
|
-
if @
|
|
63
|
+
if @deployment_manifest.has_key?('release')
|
|
64
|
+
if @deployment_manifest.has_key?('releases')
|
|
52
65
|
raise DeploymentAmbiguousReleaseSpec,
|
|
53
66
|
"Deployment manifest contains both 'release' and 'releases' " +
|
|
54
67
|
'sections, please use one of the two.'
|
|
55
68
|
end
|
|
56
|
-
release_specs << @
|
|
69
|
+
release_specs << @deployment_manifest['release']
|
|
57
70
|
else
|
|
58
|
-
safe_property(@
|
|
71
|
+
safe_property(@deployment_manifest, 'releases', :class => Array).each do |release|
|
|
59
72
|
release_specs << release
|
|
60
73
|
end
|
|
61
74
|
end
|
|
@@ -66,7 +79,7 @@ module Bosh::Director
|
|
|
66
79
|
end
|
|
67
80
|
|
|
68
81
|
def parse_networks
|
|
69
|
-
networks = safe_property(@
|
|
82
|
+
networks = safe_property(@cloud_manifest, 'networks', :class => Array)
|
|
70
83
|
networks.each do |network_spec|
|
|
71
84
|
type = safe_property(network_spec, 'type', :class => String,
|
|
72
85
|
:default => 'manual')
|
|
@@ -92,17 +105,17 @@ module Bosh::Director
|
|
|
92
105
|
end
|
|
93
106
|
|
|
94
107
|
def parse_compilation
|
|
95
|
-
compilation_spec = safe_property(@
|
|
108
|
+
compilation_spec = safe_property(@cloud_manifest, 'compilation', :class => Hash)
|
|
96
109
|
@deployment.compilation = CompilationConfig.new(@deployment, compilation_spec)
|
|
97
110
|
end
|
|
98
111
|
|
|
99
112
|
def parse_update
|
|
100
|
-
update_spec = safe_property(@
|
|
113
|
+
update_spec = safe_property(@deployment_manifest, 'update', :class => Hash)
|
|
101
114
|
@deployment.update = UpdateConfig.new(update_spec)
|
|
102
115
|
end
|
|
103
116
|
|
|
104
117
|
def parse_resource_pools
|
|
105
|
-
resource_pools = safe_property(@
|
|
118
|
+
resource_pools = safe_property(@cloud_manifest, 'resource_pools', :class => Array)
|
|
106
119
|
resource_pools.each do |rp_spec|
|
|
107
120
|
@deployment.add_resource_pool(ResourcePool.new(@deployment, rp_spec, @logger))
|
|
108
121
|
end
|
|
@@ -112,7 +125,7 @@ module Bosh::Director
|
|
|
112
125
|
end
|
|
113
126
|
|
|
114
127
|
def parse_disk_pools
|
|
115
|
-
disk_pools = safe_property(@
|
|
128
|
+
disk_pools = safe_property(@cloud_manifest, 'disk_pools', :class => Array, :optional => true)
|
|
116
129
|
return if disk_pools.nil?
|
|
117
130
|
disk_pools.each do |dp_spec|
|
|
118
131
|
@deployment.add_disk_pool(DiskPool.parse(dp_spec))
|
|
@@ -120,7 +133,7 @@ module Bosh::Director
|
|
|
120
133
|
end
|
|
121
134
|
|
|
122
135
|
def parse_jobs
|
|
123
|
-
jobs = safe_property(@
|
|
136
|
+
jobs = safe_property(@deployment_manifest, 'jobs', :class => Array, :default => [])
|
|
124
137
|
jobs.each do |job_spec|
|
|
125
138
|
state_overrides = @job_states[job_spec['name']]
|
|
126
139
|
if state_overrides
|
|
@@ -6,6 +6,7 @@ module Bosh::Director
|
|
|
6
6
|
# from the deployment manifest and the running environment.
|
|
7
7
|
module DeploymentPlan
|
|
8
8
|
class Planner
|
|
9
|
+
include LockHelper
|
|
9
10
|
include DnsHelper
|
|
10
11
|
include ValidationHelper
|
|
11
12
|
|
|
@@ -53,16 +54,18 @@ module Bosh::Director
|
|
|
53
54
|
# @param [Logger]
|
|
54
55
|
# logger Log for director logging
|
|
55
56
|
# @return [Bosh::Director::DeploymentPlan::Planner]
|
|
56
|
-
def self.parse(manifest, options, event_log, logger)
|
|
57
|
+
def self.parse(manifest, cloud_config, options, event_log, logger)
|
|
57
58
|
parser = DeploymentSpecParser.new(event_log, logger)
|
|
58
|
-
parser.parse(manifest, options)
|
|
59
|
+
parser.parse(manifest, cloud_config, options)
|
|
59
60
|
end
|
|
60
61
|
|
|
61
|
-
def initialize(name, options = {})
|
|
62
|
+
def initialize(name, manifest_text, cloud_config, options = {})
|
|
62
63
|
raise ArgumentError, 'name must not be nil' unless name
|
|
63
64
|
@name = name
|
|
64
|
-
@
|
|
65
|
+
@manifest_text = manifest_text
|
|
66
|
+
@cloud_config = cloud_config
|
|
65
67
|
|
|
68
|
+
@model = nil
|
|
66
69
|
@properties = {}
|
|
67
70
|
@releases = {}
|
|
68
71
|
@networks = {}
|
|
@@ -260,6 +263,29 @@ module Bosh::Director
|
|
|
260
263
|
def rename_in_progress?
|
|
261
264
|
@job_rename['old_name'] && @job_rename['new_name']
|
|
262
265
|
end
|
|
266
|
+
|
|
267
|
+
def persist_updates!
|
|
268
|
+
#prior updates may have had release versions that we no longer use.
|
|
269
|
+
#remove the references to these stale releases.
|
|
270
|
+
stale_release_versions = (model.release_versions - releases.map(&:model))
|
|
271
|
+
stale_release_names = stale_release_versions.map {|version_model| version_model.release.name}
|
|
272
|
+
with_release_locks(stale_release_names) do
|
|
273
|
+
stale_release_versions.each do |release_version|
|
|
274
|
+
model.remove_release_version(release_version)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
model.manifest = Psych.dump(@manifest_text)
|
|
279
|
+
model.cloud_config = @cloud_config
|
|
280
|
+
model.save
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def update_stemcell_references!
|
|
284
|
+
current_stemcell_models = resource_pools.map { |pool| pool.stemcell.model }
|
|
285
|
+
model.stemcells.each do |deployment_stemcell|
|
|
286
|
+
deployment_stemcell.remove_deployment(model) unless current_stemcell_models.include?(deployment_stemcell)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
263
289
|
end
|
|
264
290
|
end
|
|
265
291
|
end
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
require 'bosh/director/compile_task_generator'
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
module DeploymentPlan
|
|
5
|
+
module Steps
|
|
6
|
+
class PackageCompileStep
|
|
7
|
+
include LockHelper
|
|
8
|
+
|
|
9
|
+
attr_reader :compilations_performed
|
|
10
|
+
|
|
11
|
+
# @param [DeploymentPlan] deployment_plan Deployment plan
|
|
12
|
+
def initialize(deployment_plan)
|
|
13
|
+
@deployment_plan = deployment_plan
|
|
14
|
+
|
|
15
|
+
@cloud = Config.cloud
|
|
16
|
+
@event_log = Config.event_log
|
|
17
|
+
@logger = Config.logger
|
|
18
|
+
@director_job = Config.current_job
|
|
19
|
+
|
|
20
|
+
@tasks_mutex = Mutex.new
|
|
21
|
+
@network_mutex = Mutex.new
|
|
22
|
+
@counter_mutex = Mutex.new
|
|
23
|
+
|
|
24
|
+
compilation_config = @deployment_plan.compilation
|
|
25
|
+
|
|
26
|
+
@network = compilation_config.network
|
|
27
|
+
@compilation_resources = compilation_config.cloud_properties
|
|
28
|
+
@compilation_env = compilation_config.env
|
|
29
|
+
|
|
30
|
+
@vm_reuser = VmReuser.new
|
|
31
|
+
|
|
32
|
+
@compile_task_generator = CompileTaskGenerator.new(@logger, @event_log)
|
|
33
|
+
|
|
34
|
+
@compile_tasks = {}
|
|
35
|
+
@ready_tasks = []
|
|
36
|
+
@compilations_performed = 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def perform
|
|
40
|
+
@logger.info('Generating a list of compile tasks')
|
|
41
|
+
prepare_tasks
|
|
42
|
+
|
|
43
|
+
@compile_tasks.each_value do |task|
|
|
44
|
+
if task.ready_to_compile?
|
|
45
|
+
@logger.info("Package `#{task.package.desc}' is ready to be compiled for stemcell `#{task.stemcell.desc}'")
|
|
46
|
+
@ready_tasks << task
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if @ready_tasks.empty?
|
|
51
|
+
@logger.info('All packages are already compiled')
|
|
52
|
+
else
|
|
53
|
+
compile_packages
|
|
54
|
+
director_job_checkpoint
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def compile_tasks_count
|
|
59
|
+
@compile_tasks.size
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ready_tasks_count
|
|
63
|
+
@tasks_mutex.synchronize { @ready_tasks.size }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def compile_package(task)
|
|
69
|
+
package = task.package
|
|
70
|
+
stemcell = task.stemcell
|
|
71
|
+
|
|
72
|
+
with_compile_lock(package.id, stemcell.id) do
|
|
73
|
+
# Check if the package was compiled in a parallel deployment
|
|
74
|
+
compiled_package = task.find_compiled_package(@logger, @event_log)
|
|
75
|
+
if compiled_package.nil?
|
|
76
|
+
build = Models::CompiledPackage.generate_build_number(package, stemcell)
|
|
77
|
+
task_result = nil
|
|
78
|
+
|
|
79
|
+
prepare_vm(stemcell) do |vm_data|
|
|
80
|
+
vm_metadata_updater.update(vm_data.vm, :compiling => package.name)
|
|
81
|
+
agent_task =
|
|
82
|
+
vm_data.agent.compile_package(package.blobstore_id,
|
|
83
|
+
package.sha1, package.name,
|
|
84
|
+
"#{package.version}.#{build}",
|
|
85
|
+
task.dependency_spec)
|
|
86
|
+
task_result = agent_task['result']
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
compiled_package = Models::CompiledPackage.create do |p|
|
|
90
|
+
p.package = package
|
|
91
|
+
p.stemcell = stemcell
|
|
92
|
+
p.sha1 = task_result['sha1']
|
|
93
|
+
p.build = build
|
|
94
|
+
p.blobstore_id = task_result['blobstore_id']
|
|
95
|
+
p.dependency_key = task.dependency_key
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if Config.use_compiled_package_cache?
|
|
99
|
+
if BlobUtil.exists_in_global_cache?(package, task.cache_key)
|
|
100
|
+
@logger.info('Already exists in global package cache, skipping upload')
|
|
101
|
+
else
|
|
102
|
+
@logger.info('Uploading to global package cache')
|
|
103
|
+
BlobUtil.save_to_global_cache(compiled_package, task.cache_key)
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
@logger.info('Global blobstore not configured, skipping upload')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
@counter_mutex.synchronize { @compilations_performed += 1 }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
task.use_compiled_package(compiled_package)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# This method will create a VM for each stemcell in the stemcells array
|
|
117
|
+
# passed in. The VMs are yielded and their destruction is ensured.
|
|
118
|
+
# @param [Models::Stemcell] stemcell The stemcells that need to have
|
|
119
|
+
# compilation VMs created.
|
|
120
|
+
# @yield [VmData] Yields a VmData object that contains all the data for the
|
|
121
|
+
# VM that should be used for compilation. This may be a reused VM or a
|
|
122
|
+
# freshly created VM.
|
|
123
|
+
def prepare_vm(stemcell)
|
|
124
|
+
# If we're reusing VMs, try to just return an already-created VM.
|
|
125
|
+
if @deployment_plan.compilation.reuse_compilation_vms
|
|
126
|
+
vm_data = @vm_reuser.get_vm(stemcell)
|
|
127
|
+
if vm_data
|
|
128
|
+
@logger.info("Reusing compilation VM `#{vm_data.vm.cid}' for stemcell `#{stemcell.desc}'")
|
|
129
|
+
begin
|
|
130
|
+
yield vm_data
|
|
131
|
+
ensure
|
|
132
|
+
vm_data.release
|
|
133
|
+
end
|
|
134
|
+
return
|
|
135
|
+
end
|
|
136
|
+
# This shouldn't happen. If it does there's a bug.
|
|
137
|
+
if @vm_reuser.get_num_vms(stemcell) >=
|
|
138
|
+
@deployment_plan.compilation.workers
|
|
139
|
+
raise PackageCompilationNotEnoughWorkersForReuse,
|
|
140
|
+
'There should never be more VMs for a stemcell than the number of workers in reuse_compilation_vms mode'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
@logger.info("Creating compilation VM for stemcell `#{stemcell.desc}'")
|
|
145
|
+
|
|
146
|
+
reservation = reserve_network
|
|
147
|
+
|
|
148
|
+
network_settings = {
|
|
149
|
+
@network.name => @network.network_settings(reservation)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
vm = VmCreator.create(@deployment_plan.model, stemcell,
|
|
153
|
+
@compilation_resources, network_settings,
|
|
154
|
+
nil, @compilation_env)
|
|
155
|
+
vm_data = @vm_reuser.add_vm(reservation, vm, stemcell, network_settings)
|
|
156
|
+
|
|
157
|
+
@logger.info("Configuring compilation VM: #{vm.cid}")
|
|
158
|
+
|
|
159
|
+
begin
|
|
160
|
+
agent = AgentClient.with_defaults(vm.agent_id)
|
|
161
|
+
agent.wait_until_ready
|
|
162
|
+
|
|
163
|
+
configure_vm(vm, agent, network_settings)
|
|
164
|
+
vm_data.agent = agent
|
|
165
|
+
yield vm_data
|
|
166
|
+
rescue RpcTimeout => e
|
|
167
|
+
# if we time out waiting for the agent, we should clean up the the VM
|
|
168
|
+
# as it will leave us in an unrecoverable state otherwise
|
|
169
|
+
@vm_reuser.remove_vm(vm_data)
|
|
170
|
+
tear_down_vm(vm_data)
|
|
171
|
+
raise e
|
|
172
|
+
ensure
|
|
173
|
+
vm_data.release
|
|
174
|
+
unless @deployment_plan.compilation.reuse_compilation_vms
|
|
175
|
+
tear_down_vm(vm_data)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
def prepare_tasks
|
|
183
|
+
@event_log.begin_stage('Preparing package compilation', 1)
|
|
184
|
+
|
|
185
|
+
@event_log.track('Finding packages to compile') do
|
|
186
|
+
@deployment_plan.jobs.each do |job|
|
|
187
|
+
stemcell = job.resource_pool.stemcell
|
|
188
|
+
|
|
189
|
+
template_descs = job.templates.map do |t|
|
|
190
|
+
# we purposefully did NOT inline those because
|
|
191
|
+
# when instance_double blows up,
|
|
192
|
+
# it's obscure which double is at fault
|
|
193
|
+
release_name = t.release.name
|
|
194
|
+
template_name = t.name
|
|
195
|
+
"`#{release_name}/#{template_name}'"
|
|
196
|
+
end
|
|
197
|
+
@logger.info("Job templates #{template_descs.join(', ')} need to run on stemcell `#{stemcell.model.desc}'")
|
|
198
|
+
|
|
199
|
+
job.templates.each do |template|
|
|
200
|
+
template.package_models.each do |package|
|
|
201
|
+
@compile_task_generator.generate!(@compile_tasks, job, template, package, stemcell.model)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def tear_down_vm(vm_data)
|
|
209
|
+
vm = vm_data.vm
|
|
210
|
+
if vm.exists?
|
|
211
|
+
reservation = vm_data.reservation
|
|
212
|
+
@logger.info("Deleting compilation VM: #{vm.cid}")
|
|
213
|
+
@cloud.delete_vm(vm.cid)
|
|
214
|
+
vm.destroy
|
|
215
|
+
release_network(reservation)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def reserve_network
|
|
220
|
+
reservation = NetworkReservation.new_dynamic
|
|
221
|
+
|
|
222
|
+
@network_mutex.synchronize do
|
|
223
|
+
@network.reserve(reservation)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
unless reservation.reserved?
|
|
227
|
+
raise PackageCompilationNetworkNotReserved,
|
|
228
|
+
"Could not reserve network for package compilation: #{reservation.error}"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
reservation
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def release_network(reservation)
|
|
235
|
+
@network_mutex.synchronize do
|
|
236
|
+
@network.release(reservation)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def compile_packages
|
|
241
|
+
@event_log.begin_stage('Compiling packages', compilation_count)
|
|
242
|
+
number_of_workers = @deployment_plan.compilation.workers
|
|
243
|
+
|
|
244
|
+
begin
|
|
245
|
+
ThreadPool.new(:max_threads => number_of_workers).wrap do |pool|
|
|
246
|
+
loop do
|
|
247
|
+
# process as many tasks without waiting
|
|
248
|
+
loop do
|
|
249
|
+
break if director_job_cancelled?
|
|
250
|
+
task = @tasks_mutex.synchronize { @ready_tasks.pop }
|
|
251
|
+
break if task.nil?
|
|
252
|
+
|
|
253
|
+
pool.process { process_task(task) }
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
break if !pool.working? && (director_job_cancelled? || @ready_tasks.empty?)
|
|
257
|
+
sleep(0.1)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
ensure
|
|
261
|
+
# Delete all of the VMs if we were reusing compilation VMs. This can't
|
|
262
|
+
# happen until everything was done compiling.
|
|
263
|
+
if @deployment_plan.compilation.reuse_compilation_vms
|
|
264
|
+
# Using a new ThreadPool instead of reusing the previous one,
|
|
265
|
+
# as if there's a failed compilation, the thread pool will stop
|
|
266
|
+
# processing any new thread.
|
|
267
|
+
ThreadPool.new(:max_threads => number_of_workers).wrap do |pool|
|
|
268
|
+
@vm_reuser.each do |vm_data|
|
|
269
|
+
pool.process { tear_down_vm(vm_data) }
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def enqueue_unblocked_tasks(task)
|
|
277
|
+
@tasks_mutex.synchronize do
|
|
278
|
+
@logger.info("Unblocking dependents of `#{task.package.desc}` for `#{task.stemcell.desc}`")
|
|
279
|
+
task.dependent_tasks.each do |dep_task|
|
|
280
|
+
if dep_task.ready_to_compile?
|
|
281
|
+
@logger.info("Package `#{dep_task.package.desc}' now ready to be compiled for `#{dep_task.stemcell.desc}'")
|
|
282
|
+
@ready_tasks << dep_task
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def process_task(task)
|
|
289
|
+
package_desc = task.package.desc
|
|
290
|
+
stemcell_desc = task.stemcell.desc
|
|
291
|
+
task_desc = "package `#{package_desc}' for stemcell `#{stemcell_desc}'"
|
|
292
|
+
|
|
293
|
+
with_thread_name("compile_package(#{package_desc}, #{stemcell_desc})") do
|
|
294
|
+
if director_job_cancelled?
|
|
295
|
+
@logger.info("Cancelled compiling #{task_desc}")
|
|
296
|
+
else
|
|
297
|
+
@event_log.track(package_desc) do
|
|
298
|
+
@logger.info("Compiling #{task_desc}")
|
|
299
|
+
compile_package(task)
|
|
300
|
+
@logger.info("Finished compiling #{task_desc}")
|
|
301
|
+
enqueue_unblocked_tasks(task)
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def director_job_cancelled?
|
|
308
|
+
@director_job && @director_job.task_cancelled?
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def director_job_checkpoint
|
|
312
|
+
@director_job.task_checkpoint if @director_job
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def configure_vm(vm, agent, network_settings)
|
|
316
|
+
state = {
|
|
317
|
+
'deployment' => @deployment_plan.name,
|
|
318
|
+
'resource_pool' => 'package_compiler',
|
|
319
|
+
'networks' => network_settings
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
vm.update(:apply_spec => state)
|
|
323
|
+
agent.apply(state)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def compilation_count
|
|
327
|
+
counter = 0
|
|
328
|
+
@compile_tasks.each_value do |task|
|
|
329
|
+
counter += 1 unless task.compiled?
|
|
330
|
+
end
|
|
331
|
+
counter
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def vm_metadata_updater
|
|
335
|
+
@vm_metadata_updater ||= VmMetadataUpdater.build
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|