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