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,36 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director::CycleHelper
4
+
5
+ def self.check_for_cycle(vertices, options = {}, &block)
6
+ result = {}
7
+ result[:connected_vertices] = {} if options[:connected_vertices]
8
+ vertices.each do |vertex|
9
+ path = {}
10
+ connected_vertices = options[:connected_vertices] ? Set.new : nil
11
+ check_for_cycle_helper(path, vertices, vertex, connected_vertices, &block)
12
+ result[:connected_vertices][vertex] = connected_vertices.to_a if connected_vertices
13
+ end
14
+ result
15
+ end
16
+
17
+ def self.check_for_cycle_helper(path, valid_vertices, vertex, connected_vertices, &block)
18
+ path[vertex] = path.size + 1
19
+ connected_vertices << vertex if connected_vertices && path.size > 1
20
+ edges = block.call(vertex)
21
+ if edges
22
+ edges.each do |edge|
23
+ raise "Invalid edge: #{edge}" unless valid_vertices.include?(edge)
24
+ if path.include?(edge)
25
+ vertex_path = []
26
+ path = path.invert
27
+ path.size.times { |index| vertex_path << path[index + 1] }
28
+ raise "Cycle: #{vertex_path.join("=>")}=>#{edge}"
29
+ end
30
+ check_for_cycle_helper(path, valid_vertices, edge, connected_vertices, &block)
31
+ end
32
+ end
33
+ path.delete(vertex)
34
+ end
35
+
36
+ end
@@ -0,0 +1,22 @@
1
+ require 'bosh/director/db_backup/adapter'
2
+ require 'bosh/director/db_backup/error'
3
+
4
+ module Bosh
5
+ module Director
6
+ module DbBackup
7
+ def self.create(db_config)
8
+ adapter_to_module(db_config['adapter']).new(db_config)
9
+ end
10
+
11
+ def self.adapter_to_module(adapter)
12
+ adapter_module = adapter.capitalize
13
+
14
+ if Adapter.const_defined?(adapter_module)
15
+ Adapter.const_get adapter_module
16
+ else
17
+ raise Adapter::Error.new("backup for database adapter #{adapter} (module #{adapter_module}) is not implemented")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ require 'bosh/director/db_backup/adapter/mysql2'
2
+ require 'bosh/director/db_backup/adapter/postgres'
3
+ require 'bosh/director/db_backup/adapter/sqlite'
@@ -0,0 +1,27 @@
1
+ require 'open3'
2
+
3
+ module Bosh
4
+ module Director
5
+ module DbBackup
6
+ module Adapter
7
+ class Mysql2
8
+ def initialize(db_config)
9
+ @db_config = db_config
10
+ end
11
+
12
+ def export(path)
13
+ out, err, status = Open3.capture3({'MYSQL_PWD' => @db_config.fetch('password')},
14
+ 'mysqldump',
15
+ '--user', @db_config.fetch('user'),
16
+ '--host', @db_config.fetch('host'),
17
+ '--port', @db_config.fetch('port').to_s,
18
+ '--result-file', path,
19
+ @db_config.fetch('database'))
20
+ raise("mysqldump exited #{status.exitstatus}, output: '#{out}', error: '#{err}'") unless status.success?
21
+ path
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ require 'open3'
2
+
3
+ module Bosh
4
+ module Director
5
+ module DbBackup
6
+ module Adapter
7
+ class Postgres
8
+ def initialize(db_config)
9
+ @db_config = db_config
10
+ end
11
+
12
+ def export(path)
13
+ env = {}
14
+ env['PGPASSWORD'] = @db_config['password'] if @db_config.has_key?('password')
15
+
16
+ stdout, stderr, status = Open3.capture3(
17
+ env,
18
+ 'pg_dump',
19
+ '--host', @db_config.fetch('host'),
20
+ '--port', @db_config.fetch('port').to_s,
21
+ '--username', @db_config.fetch('user'),
22
+ '--file', path,
23
+ @db_config.fetch('database'),
24
+ )
25
+
26
+ unless status.success?
27
+ raise("pg_dump exited #{status.exitstatus}, output: '#{stdout}', error: '#{stderr}'")
28
+ end
29
+
30
+ path
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ module Bosh
2
+ module Director
3
+ module DbBackup
4
+ module Adapter
5
+ class Sqlite
6
+ def initialize(db_config)
7
+ @db_config = db_config
8
+ end
9
+
10
+ def export(output_path)
11
+ FileUtils.cp(@db_config.fetch('database'), output_path)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ module Bosh
2
+ module Director
3
+ module DbBackup
4
+ module Adapter
5
+ class Error < StandardError
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ end
6
+ end
7
+
8
+ require 'bosh/director/deployment_plan/compilation_config'
9
+ require 'bosh/director/deployment_plan/idle_vm'
10
+ require 'bosh/director/deployment_plan/instance'
11
+ require 'bosh/director/deployment_plan/job'
12
+ require 'bosh/director/deployment_plan/network'
13
+ require 'bosh/director/deployment_plan/network_subnet'
14
+ require 'bosh/director/deployment_plan/compiled_package'
15
+ require 'bosh/director/deployment_plan/preparer'
16
+ require 'bosh/director/deployment_plan/resource_pools'
17
+ require 'bosh/director/deployment_plan/updater'
18
+ require 'bosh/director/deployment_plan/release'
19
+ require 'bosh/director/deployment_plan/resource_pool'
20
+ require 'bosh/director/deployment_plan/stemcell'
21
+ require 'bosh/director/deployment_plan/template'
22
+ require 'bosh/director/deployment_plan/update_config'
23
+ require 'bosh/director/deployment_plan/dynamic_network'
24
+ require 'bosh/director/deployment_plan/manual_network'
25
+ require 'bosh/director/deployment_plan/vip_network'
26
+ require 'bosh/director/deployment_plan/planner'
@@ -0,0 +1,430 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ # DeploymentPlan::Assembler is used to populate deployment plan with information
5
+ # about existing deployment and information from director DB
6
+ class DeploymentPlan::Assembler
7
+ include DnsHelper
8
+ include LockHelper
9
+ include IpUtil
10
+
11
+ # @param [DeploymentPlan] deployment_plan Deployment plan
12
+ def initialize(deployment_plan)
13
+ @deployment_plan = deployment_plan
14
+ @cloud = Config.cloud
15
+ @logger = Config.logger
16
+ @event_log = Config.event_log
17
+ @stemcell_manager = Api::StemcellManager.new
18
+ end
19
+
20
+ # Binds deployment DB record to a plan
21
+ # @return [void]
22
+ def bind_deployment
23
+ @deployment_plan.bind_model
24
+ end
25
+
26
+ # Binds release DB record(s) to a plan
27
+ # @return [void]
28
+ def bind_releases
29
+ with_release_locks(@deployment_plan) do
30
+ @deployment_plan.releases.each do |release|
31
+ release.bind_model
32
+ end
33
+ end
34
+ end
35
+
36
+ # Binds information about existing deployment to a plan
37
+ # @return [void]
38
+ def bind_existing_deployment
39
+ lock = Mutex.new
40
+ ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool|
41
+ @deployment_plan.vms.each do |vm|
42
+ pool.process do
43
+ with_thread_name("bind_existing_deployment(#{vm.agent_id})") do
44
+ bind_existing_vm(vm, lock)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ # Queries agent for VM state and updates deployment plan accordingly
52
+ # @param [Models::Vm] vm VM database model
53
+ # @param [Mutex] lock Lock to hold on to while updating deployment plan
54
+ def bind_existing_vm(vm, lock)
55
+ state = get_state(vm)
56
+ lock.synchronize do
57
+ @logger.debug("Processing network reservations")
58
+ reservations = get_network_reservations(state)
59
+
60
+ instance = vm.instance
61
+ if instance
62
+ bind_instance(instance, state, reservations)
63
+ else
64
+ @logger.debug("Binding resource pool VM")
65
+ resource_pool = @deployment_plan.resource_pool(
66
+ state["resource_pool"]["name"])
67
+ if resource_pool
68
+ bind_idle_vm(vm, resource_pool, state, reservations)
69
+ else
70
+ @logger.debug("Resource pool doesn't exist, marking for deletion")
71
+ @deployment_plan.delete_vm(vm)
72
+ end
73
+ end
74
+ @logger.debug("Finished binding VM")
75
+ end
76
+ end
77
+
78
+ # Binds idle VM to a resource pool with a proper network reservation
79
+ # @param [Models::Vm] vm VM DB model
80
+ # @param [DeploymentPlan::ResourcePool] resource_pool Resource pool
81
+ # @param [Hash] state VM state according to its agent
82
+ # @param [Hash] reservations Network reservations
83
+ def bind_idle_vm(vm, resource_pool, state, reservations)
84
+ @logger.debug("Adding to resource pool")
85
+ idle_vm = resource_pool.add_idle_vm
86
+ idle_vm.vm = vm
87
+ idle_vm.current_state = state
88
+
89
+ reservation = reservations[resource_pool.network.name]
90
+ if reservation
91
+ if reservation.static?
92
+ @logger.debug("Releasing static network reservation for " +
93
+ "resource pool VM `#{vm.cid}'")
94
+ resource_pool.network.release(reservation)
95
+ else
96
+ idle_vm.use_reservation(reservation)
97
+ end
98
+ else
99
+ @logger.debug("No network reservation for VM `#{vm.cid}'")
100
+ end
101
+ end
102
+
103
+ # @param [Models::Instance] instance_model Instance model
104
+ # @param [Hash] state Instance state according to agent
105
+ # @param [Hash] reservations Instance network reservations
106
+ def bind_instance(instance_model, state, reservations)
107
+ @logger.debug("Binding instance VM")
108
+
109
+ # Update instance, if we are renaming a job.
110
+ if @deployment_plan.rename_in_progress?
111
+ old_name = @deployment_plan.job_rename["old_name"]
112
+ new_name = @deployment_plan.job_rename["new_name"]
113
+
114
+ if instance_model.job == old_name
115
+ @logger.info("Renaming `#{old_name}' to `#{new_name}'")
116
+ instance_model.update(:job => new_name)
117
+ end
118
+ end
119
+
120
+ # Does the job instance exist in the new deployment?
121
+ if (job = @deployment_plan.job(instance_model.job)) &&
122
+ (instance = job.instance(instance_model.index))
123
+
124
+ @logger.debug("Found job and instance spec")
125
+ instance.use_model(instance_model)
126
+ instance.current_state = state
127
+
128
+ @logger.debug("Copying network reservations")
129
+ instance.take_network_reservations(reservations)
130
+
131
+ @logger.debug("Copying resource pool reservation")
132
+ job.resource_pool.mark_active_vm
133
+ else
134
+ @logger.debug("Job/instance not found, marking for deletion")
135
+ @deployment_plan.delete_instance(instance_model)
136
+ end
137
+ end
138
+
139
+ def get_network_reservations(state)
140
+ reservations = {}
141
+ state["networks"].each do |name, network_config|
142
+ network = @deployment_plan.network(name)
143
+ if network
144
+ reservation = NetworkReservation.new(:ip => network_config["ip"])
145
+ network.reserve(reservation)
146
+ reservations[name] = reservation if reservation.reserved?
147
+ end
148
+ end
149
+ reservations
150
+ end
151
+
152
+ def get_state(vm)
153
+ @logger.debug("Requesting current VM state for: #{vm.agent_id}")
154
+ agent = AgentClient.new(vm.agent_id)
155
+ state = agent.get_state
156
+
157
+ @logger.debug("Received VM state: #{state.pretty_inspect}")
158
+ verify_state(vm, state)
159
+ @logger.debug("Verified VM state")
160
+
161
+ migrate_legacy_state(vm, state)
162
+ state
163
+ end
164
+
165
+ def verify_state(vm, state)
166
+ instance = vm.instance
167
+
168
+ if instance && instance.deployment_id != vm.deployment_id
169
+ # Both VM and instance should reference same deployment
170
+ raise VmInstanceOutOfSync,
171
+ "VM `#{vm.cid}' and instance " +
172
+ "`#{instance.job}/#{instance.index}' " +
173
+ "don't belong to the same deployment"
174
+ end
175
+
176
+ unless state.kind_of?(Hash)
177
+ @logger.error("Invalid state for `#{vm.cid}': #{state.pretty_inspect}")
178
+ raise AgentInvalidStateFormat,
179
+ "VM `#{vm.cid}' returns invalid state: " +
180
+ "expected Hash, got #{state.class}"
181
+ end
182
+
183
+ actual_deployment_name = state["deployment"]
184
+ expected_deployment_name = @deployment_plan.name
185
+
186
+ if actual_deployment_name != expected_deployment_name
187
+ raise AgentWrongDeployment,
188
+ "VM `#{vm.cid}' is out of sync: " +
189
+ "expected to be a part of deployment " +
190
+ "`#{expected_deployment_name}' " +
191
+ "but is actually a part of deployment " +
192
+ "`#{actual_deployment_name}'"
193
+ end
194
+
195
+ actual_job = state["job"].is_a?(Hash) ? state["job"]["name"] : nil
196
+ actual_index = state["index"]
197
+
198
+ if instance.nil? && !actual_job.nil?
199
+ raise AgentUnexpectedJob,
200
+ "VM `#{vm.cid}' is out of sync: " +
201
+ "it reports itself as `#{actual_job}/#{actual_index}' but " +
202
+ "there is no instance reference in DB"
203
+ end
204
+
205
+ if instance &&
206
+ (instance.job != actual_job || instance.index != actual_index)
207
+ # Check if we are resuming a previously unfinished rename
208
+ if actual_job == @deployment_plan.job_rename["old_name"] &&
209
+ instance.job == @deployment_plan.job_rename["new_name"] &&
210
+ instance.index == actual_index
211
+
212
+ # Rename already happened in the DB but then something happened
213
+ # and agent has never been updated.
214
+ unless @deployment_plan.job_rename["force"]
215
+ raise AgentRenameInProgress,
216
+ "Found a job `#{actual_job}' that seems to be " +
217
+ "in the middle of a rename to `#{instance.job}'. " +
218
+ "Run 'rename' again with '--force' to proceed."
219
+ end
220
+ else
221
+ raise AgentJobMismatch,
222
+ "VM `#{vm.cid}' is out of sync: " +
223
+ "it reports itself as `#{actual_job}/#{actual_index}' but " +
224
+ "according to DB it is `#{instance.job}/#{instance.index}'"
225
+ end
226
+ end
227
+ end
228
+
229
+ def migrate_legacy_state(vm, state)
230
+ # Persisting apply spec for VMs that were introduced before we started
231
+ # persisting it on apply itself (this is for cloudcheck purposes only)
232
+ if vm.apply_spec.nil?
233
+ # The assumption is that apply_spec <=> VM state
234
+ vm.update(:apply_spec => state)
235
+ end
236
+
237
+ instance = vm.instance
238
+ if instance
239
+ disk_size = state["persistent_disk"].to_i
240
+ persistent_disk = instance.persistent_disk
241
+
242
+ # This is to support legacy deployments where we did not have
243
+ # the disk_size specified.
244
+ if disk_size != 0 && persistent_disk && persistent_disk.size == 0
245
+ persistent_disk.update(:size => disk_size)
246
+ end
247
+ end
248
+ end
249
+
250
+ # Takes a look at the current state of all resource pools in the deployment
251
+ # and schedules adding any new VMs if needed. VMs are NOT created at this
252
+ # stage, only data structures are being allocated. {ResourcePoolUpdater}
253
+ # will later perform actual changes based on this data.
254
+ # @return [void]
255
+ def bind_resource_pools
256
+ @deployment_plan.resource_pools.each do |resource_pool|
257
+ resource_pool.process_idle_vms
258
+ end
259
+ end
260
+
261
+ # Looks at every job instance in the deployment plan and binds it to the
262
+ # instance database model (idle VM is also created in the appropriate
263
+ # resource pool if necessary)
264
+ # @return [void]
265
+ def bind_unallocated_vms
266
+ @deployment_plan.jobs.each do |job|
267
+ job.instances.each do |instance|
268
+ instance.bind_unallocated_vm
269
+ # Now that we know every VM has been allocated and instance models are
270
+ # bound, we can sync the state.
271
+ instance.sync_state_with_db
272
+ end
273
+ end
274
+ end
275
+
276
+ def bind_instance_networks
277
+ @deployment_plan.jobs.each do |job|
278
+ job.instances.each do |instance|
279
+ instance.network_reservations.each do |name, reservation|
280
+ unless reservation.reserved?
281
+ network = @deployment_plan.network(name)
282
+ network.reserve!(reservation, "`#{job.name}/#{instance.index}'")
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end
288
+
289
+ # Binds template models for each release spec in the deployment plan
290
+ # @return [void]
291
+ def bind_templates
292
+ @deployment_plan.releases.each do |release|
293
+ release.bind_templates
294
+ end
295
+ end
296
+
297
+ # Binds properties for all templates in the deployment
298
+ # @return [void]
299
+ def bind_properties
300
+ @deployment_plan.jobs.each do |job|
301
+ job.bind_properties
302
+ end
303
+ end
304
+
305
+ # Binds stemcell model for each stemcell spec in each resource pool in
306
+ # the deployment plan
307
+ # @return [void]
308
+ def bind_stemcells
309
+ @deployment_plan.resource_pools.each do |resource_pool|
310
+ stemcell = resource_pool.stemcell
311
+
312
+ if stemcell.nil?
313
+ raise DirectorError,
314
+ "Stemcell not bound for resource pool `#{resource_pool.name}'"
315
+ end
316
+
317
+ stemcell.bind_model
318
+ end
319
+ end
320
+
321
+ # Calculates configuration checksums for all jobs in this deployment plan
322
+ # @return [void]
323
+ def bind_configuration
324
+ @deployment_plan.jobs.each do |job|
325
+ ConfigurationHasher.new(job).hash
326
+ end
327
+ end
328
+
329
+ def bind_dns
330
+ domain = Models::Dns::Domain.find_or_create(:name => dns_domain_name,
331
+ :type => "NATIVE")
332
+ @deployment_plan.dns_domain = domain
333
+
334
+ soa_record = Models::Dns::Record.find_or_create(:domain_id => domain.id,
335
+ :name => dns_domain_name,
336
+ :type => "SOA")
337
+ soa_record.content = SOA
338
+ soa_record.ttl = 300
339
+ soa_record.save
340
+
341
+ # add NS record
342
+ Models::Dns::Record.find_or_create(:domain_id => domain.id,
343
+ :name => dns_domain_name,
344
+ :type =>'NS', :ttl => TTL_4H,
345
+ :content => dns_ns_record)
346
+ # add A record for name server
347
+ Models::Dns::Record.find_or_create(:domain_id => domain.id,
348
+ :name => dns_ns_record,
349
+ :type =>'A', :ttl => TTL_4H,
350
+ :content => Config.dns["address"])
351
+ end
352
+
353
+ def bind_instance_vms
354
+ unbound_instances = []
355
+
356
+ @deployment_plan.jobs.each do |job|
357
+ job.instances.each do |instance|
358
+ # Don't allocate resource pool VMs to instances in detached state
359
+ next if instance.state == "detached"
360
+ # Skip bound instances
361
+ next if instance.model.vm
362
+ unbound_instances << instance
363
+ end
364
+ end
365
+
366
+ return if unbound_instances.empty?
367
+
368
+ @event_log.begin_stage("Binding instance VMs", unbound_instances.size)
369
+
370
+ ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool|
371
+ unbound_instances.each do |instance|
372
+ pool.process do
373
+ bind_instance_vm(instance)
374
+ end
375
+ end
376
+ end
377
+ end
378
+
379
+ # @param [DeploymentPlan::Instance]
380
+ def bind_instance_vm(instance)
381
+ job = instance.job
382
+ idle_vm = instance.idle_vm
383
+
384
+ instance.model.update(:vm => idle_vm.vm)
385
+
386
+ @event_log.track("#{job.name}/#{instance.index}") do
387
+ # Apply the assignment to the VM
388
+ state = idle_vm.current_state
389
+ state["job"] = job.spec
390
+ state["index"] = instance.index
391
+ state["release"] = job.release.spec
392
+
393
+ idle_vm.vm.update(:apply_spec => state)
394
+
395
+ agent = AgentClient.new(idle_vm.vm.agent_id)
396
+ agent.apply(state)
397
+ instance.current_state = state
398
+ end
399
+ end
400
+
401
+ def delete_unneeded_vms
402
+ unneeded_vms = @deployment_plan.unneeded_vms
403
+ return if unneeded_vms.empty?
404
+
405
+ @event_log.begin_stage("Deleting unneeded VMs", unneeded_vms.size)
406
+
407
+ ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool|
408
+ unneeded_vms.each do |vm|
409
+ pool.process do
410
+ @event_log.track(vm.cid) do
411
+ @logger.info("Delete unneeded VM #{vm.cid}")
412
+ @cloud.delete_vm(vm.cid)
413
+ vm.destroy
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end
419
+
420
+ def delete_unneeded_instances
421
+ unneeded_instances = @deployment_plan.unneeded_instances
422
+ return if unneeded_instances.empty?
423
+
424
+ @event_log.begin_stage("Deleting unneeded instances",
425
+ unneeded_instances.size)
426
+ InstanceDeleter.new(@deployment_plan).delete_instances(unneeded_instances)
427
+ @logger.info("Deleted no longer needed instances")
428
+ end
429
+ end
430
+ end