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.
Files changed (180) hide show
  1. data/CHANGELOG +34 -0
  2. data/bin/bosh-director +36 -0
  3. data/bin/bosh-director-console +84 -0
  4. data/bin/bosh-director-drain-workers +42 -0
  5. data/bin/bosh-director-migrate +58 -0
  6. data/bin/bosh-director-scheduler +27 -0
  7. data/bin/bosh-director-worker +76 -0
  8. data/db/migrations/README +1 -0
  9. data/db/migrations/director/20110209010747_initial.rb +118 -0
  10. data/db/migrations/director/20110406055800_add_task_user.rb +9 -0
  11. data/db/migrations/director/20110518225809_remove_cid_constrain.rb +13 -0
  12. data/db/migrations/director/20110617211923_add_deployments_release_versions.rb +32 -0
  13. data/db/migrations/director/20110622212607_add_task_checkpoint_timestamp.rb +9 -0
  14. data/db/migrations/director/20110628023039_add_state_to_instances.rb +21 -0
  15. data/db/migrations/director/20110709012332_add_disk_size_to_instances.rb +9 -0
  16. data/db/migrations/director/20110906183441_add_log_bundles.rb +11 -0
  17. data/db/migrations/director/20110907194830_add_logs_json_to_templates.rb +9 -0
  18. data/db/migrations/director/20110915205610_add_persistent_disks.rb +51 -0
  19. data/db/migrations/director/20111005180929_add_properties.rb +14 -0
  20. data/db/migrations/director/20111110024617_add_deployment_problems.rb +24 -0
  21. data/db/migrations/director/20111216214145_recreate_support_for_vms.rb +9 -0
  22. data/db/migrations/director/20120102084027_add_credentials_to_vms.rb +7 -0
  23. data/db/migrations/director/20120427235217_allow_multiple_releases_per_deployment.rb +36 -0
  24. data/db/migrations/director/20120524175805_add_task_type.rb +44 -0
  25. data/db/migrations/director/20120614001930_delete_redundant_deployment_release_relation.rb +34 -0
  26. data/db/migrations/director/20120822004528_add_fingerprint_to_templates_and_packages.rb +17 -0
  27. data/db/migrations/director/20120830191244_add_properties_to_templates.rb +9 -0
  28. data/db/migrations/director/20121106190739_persist_vm_env.rb +9 -0
  29. data/db/migrations/director/20130222232131_add_sha1_to_stemcells.rb +9 -0
  30. data/db/migrations/director/20130312211407_add_commit_hash_to_release_versions.rb +19 -0
  31. data/db/migrations/director/20130409235338_snapshot.rb +15 -0
  32. data/db/migrations/director/20130530164918_add_paused_flag_to_instance.rb +14 -0
  33. data/db/migrations/director/20130531172604_add_director_attributes.rb +13 -0
  34. data/db/migrations/dns/20120123234908_initial.rb +27 -0
  35. data/lib/bosh/director.rb +133 -0
  36. data/lib/bosh/director/agent_client.rb +78 -0
  37. data/lib/bosh/director/api.rb +29 -0
  38. data/lib/bosh/director/api/api_helper.rb +81 -0
  39. data/lib/bosh/director/api/backup_manager.rb +15 -0
  40. data/lib/bosh/director/api/controller.rb +639 -0
  41. data/lib/bosh/director/api/controller_helpers.rb +34 -0
  42. data/lib/bosh/director/api/deployment_lookup.rb +13 -0
  43. data/lib/bosh/director/api/deployment_manager.rb +60 -0
  44. data/lib/bosh/director/api/http_constants.rb +16 -0
  45. data/lib/bosh/director/api/instance_lookup.rb +44 -0
  46. data/lib/bosh/director/api/instance_manager.rb +63 -0
  47. data/lib/bosh/director/api/problem_manager.rb +40 -0
  48. data/lib/bosh/director/api/property_manager.rb +69 -0
  49. data/lib/bosh/director/api/release_manager.rb +59 -0
  50. data/lib/bosh/director/api/resource_manager.rb +69 -0
  51. data/lib/bosh/director/api/resurrector_manager.rb +15 -0
  52. data/lib/bosh/director/api/snapshot_manager.rb +94 -0
  53. data/lib/bosh/director/api/stemcell_manager.rb +50 -0
  54. data/lib/bosh/director/api/task_helper.rb +46 -0
  55. data/lib/bosh/director/api/task_manager.rb +64 -0
  56. data/lib/bosh/director/api/user_manager.rb +72 -0
  57. data/lib/bosh/director/api/vm_state_manager.rb +11 -0
  58. data/lib/bosh/director/app.rb +35 -0
  59. data/lib/bosh/director/blob_util.rb +87 -0
  60. data/lib/bosh/director/blobstores.rb +29 -0
  61. data/lib/bosh/director/client.rb +156 -0
  62. data/lib/bosh/director/cloudcheck_helper.rb +204 -0
  63. data/lib/bosh/director/compile_task.rb +157 -0
  64. data/lib/bosh/director/config.rb +370 -0
  65. data/lib/bosh/director/configuration_hasher.rb +114 -0
  66. data/lib/bosh/director/cycle_helper.rb +36 -0
  67. data/lib/bosh/director/db_backup.rb +22 -0
  68. data/lib/bosh/director/db_backup/adapter.rb +3 -0
  69. data/lib/bosh/director/db_backup/adapter/mysql2.rb +27 -0
  70. data/lib/bosh/director/db_backup/adapter/postgres.rb +36 -0
  71. data/lib/bosh/director/db_backup/adapter/sqlite.rb +17 -0
  72. data/lib/bosh/director/db_backup/error.rb +10 -0
  73. data/lib/bosh/director/deployment_plan.rb +26 -0
  74. data/lib/bosh/director/deployment_plan/assembler.rb +430 -0
  75. data/lib/bosh/director/deployment_plan/compilation_config.rb +54 -0
  76. data/lib/bosh/director/deployment_plan/compiled_package.rb +35 -0
  77. data/lib/bosh/director/deployment_plan/dynamic_network.rb +91 -0
  78. data/lib/bosh/director/deployment_plan/idle_vm.rb +109 -0
  79. data/lib/bosh/director/deployment_plan/instance.rb +413 -0
  80. data/lib/bosh/director/deployment_plan/job.rb +470 -0
  81. data/lib/bosh/director/deployment_plan/manual_network.rb +137 -0
  82. data/lib/bosh/director/deployment_plan/network.rb +74 -0
  83. data/lib/bosh/director/deployment_plan/network_subnet.rb +167 -0
  84. data/lib/bosh/director/deployment_plan/planner.rb +288 -0
  85. data/lib/bosh/director/deployment_plan/preparer.rb +52 -0
  86. data/lib/bosh/director/deployment_plan/release.rb +126 -0
  87. data/lib/bosh/director/deployment_plan/resource_pool.rb +143 -0
  88. data/lib/bosh/director/deployment_plan/resource_pools.rb +68 -0
  89. data/lib/bosh/director/deployment_plan/stemcell.rb +56 -0
  90. data/lib/bosh/director/deployment_plan/template.rb +94 -0
  91. data/lib/bosh/director/deployment_plan/update_config.rb +80 -0
  92. data/lib/bosh/director/deployment_plan/updater.rb +55 -0
  93. data/lib/bosh/director/deployment_plan/vip_network.rb +79 -0
  94. data/lib/bosh/director/dns_helper.rb +204 -0
  95. data/lib/bosh/director/download_helper.rb +44 -0
  96. data/lib/bosh/director/duration.rb +36 -0
  97. data/lib/bosh/director/encryption_helper.rb +10 -0
  98. data/lib/bosh/director/errors.rb +198 -0
  99. data/lib/bosh/director/event_log.rb +136 -0
  100. data/lib/bosh/director/ext.rb +64 -0
  101. data/lib/bosh/director/hash_string_vals.rb +13 -0
  102. data/lib/bosh/director/instance_deleter.rb +109 -0
  103. data/lib/bosh/director/instance_updater.rb +506 -0
  104. data/lib/bosh/director/ip_util.rb +67 -0
  105. data/lib/bosh/director/job_queue.rb +16 -0
  106. data/lib/bosh/director/job_runner.rb +162 -0
  107. data/lib/bosh/director/job_updater.rb +121 -0
  108. data/lib/bosh/director/jobs/backup.rb +86 -0
  109. data/lib/bosh/director/jobs/base_job.rb +66 -0
  110. data/lib/bosh/director/jobs/cloud_check/apply_resolutions.rb +46 -0
  111. data/lib/bosh/director/jobs/cloud_check/scan.rb +38 -0
  112. data/lib/bosh/director/jobs/cloud_check/scan_and_fix.rb +73 -0
  113. data/lib/bosh/director/jobs/create_snapshot.rb +23 -0
  114. data/lib/bosh/director/jobs/delete_deployment.rb +183 -0
  115. data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +34 -0
  116. data/lib/bosh/director/jobs/delete_release.rb +219 -0
  117. data/lib/bosh/director/jobs/delete_snapshots.rb +23 -0
  118. data/lib/bosh/director/jobs/delete_stemcell.rb +102 -0
  119. data/lib/bosh/director/jobs/fetch_logs.rb +99 -0
  120. data/lib/bosh/director/jobs/scheduled_backup.rb +38 -0
  121. data/lib/bosh/director/jobs/snapshot_deployment.rb +61 -0
  122. data/lib/bosh/director/jobs/snapshot_deployments.rb +23 -0
  123. data/lib/bosh/director/jobs/snapshot_self.rb +43 -0
  124. data/lib/bosh/director/jobs/ssh.rb +59 -0
  125. data/lib/bosh/director/jobs/update_deployment.rb +110 -0
  126. data/lib/bosh/director/jobs/update_release.rb +672 -0
  127. data/lib/bosh/director/jobs/update_stemcell.rb +109 -0
  128. data/lib/bosh/director/jobs/vm_state.rb +89 -0
  129. data/lib/bosh/director/lock.rb +133 -0
  130. data/lib/bosh/director/lock_helper.rb +92 -0
  131. data/lib/bosh/director/models.rb +29 -0
  132. data/lib/bosh/director/models/compiled_package.rb +33 -0
  133. data/lib/bosh/director/models/deployment.rb +22 -0
  134. data/lib/bosh/director/models/deployment_problem.rb +49 -0
  135. data/lib/bosh/director/models/deployment_property.rb +21 -0
  136. data/lib/bosh/director/models/director_attribute.rb +9 -0
  137. data/lib/bosh/director/models/dns.rb +9 -0
  138. data/lib/bosh/director/models/dns/domain.rb +9 -0
  139. data/lib/bosh/director/models/dns/record.rb +7 -0
  140. data/lib/bosh/director/models/helpers/model_helper.rb +7 -0
  141. data/lib/bosh/director/models/instance.rb +28 -0
  142. data/lib/bosh/director/models/log_bundle.rb +10 -0
  143. data/lib/bosh/director/models/package.rb +30 -0
  144. data/lib/bosh/director/models/persistent_disk.rb +13 -0
  145. data/lib/bosh/director/models/release.rb +17 -0
  146. data/lib/bosh/director/models/release_version.rb +16 -0
  147. data/lib/bosh/director/models/snapshot.rb +13 -0
  148. data/lib/bosh/director/models/stemcell.rb +18 -0
  149. data/lib/bosh/director/models/task.rb +10 -0
  150. data/lib/bosh/director/models/template.rb +44 -0
  151. data/lib/bosh/director/models/user.rb +11 -0
  152. data/lib/bosh/director/models/vm.rb +42 -0
  153. data/lib/bosh/director/nats_rpc.rb +54 -0
  154. data/lib/bosh/director/network_reservation.rb +121 -0
  155. data/lib/bosh/director/next_rebase_version.rb +20 -0
  156. data/lib/bosh/director/package_compiler.rb +423 -0
  157. data/lib/bosh/director/problem_handlers/base.rb +153 -0
  158. data/lib/bosh/director/problem_handlers/inactive_disk.rb +112 -0
  159. data/lib/bosh/director/problem_handlers/invalid_problem.rb +28 -0
  160. data/lib/bosh/director/problem_handlers/missing_vm.rb +34 -0
  161. data/lib/bosh/director/problem_handlers/mount_info_mismatch.rb +62 -0
  162. data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +64 -0
  163. data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +85 -0
  164. data/lib/bosh/director/problem_handlers/unresponsive_agent.rb +78 -0
  165. data/lib/bosh/director/problem_resolver.rb +103 -0
  166. data/lib/bosh/director/problem_scanner.rb +268 -0
  167. data/lib/bosh/director/resource_pool_updater.rb +216 -0
  168. data/lib/bosh/director/scheduler.rb +57 -0
  169. data/lib/bosh/director/sequel.rb +13 -0
  170. data/lib/bosh/director/tar_gzipper.rb +47 -0
  171. data/lib/bosh/director/task_result_file.rb +19 -0
  172. data/lib/bosh/director/thread_pool.rb +8 -0
  173. data/lib/bosh/director/validation_helper.rb +55 -0
  174. data/lib/bosh/director/version.rb +7 -0
  175. data/lib/bosh/director/vm_creator.rb +80 -0
  176. data/lib/bosh/director/vm_data.rb +63 -0
  177. data/lib/bosh/director/vm_metadata_updater.rb +29 -0
  178. data/lib/bosh/director/vm_reuser.rb +63 -0
  179. data/lib/cloud/dummy.rb +149 -0
  180. metadata +664 -0
