bosh-director 1.5.0.pre.1113

Sign up to get free protection for your applications and to get access to all the features.
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