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,54 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ ##
6
+ # Represents the deployment compilation worker configuration.
7
+ class CompilationConfig
8
+ include ValidationHelper
9
+
10
+ # @return [DeploymentPlan] associated deployment
11
+ attr_accessor :deployment
12
+
13
+ # @return [Integer] number of worker VMs to use
14
+ attr_accessor :workers
15
+
16
+ # @return [DeploymentPlan::Network] network used by compilation workers
17
+ attr_accessor :network
18
+
19
+ # @return [Hash] cloud properties to use when creating VMs. (optional)
20
+ attr_accessor :cloud_properties
21
+
22
+ # @return [Hash] environment to use when creating VMs. (optional)
23
+ attr_accessor :env
24
+
25
+ # @return [Bool] if VMs should be reused for compilation tasks. (optional)
26
+ attr_accessor :reuse_compilation_vms
27
+
28
+ # Creates compilation configuration spec from the deployment manifest.
29
+ # @param [DeploymentPlan] deployment
30
+ # @param [Hash] compilation_config parsed compilation config YAML section
31
+ def initialize(deployment, compilation_config)
32
+ @deployment = deployment
33
+ @workers = safe_property(compilation_config, "workers",
34
+ :class => Integer, :min => 1)
35
+ network_name = safe_property(compilation_config, "network",
36
+ :class => String)
37
+ @reuse_compilation_vms = safe_property(compilation_config,
38
+ "reuse_compilation_vms",
39
+ :class => :boolean,
40
+ :optional => true)
41
+ @network = deployment.network(network_name)
42
+ if @network.nil?
43
+ raise CompilationConfigUnknownNetwork,
44
+ "Compilation config references an unknown " +
45
+ "network `#{network_name}'"
46
+ end
47
+ @cloud_properties = safe_property(
48
+ compilation_config, "cloud_properties", :class => Hash)
49
+ @env = safe_property(compilation_config, "env", :class => Hash,
50
+ :optional => true, :default => {})
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ class CompiledPackage
6
+
7
+ # @return [Models::CompiledPackage] Compiled package DB model
8
+ attr_reader :model
9
+
10
+ # @return [String] Package name
11
+ attr_reader :name
12
+
13
+ # @return [String] Package version
14
+ attr_reader :version
15
+
16
+ # @param [Models::CompiledPackage]
17
+ def initialize(model)
18
+ @model = model
19
+
20
+ @name = model.package.name
21
+ @version = model.package.version
22
+ end
23
+
24
+ # @return [Hash<String,Object>] Hash representation
25
+ def spec
26
+ {
27
+ "name" => @name,
28
+ "version" => "#{@version}.#{@model.build}",
29
+ "sha1" => @model.sha1,
30
+ "blobstore_id" => @model.blobstore_id
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,91 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ class DynamicNetwork < Network
6
+ include DnsHelper
7
+
8
+ DYNAMIC_IP = NetAddr::CIDR.create("255.255.255.255").to_i
9
+
10
+ # @!attribute [rw] cloud_properties
11
+ # @return [Hash] Network cloud properties
12
+ attr_accessor :cloud_properties
13
+
14
+ # @!attribute [rw] dns
15
+ # @return [Array] an array of DNS servers
16
+ attr_accessor :dns
17
+
18
+ ##
19
+ # Creates a new network.
20
+ #
21
+ # @param [DeploymentPlan] deployment associated deployment plan
22
+ # @param [Hash] network_spec parsed deployment manifest network section
23
+ def initialize(deployment, network_spec)
24
+ super
25
+ @cloud_properties =
26
+ safe_property(network_spec, "cloud_properties", :class => Hash)
27
+
28
+ @dns = dns_servers(network_spec["name"], network_spec)
29
+ end
30
+
31
+ ##
32
+ # Reserves a network resource.
33
+ #
34
+ # This is either an already used reservation being verified or a new one
35
+ # waiting to be fulfilled.
36
+ # @param [NetworkReservation] reservation
37
+ # @return [Boolean] true if the reservation was fulfilled
38
+ def reserve(reservation)
39
+ reservation.reserved = false
40
+ if reservation.static?
41
+ reservation.error = NetworkReservation::WRONG_TYPE
42
+ else
43
+ reservation.ip = DYNAMIC_IP
44
+ reservation.reserved = true
45
+ reservation.type = NetworkReservation::DYNAMIC
46
+ end
47
+ reservation.reserved?
48
+ end
49
+
50
+ ##
51
+ # Releases a previous reservation that had been fulfilled.
52
+ # @param [NetworkReservation] reservation
53
+ # @return [void]
54
+ def release(reservation)
55
+ validate_ip(reservation)
56
+ end
57
+
58
+ ##
59
+ # Returns the network settings for the specific reservation.
60
+ #
61
+ # @param [NetworkReservation] reservation
62
+ # @param [Array<String>] default_properties
63
+ # @return [Hash] network settings that will be passed to the BOSH Agent
64
+ def network_settings(reservation, default_properties = VALID_DEFAULTS)
65
+ validate_ip(reservation)
66
+
67
+ config = {
68
+ "type" => "dynamic",
69
+ "cloud_properties" => @cloud_properties
70
+ }
71
+ config["dns"] = @dns if @dns
72
+
73
+ if default_properties
74
+ config["default"] = default_properties.sort
75
+ end
76
+
77
+ config
78
+ end
79
+
80
+ private
81
+
82
+ def validate_ip(reservation)
83
+ unless reservation.ip == DYNAMIC_IP
84
+ raise NetworkReservationInvalidIp,
85
+ "Invalid IP: `%s', did not match magic DYNAMIC IP" % [
86
+ reservation.ip]
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,109 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ ##
6
+ # Represents a resource pool VM.
7
+ #
8
+ # It represents a VM until it's officially bound to an instance. It can be
9
+ # reserved for an instance to minimize the number of CPI operations
10
+ # (network & storage) required for the VM to match the instance
11
+ # requirements.
12
+ class IdleVm
13
+ # @return [DeploymentPlan::ResourcePool] Associated resource pool
14
+ attr_reader :resource_pool
15
+
16
+ # @return [NetworkReservation] VM network reservation
17
+ attr_accessor :network_reservation
18
+
19
+ # @return [Models::Vm] Associated model
20
+ attr_accessor :vm
21
+
22
+ # @return [Hash] Current state as provided by the BOSH Agent
23
+ attr_accessor :current_state
24
+
25
+ # @return [DeploymentPlan::Instance, nil] Instance that reserved this VM
26
+ attr_accessor :bound_instance
27
+
28
+ ##
29
+ # Creates a new idle VM reference for the specific resource pool
30
+ # @param [DeploymentPlan::ResourcePool] resource_pool Resource pool
31
+ def initialize(resource_pool)
32
+ @resource_pool = resource_pool
33
+ @current_state = nil
34
+ @bound_instance = nil
35
+ @network_reservation = nil
36
+ @vm = nil
37
+ end
38
+
39
+ #
40
+ # @return [Boolean] Does this VM have a network reservation?
41
+ def has_network_reservation?
42
+ !@network_reservation.nil?
43
+ end
44
+
45
+ #
46
+ # Uses provided network reservation
47
+ # @param [NetworkReservation] reservation Network reservation
48
+ def use_reservation(reservation)
49
+ @network_reservation = reservation
50
+ end
51
+
52
+ #
53
+ # Releases current network reservation (if any)
54
+ # @return [void]
55
+ def release_reservation
56
+ if has_network_reservation?
57
+ @resource_pool.network.release(@network_reservation)
58
+ @network_reservation = nil
59
+ end
60
+ end
61
+
62
+ ##
63
+ # @return [Hash] BOSH network settings used for Agent apply call
64
+ def network_settings
65
+ # use the instance network settings if bound, otherwise use the one
66
+ # provided by the resource pool
67
+ if @bound_instance
68
+ @bound_instance.network_settings
69
+ else
70
+ unless @network_reservation
71
+ raise NetworkReservationMissing,
72
+ "Missing network reservation for resource pool VM"
73
+ end
74
+
75
+ network_settings = {}
76
+ network = @resource_pool.network
77
+ network_settings[network.name] = network.network_settings(
78
+ @network_reservation)
79
+ network_settings
80
+ end
81
+ end
82
+
83
+ ##
84
+ # @return [Boolean] returns true if the expected network configuration
85
+ # differs from the one provided by the VM
86
+ def networks_changed?
87
+ network_settings != @current_state["networks"]
88
+ end
89
+
90
+ ##
91
+ # @return [Boolean] returns true if the expected resource pool
92
+ # specification differs from the one provided by the VM
93
+ def resource_pool_changed?
94
+ return true if resource_pool.spec != @current_state["resource_pool"]
95
+ return true if resource_pool.deployment_plan.recreate
96
+ return true if @vm && @vm.env != resource_pool.env
97
+
98
+ false
99
+ end
100
+
101
+ ##
102
+ # @return [Boolean] returns true if the any of the expected specifications
103
+ # differ from the ones provided by the VM
104
+ def changed?
105
+ resource_pool_changed? || networks_changed?
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,413 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ ##
6
+ # Represents a single job instance.
7
+ class Instance
8
+ include DnsHelper
9
+
10
+ # @return [DeploymentPlan::Job] Associated job
11
+ attr_reader :job
12
+
13
+ # @return [Integer] Instance index
14
+ attr_reader :index
15
+
16
+ # @return [Models::Instance] Instance model
17
+ attr_reader :model
18
+
19
+ # @return [String] Checksum all of the configuration templates
20
+ attr_accessor :configuration_hash
21
+
22
+ # @return [Hash] A hash of template SHA1 hashes.
23
+ attr_accessor :template_hashes
24
+
25
+ # @return [Hash<String, NetworkReservation>] network reservations
26
+ attr_accessor :network_reservations
27
+
28
+ # @return [String] job state
29
+ attr_accessor :state
30
+
31
+ # @return [Hash] current state as provided by the BOSH Agent
32
+ attr_accessor :current_state
33
+
34
+ # @return [DeploymentPlan::IdleVm] Associated resource pool VM
35
+ attr_reader :idle_vm
36
+
37
+ # @return [Boolean] true if this instance needs to be recreated
38
+ attr_accessor :recreate
39
+
40
+ # @return [Boolean] true if this instance needs to be restarted
41
+ attr_accessor :restart
42
+
43
+ ##
44
+ # Creates a new instance specification based on the job and index.
45
+ #
46
+ # @param [DeploymentPlan::Job] job associated job
47
+ # @param [Integer] index index for this instance
48
+ def initialize(job, index)
49
+ @job = job
50
+ @index = index
51
+ @model = nil
52
+ @configuration_hash = nil
53
+ @template_hashes = nil
54
+ @idle_vm = nil
55
+ @current_state = nil
56
+
57
+ @network_reservations = {}
58
+ @state = job.instance_state(@index)
59
+
60
+ # Expanding virtual states
61
+ case @state
62
+ when "recreate"
63
+ @recreate = true
64
+ @state = "started"
65
+ when "restart"
66
+ @restart = true
67
+ @state = "started"
68
+ end
69
+ end
70
+
71
+ def to_s
72
+ "#{@job.name}/#{@index}"
73
+ end
74
+
75
+ # @param [Models::Instance] model Instance DB model
76
+ # @return [void]
77
+ def use_model(model)
78
+ if @model
79
+ raise DirectorError, "Instance model is already bound"
80
+ end
81
+ @model = model
82
+ end
83
+
84
+ # Looks up a DB model for this instance, creates one if doesn't exist
85
+ # yet.
86
+ # @return [void]
87
+ def bind_model
88
+ @model ||= find_or_create_model
89
+ end
90
+
91
+ # Looks up instance model in DB and binds it to this instance spec.
92
+ # Instance model is created if it's not found in DB. New idle VM is
93
+ # allocated if instance DB record doesn't reference one.
94
+ # @return [void]
95
+ def bind_unallocated_vm
96
+ bind_model
97
+ if @model.vm.nil?
98
+ allocate_idle_vm
99
+ end
100
+ end
101
+
102
+ # Syncs instance state with instance model in DB. This is needed because
103
+ # not all instance states are available in the deployment manifest and we
104
+ # we cannot really persist this data in the agent state (as VM might be
105
+ # stopped or detached).
106
+ # @return [void]
107
+ def sync_state_with_db
108
+ if @model.nil?
109
+ raise DirectorError, "Instance `#{self}' model is not bound"
110
+ end
111
+
112
+ if @state
113
+ # Deployment plan explicitly sets state for this instance
114
+ @model.update(:state => @state)
115
+ elsif @model.state
116
+ # Instance has its state persisted from the previous deployment
117
+ @state = @model.state
118
+ else
119
+ # Target instance state should either be persisted in DB or provided
120
+ # via deployment plan, otherwise something is really wrong
121
+ raise InstanceTargetStateUndefined,
122
+ "Instance `#{self}' target state cannot be determined"
123
+ end
124
+ end
125
+
126
+ ##
127
+ # Adds a new network to this instance
128
+ # @param [String] name network name
129
+ # @param [NetworkReservation] reservation
130
+ def add_network_reservation(name, reservation)
131
+ old_reservation = @network_reservations[name]
132
+
133
+ if old_reservation
134
+ raise NetworkReservationAlreadyExists,
135
+ "`#{self}' already has reservation " +
136
+ "for network `#{name}', IP #{old_reservation.ip}"
137
+ end
138
+ @network_reservations[name] = reservation
139
+ end
140
+
141
+ ##
142
+ # Take any existing valid network reservations
143
+ #
144
+ # @param [Hash<String, NetworkReservation] reservations
145
+ # @return [void]
146
+ def take_network_reservations(reservations)
147
+ reservations.each do |name, provided_reservation|
148
+ reservation = @network_reservations[name]
149
+ reservation.take(provided_reservation) if reservation
150
+ end
151
+ end
152
+
153
+ ##
154
+ # @return [Hash] BOSH network settings used for Agent apply call
155
+ def network_settings
156
+ default_properties = {}
157
+ @job.default_network.each do |key, value|
158
+ (default_properties[value] ||= []) << key
159
+ end
160
+
161
+ network_settings = {}
162
+ @network_reservations.each do |name, reservation|
163
+ network = @job.deployment.network(name)
164
+ network_settings[name] = network.network_settings(reservation, default_properties[name])
165
+ network_settings[name]['dns_record_name'] = dns_record_name(name)
166
+
167
+ # Somewhat of a hack: for dynamic networks we might know IP address, Netmask & Gateway
168
+ # if they're featured in agent state, in that case we put them into network spec to satisfy
169
+ # ConfigurationHasher in both agent and director.
170
+ if @current_state.is_a?(Hash) &&
171
+ @current_state['networks'].is_a?(Hash) &&
172
+ @current_state['networks'][name].is_a?(Hash) &&
173
+ network_settings[name]['type'] == 'dynamic'
174
+ %w(ip netmask gateway).each do |key|
175
+ network_settings[name][key] = @current_state['networks'][name][key]
176
+ end
177
+ end
178
+ end
179
+ network_settings
180
+ end
181
+
182
+ ##
183
+ # @return [Integer] persistent disk size
184
+ def disk_size
185
+ if @model.nil?
186
+ current_state["persistent_disk"].to_i
187
+ elsif @model.persistent_disk
188
+ @model.persistent_disk.size
189
+ else
190
+ 0
191
+ end
192
+ end
193
+
194
+ ##
195
+ # @return [Hash<String, String>] dns record hash of dns name and IP
196
+ def dns_record_info
197
+ dns_record_info = {}
198
+ network_settings.each do |network_name, network|
199
+ name = dns_record_name(network_name)
200
+ dns_record_info[name] = network["ip"]
201
+ end
202
+ dns_record_info
203
+ end
204
+
205
+ ##
206
+ # @return [String] dns record name
207
+ def dns_record_name(network_name)
208
+ [index, job.canonical_name, canonical(network_name), job.deployment.canonical_name, dns_domain_name].join(".")
209
+ end
210
+
211
+ ##
212
+ # @return [Boolean] returns true if the persistent disk is attached to the
213
+ # VM
214
+ def disk_currently_attached?
215
+ current_state["persistent_disk"].to_i > 0
216
+ end
217
+
218
+ ##
219
+ # @return [Boolean] returns true if the network configuration changed
220
+ def networks_changed?
221
+ network_settings != @current_state["networks"]
222
+ end
223
+
224
+ ##
225
+ # @return [Boolean] returns true if the expected resource pool differs
226
+ # from the one provided by the VM
227
+ def resource_pool_changed?
228
+ if @recreate || @job.deployment.recreate
229
+ return true
230
+ end
231
+
232
+ if @job.resource_pool.spec != @current_state["resource_pool"]
233
+ return true
234
+ end
235
+
236
+ # env is not a part of a resource pool spec but rather gets persisted
237
+ # in director DB, hence the check below
238
+ # NOTE: we only update VMs that have env persisted to avoid recreating
239
+ # everything, so if the director gets updated from the version that
240
+ # doesn't persist VM env to the version that does, there needs to
241
+ # be at least one deployment that recreates all VMs before the following
242
+ # code path gets exercised.
243
+ if @model && @model.vm && @model.vm.env &&
244
+ @job.resource_pool.env != @model.vm.env
245
+ return true
246
+ end
247
+
248
+ false
249
+ end
250
+
251
+ ##
252
+ # @return [Boolean] returns true if the expected configuration hash
253
+ # differs from the one provided by the VM
254
+ def configuration_changed?
255
+ configuration_hash != @current_state["configuration_hash"]
256
+ end
257
+
258
+ ##
259
+ # @return [Boolean] returns true if the expected job configuration differs
260
+ # from the one provided by the VM
261
+ def job_changed?
262
+ job_spec = @job.spec
263
+ if job_spec != @current_state["job"]
264
+ # The agent job spec could be in legacy form. job_spec cannot be,
265
+ # though, because we got it from the spec function in job.rb which
266
+ # automatically makes it non-legacy.
267
+ return job_spec != Job.convert_from_legacy_spec(@current_state["job"])
268
+ end
269
+ return false
270
+ end
271
+
272
+ ##
273
+ # @return [Boolean] returns true if the expected packaged of the running
274
+ # instance differ from the ones provided by the VM
275
+ def packages_changed?
276
+ @job.package_spec != @current_state["packages"]
277
+ end
278
+
279
+ ##
280
+ # @return [Boolean] returns true if the expected persistent disk differs
281
+ # from the one currently configured on the VM
282
+ def persistent_disk_changed?
283
+ @job.persistent_disk != disk_size
284
+ end
285
+
286
+ ##
287
+ # @return [Boolean] returns true if the DNS records configured for the
288
+ # instance differ from the ones configured on the DNS server
289
+ def dns_changed?
290
+ if Config.dns_enabled?
291
+ dns_record_info.any? do |name, ip|
292
+ Models::Dns::Record.find(:name => name, :type => "A",
293
+ :content => ip).nil?
294
+ end
295
+ else
296
+ false
297
+ end
298
+ end
299
+
300
+ ##
301
+ # Checks if agent view of the instance state is consistent with target
302
+ # instance state.
303
+ #
304
+ # In case the instance current state is 'detached' we should never get to
305
+ # this method call.
306
+ # @return [Boolean] returns true if the expected job state differs from
307
+ # the one provided by the VM
308
+ def state_changed?
309
+ @state == "detached" ||
310
+ @state == "started" && @current_state["job_state"] != "running" ||
311
+ @state == "stopped" && @current_state["job_state"] == "running"
312
+ end
313
+
314
+ ##
315
+ # @return [Boolean] returns true if the any of the expected specifications
316
+ # differ from the ones provided by the VM
317
+ def changed?
318
+ !changes.empty?
319
+ end
320
+
321
+ ##
322
+ # @return [Set<Symbol>] returns a set of all of the specification
323
+ # differences
324
+ def changes
325
+ changes = Set.new
326
+ unless @state == "detached" && @current_state.nil?
327
+ changes << :restart if @restart
328
+ changes << :resource_pool if resource_pool_changed?
329
+ changes << :network if networks_changed?
330
+ changes << :packages if packages_changed?
331
+ changes << :persistent_disk if persistent_disk_changed?
332
+ changes << :configuration if configuration_changed?
333
+ changes << :job if job_changed?
334
+ changes << :state if state_changed?
335
+ changes << :dns if dns_changed?
336
+ end
337
+ changes
338
+ end
339
+
340
+ ##
341
+ # Instance spec that's passed to the VM during the BOSH Agent apply call.
342
+ # It's what's used for comparing the expected vs the actual state.
343
+ #
344
+ # @return [Hash<String, Object>] instance spec
345
+ def spec
346
+ spec = {
347
+ "deployment" => @job.deployment.name,
348
+ "release" => job.release.spec,
349
+ "job" => job.spec,
350
+ "index" => index,
351
+ "networks" => network_settings,
352
+ "resource_pool" => job.resource_pool.spec,
353
+ "packages" => job.package_spec,
354
+ "persistent_disk" => job.persistent_disk,
355
+ "configuration_hash" => configuration_hash,
356
+ "properties" => job.properties,
357
+ "dns_domain_name" => dns_domain_name
358
+ }
359
+
360
+ if template_hashes
361
+ spec["template_hashes"] = template_hashes
362
+ end
363
+
364
+ spec
365
+ end
366
+
367
+ # Looks up instance model in DB
368
+ # @return [Models::Instance]
369
+ def find_or_create_model
370
+ if @job.deployment.model.nil?
371
+ raise DirectorError, "Deployment model is not bound"
372
+ end
373
+
374
+ conditions = {
375
+ :deployment_id => @job.deployment.model.id,
376
+ :job => @job.name,
377
+ :index => @index
378
+ }
379
+
380
+ Models::Instance.find_or_create(conditions) do |model|
381
+ model.state = "started"
382
+ end
383
+ end
384
+
385
+ # Allocates an idle VM in this job resource pool and binds current
386
+ # instance to that idle VM.
387
+ # @return [void]
388
+ def allocate_idle_vm
389
+ resource_pool = @job.resource_pool
390
+ idle_vm = resource_pool.allocate_vm
391
+ network = resource_pool.network
392
+
393
+ if idle_vm.vm
394
+ # There's already a resource pool VM that can become our instance,
395
+ # so we can try to reuse its reservation
396
+ instance_reservation = @network_reservations[network.name]
397
+ if instance_reservation
398
+ instance_reservation.take(idle_vm.network_reservation)
399
+ end
400
+ else
401
+ # VM is not created yet: let's just make it reference this instance
402
+ # so later it knows what it needs to become
403
+ idle_vm.bound_instance = self
404
+ # this also means we no longer need previous VM network reservation
405
+ # (instance has its own)
406
+ idle_vm.release_reservation
407
+ end
408
+
409
+ @idle_vm = idle_vm
410
+ end
411
+ end
412
+ end
413
+ end