@@ -0,0 +1,470 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require 'common/deep_copy'
4
+
5
+ module Bosh::Director
6
+ module DeploymentPlan
7
+ class Job
8
+ include Bosh::Common::PropertyHelper
9
+
10
+ include IpUtil
11
+ include DnsHelper
12
+ include ValidationHelper
13
+
14
+ # started, stopped and detached are real states
15
+ # (persisting in DB and reflecting target instance state)
16
+ # recreate and restart are two virtual states
17
+ # (both set target instance state to "started" and set
18
+ # appropriate instance spec modifiers)
19
+ VALID_JOB_STATES = %w(started stopped detached recreate restart)
20
+
21
+ # @return [String] Job name
22
+ attr_accessor :name
23
+
24
+ # @return [String] Job canonical name (mostly for DNS)
25
+ attr_accessor :canonical_name
26
+
27
+ # @return [Integer] Persistent disk size (no disk if zero)
28
+ attr_accessor :persistent_disk
29
+
30
+ # @return [DeploymentPlan] Current deployment plan
31
+ attr_accessor :deployment
32
+
33
+ # @return [DeploymentPlan::Release] Release this job belongs to
34
+ attr_accessor :release
35
+
36
+ # @return [DeploymentPlan::ResourcePool] Resource pool this job should
37
+ # be run in
38
+ attr_accessor :resource_pool
39
+
40
+ # @return [DeploymentPlan::Network Job default network
41
+ attr_accessor :default_network
42
+
43
+ # @return [Array<DeploymentPlan::Template] Templates included into the job
44
+ attr_accessor :templates
45
+
46
+ # @return [Hash] Job properties
47
+ attr_accessor :properties
48
+
49
+ # @return [Hash<String, DeploymentPlan::Package] Packages included into
50
+ # this job
51
+ attr_accessor :packages
52
+
53
+ # @return [DeploymentPlan::UpdateConfig] Job update settings
54
+ attr_accessor :update
55
+
56
+ # @return [Array<Models::Instance>] List of excess instance models that
57
+ # are not needed for current deployment
58
+ attr_accessor :unneeded_instances
59
+
60
+ # @return [String] Expected job state
61
+ attr_accessor :state
62
+
63
+ # @return [Hash<Integer, String>] Individual instance expected states
64
+ attr_accessor :instance_states
65
+
66
+ # @return [Exception] Exception that requires job update process to be
67
+ # interrupted
68
+ attr_accessor :halt_exception
69
+
70
+ # @param [Bosh::Director::DeploymentPlan] deployment Deployment plan
71
+ # @param [Hash] job_spec Raw job spec from the deployment manifest
72
+ # @return [Bosh::Director::DeploymentPlan::Job]
73
+ def self.parse(deployment, job_spec)
74
+ job = new(deployment, job_spec)
75
+ job.parse
76
+ job
77
+ end
78
+
79
+ # @param [Bosh::Director::DeploymentPlan] deployment Deployment plan
80
+ # @param [Hash] job_spec Raw job spec from the deployment manifest
81
+ def initialize(deployment, job_spec)
82
+ @deployment = deployment
83
+ @job_spec = job_spec
84
+
85
+ @release = nil
86
+ @templates = []
87
+ @all_properties = nil # All properties available to job
88
+ @properties = nil # Actual job properties
89
+
90
+ @error_mutex = Mutex.new
91
+ @packages = {}
92
+ @halt = false
93
+ @unneeded_instances = []
94
+ end
95
+
96
+ def parse
97
+ parse_name
98
+ parse_release
99
+ parse_template
100
+ parse_disk
101
+ parse_properties
102
+ parse_resource_pool
103
+ parse_update_config
104
+ parse_instances
105
+ parse_networks
106
+ end
107
+
108
+ def self.is_legacy_spec?(job_spec)
109
+ !job_spec.has_key?("templates")
110
+ end
111
+
112
+ # Takes in a job spec and returns a job spec in the new format, if it
113
+ # needs to be modified. The new format has "templates" key, which is an
114
+ # array with each template's data. This is used for job collocation,
115
+ # specifically for the agent's current job spec when compared to the
116
+ # director's. We only convert their template to a single array entry
117
+ # because it should be impossible for the agent to have a job spec with
118
+ # multiple templates in legacy form.
119
+ def self.convert_from_legacy_spec(job_spec)
120
+ return job_spec if !self.is_legacy_spec?(job_spec)
121
+ template = {
122
+ "name" => job_spec["template"],
123
+ "version" => job_spec["version"],
124
+ "sha1" => job_spec["sha1"],
125
+ "blobstore_id" => job_spec["blobstore_id"]
126
+ }
127
+ job_spec["templates"] = [template]
128
+ end
129
+
130
+ # Returns job spec as a Hash. To be used by all instances of the job to
131
+ # populate agent state.
132
+ # @return [Hash] Hash representation
133
+ def spec
134
+ first_template = @templates[0]
135
+ result = {
136
+ "name" => @name,
137
+ "release" => @release.name,
138
+ "templates" => [],
139
+ # --- Legacy ---
140
+ "template" => first_template.name,
141
+ "version" => first_template.version,
142
+ "sha1" => first_template.sha1,
143
+ "blobstore_id" => first_template.blobstore_id
144
+ }
145
+ if first_template.logs
146
+ result["logs"] = first_template.logs
147
+ end
148
+ # --- /Legacy ---
149
+
150
+ @templates.each do |template|
151
+ template_entry = {
152
+ "name" => template.name,
153
+ "version" => template.version,
154
+ "sha1" => template.sha1,
155
+ "blobstore_id" => template.blobstore_id
156
+ }
157
+ if template.logs
158
+ template_entry["logs"] = template.logs
159
+ end
160
+ result["templates"] << template_entry
161
+ end
162
+
163
+ result
164
+ end
165
+
166
+ # Returns package specs for all packages in the job indexed by package
167
+ # name. To be used by all instances of the job to populate agent state.
168
+ # @return [Hash<String, Hash>] All package specs indexed by package name
169
+ def package_spec
170
+ result = {}
171
+ @packages.each do |name, package|
172
+ result[name] = package.spec
173
+ end
174
+
175
+ result.select { |name, _| run_time_dependencies.include? name }
176
+ end
177
+
178
+ # Returns all instances of this job
179
+ # @return [Array<DeploymentPlan::Instance>] All job instances
180
+ def instances
181
+ @instances
182
+ end
183
+
184
+ # Returns job instance by index
185
+ # @param [Integer] index
186
+ # @return [DeploymentPlan::Instance] index-th instance
187
+ def instance(index)
188
+ @instances[index]
189
+ end
190
+
191
+ # Returns the state state of job instance by its index
192
+ # @param [Integer] index Instance index
193
+ # @return [String, nil] Instance state (nil if not specified)
194
+ def instance_state(index)
195
+ @instance_states[index] || @state
196
+ end
197
+
198
+ # Registers compiled package with this job.
199
+ # @param [Models::CompiledPackage] compiled_package_model Compiled package
200
+ # @return [void]
201
+ def use_compiled_package(compiled_package_model)
202
+ compiled_package = CompiledPackage.new(compiled_package_model)
203
+ @packages[compiled_package.name] = compiled_package
204
+ end
205
+
206
+ def should_halt?
207
+ @halt
208
+ end
209
+
210
+ def record_update_error(error, options = {})
211
+ @error_mutex.synchronize do
212
+ @halt = true
213
+ @halt_exception = error
214
+ end
215
+ end
216
+
217
+ def parse_name
218
+ @name = safe_property(@job_spec, "name", :class => String)
219
+ @canonical_name = canonical(@name)
220
+ end
221
+
222
+ def parse_release
223
+ release_name = safe_property(@job_spec, "release", :class => String,
224
+ :optional => true)
225
+
226
+ if release_name.nil?
227
+ if @deployment.releases.size == 1
228
+ @release = @deployment.releases.first
229
+ else
230
+ raise JobMissingRelease,
231
+ "Cannot tell what release job `#{@name}' supposed to use, please reference an existing release"
232
+ end
233
+ else
234
+ @release = @deployment.release(release_name)
235
+ end
236
+
237
+ if @release.nil?
238
+ raise JobUnknownRelease,
239
+ "Job `#{@name}' references an unknown release `#{release_name}'"
240
+ end
241
+ end
242
+
243
+ def parse_template
244
+ if @release.nil?
245
+ raise DirectorError, "Cannot parse template before parsing release"
246
+ end
247
+
248
+ template_names = safe_property(@job_spec, "template")
249
+
250
+ if template_names.is_a?(String)
251
+ template_names = Array(template_names)
252
+ end
253
+
254
+ unless template_names.is_a?(Array)
255
+ invalid_type("template", "String or Array", template_names)
256
+ end
257
+
258
+ template_names.each do |template_name|
259
+ @release.use_template_named(template_name)
260
+ @templates << @release.template(template_name)
261
+ end
262
+ end
263
+
264
+ def parse_disk
265
+ @persistent_disk = safe_property(@job_spec, "persistent_disk", :class => Integer, :default => 0)
266
+ end
267
+
268
+ def parse_properties
269
+ # Manifest can contain global and per-job properties section
270
+ job_properties = safe_property(@job_spec, "properties", :class => Hash, :optional => true)
271
+
272
+ @all_properties = Bosh::Common::DeepCopy.copy(deployment.properties)
273
+
274
+ if job_properties
275
+ @all_properties.recursive_merge!(job_properties)
276
+ end
277
+
278
+ mappings = safe_property(@job_spec, "property_mappings", :class => Hash, :default => {})
279
+
280
+ mappings.each_pair do |to, from|
281
+ resolved = lookup_property(@all_properties, from)
282
+
283
+ if resolved.nil?
284
+ raise JobInvalidPropertyMapping,
285
+ "Cannot satisfy property mapping `#{to}: #{from}', as `#{from}' is not in deployment properties"
286
+ end
287
+
288
+ @all_properties[to] = resolved
289
+ end
290
+ end
291
+
292
+ def parse_resource_pool
293
+ resource_pool_name = safe_property(@job_spec, "resource_pool",
294
+ :class => String)
295
+ @resource_pool = deployment.resource_pool(resource_pool_name)
296
+ if @resource_pool.nil?
297
+ raise JobUnknownResourcePool,
298
+ "Job `#{@name}' references an unknown resource pool `#{resource_pool_name}'"
299
+ end
300
+ end
301
+
302
+ def parse_update_config
303
+ update_spec = safe_property(@job_spec, "update",
304
+ :class => Hash, :optional => true)
305
+ @update = UpdateConfig.new(update_spec, @deployment.update)
306
+ end
307
+
308
+ def parse_instances
309
+ @instances = []
310
+ @instance_states = {}
311
+
312
+ @state = safe_property(@job_spec, "state",
313
+ :class => String, :optional => true)
314
+
315
+ job_size = safe_property(@job_spec, "instances", :class => Integer)
316
+
317
+ instance_states = safe_property(@job_spec, "instance_states",
318
+ :class => Hash, :default => {})
319
+
320
+ instance_states.each_pair do |index, state|
321
+ begin
322
+ index = Integer(index)
323
+ rescue ArgumentError
324
+ raise JobInvalidInstanceIndex,
325
+ "Invalid job index `#{index}', integer expected"
326
+ end
327
+ unless (0...job_size).include?(index)
328
+ raise JobInvalidInstanceIndex,
329
+ "`#{@name}/#{index}' is outside of (0..#{job_size-1}) range"
330
+ end
331
+ unless VALID_JOB_STATES.include?(state)
332
+ raise JobInvalidInstanceState,
333
+ "Invalid state `#{state}' for `#{@name}/#{index}', valid states are: #{VALID_JOB_STATES.join(", ")}"
334
+ end
335
+ @instance_states[index] = state
336
+ end
337
+
338
+ if @state && !VALID_JOB_STATES.include?(@state)
339
+ raise JobInvalidJobState,
340
+ "Invalid state `#{@state}' for `#{@name}', valid states are: #{VALID_JOB_STATES.join(", ")}"
341
+ end
342
+
343
+ job_size.times do |index|
344
+ @instances[index] = Instance.new(self, index)
345
+ @resource_pool.reserve_capacity(1)
346
+ end
347
+ end
348
+
349
+ def parse_networks
350
+ @default_network = {}
351
+
352
+ network_specs = safe_property(@job_spec, "networks", :class => Array)
353
+ if network_specs.empty?
354
+ raise JobMissingNetwork,
355
+ "Job `#{@name}' must specify at least one network"
356
+ end
357
+
358
+ network_specs.each do |network_spec|
359
+ network_name = safe_property(network_spec, "name", :class => String)
360
+ network = @deployment.network(network_name)
361
+ if network.nil?
362
+ raise JobUnknownNetwork,
363
+ "Job `#{@name}' references an unknown network `#{network_name}'"
364
+ end
365
+
366
+ static_ips = nil
367
+ if network_spec["static_ips"]
368
+ static_ips = []
369
+ each_ip(network_spec["static_ips"]) do |ip|
370
+ static_ips << ip
371
+ end
372
+ if static_ips.size != @instances.size
373
+ raise JobNetworkInstanceIpMismatch,
374
+ "Job `#{@name}' has #{@instances.size} instances but was allocated #{static_ips.size} static IPs"
375
+ end
376
+ end
377
+
378
+ default_network = safe_property(network_spec, "default",
379
+ :class => Array, :optional => true)
380
+ if default_network
381
+ default_network.each do |property|
382
+ unless Network::VALID_DEFAULTS.include?(property)
383
+ raise JobNetworkInvalidDefault,
384
+ "Job `#{@name}' specified an invalid default network property `#{property}', " +
385
+ "valid properties are: " + Network::VALID_DEFAULTS.join(", ")
386
+ end
387
+
388
+ if @default_network[property]
389
+ raise JobNetworkMultipleDefaults,
390
+ "Job `#{@name}' specified more than one network to contain default #{property}"
391
+ else
392
+ @default_network[property] = network_name
393
+ end
394
+ end
395
+ end
396
+
397
+ @instances.each_with_index do |instance, index|
398
+ reservation = NetworkReservation.new
399
+ if static_ips
400
+ reservation.ip = static_ips[index]
401
+ reservation.type = NetworkReservation::STATIC
402
+ else
403
+ reservation.type = NetworkReservation::DYNAMIC
404
+ end
405
+ instance.add_network_reservation(network_name, reservation)
406
+ end
407
+ end
408
+
409
+ if network_specs.size > 1
410
+ missing_default_properties = Network::VALID_DEFAULTS.dup
411
+ @default_network.each_key do |key|
412
+ missing_default_properties.delete(key)
413
+ end
414
+ unless missing_default_properties.empty?
415
+ raise JobNetworkMissingDefault,
416
+ "Job `#{@name}' must specify which network is default for " +
417
+ missing_default_properties.sort.join(", ") + ", since it has more than one network configured"
418
+ end
419
+ else
420
+ # Set the default network to the one and only available network
421
+ # (if not specified already)
422
+ network = safe_property(network_specs[0], "name", :class => String)
423
+ Network::VALID_DEFAULTS.each do |property|
424
+ @default_network[property] ||= network
425
+ end
426
+ end
427
+ end
428
+
429
+ # Extracts only the properties needed by this job. This is decoupled from
430
+ # parsing properties because templates need to be bound to their models
431
+ # before 'bind_properties' is being called (as we persist job template
432
+ # property definitions in DB).
433
+ def bind_properties
434
+ @properties = filter_properties(@all_properties)
435
+ end
436
+
437
+ private
438
+
439
+ # @param [Hash] collection All properties collection
440
+ # @return [Hash] Properties required by templates included in this job
441
+ def filter_properties(collection)
442
+ if @templates.empty?
443
+ raise DirectorError, "Can't extract job properties before parsing job templates"
444
+ end
445
+
446
+ return collection if @templates.none? { |template| template.properties }
447
+ return extract_template_properties(collection) if @templates.all? { |template| template.properties }
448
+ raise JobIncompatibleSpecs, "Job `#{name}' has specs with conflicting property definition styles between" +
449
+ " its job spec templates. This may occur if colocating jobs, one of which has a spec file including" +
450
+ " `properties' and one which doesn't."
451
+ end
452
+
453
+ def extract_template_properties(collection)
454
+ result = {}
455
+
456
+ @templates.each do |template|
457
+ template.properties.each_pair do |name, definition|
458
+ copy_property(result, collection, name, definition["default"])
459
+ end
460
+ end
461
+
462
+ result
463
+ end
464
+
465
+ def run_time_dependencies
466
+ templates.flat_map { |template| template.package_models }.uniq.map(&:name)
467
+ end
468
+ end
469
+ end
470
+ end