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