bosh-director 1.3160.0 → 1.3163.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bosh-director-worker +2 -14
  3. data/db/migrations/director/20150513225143_ip_addresses.rb +11 -0
  4. data/db/migrations/director/20150702004608_add_links.rb +8 -0
  5. data/db/migrations/director/20150708231924_add_link_spec.rb +7 -0
  6. data/db/migrations/director/20150724183256_add_debugging_to_ip_addresses.rb +8 -0
  7. data/db/migrations/director/20150730225029_add_uuid_to_instances.rb +16 -0
  8. data/db/migrations/director/20150803215805_add_availabililty_zone_and_cloud_properties_to_instances.rb +8 -0
  9. data/db/migrations/director/20150804211419_add_compilation_flag_to_instance.rb +7 -0
  10. data/db/migrations/director/20150918003455_add_bootstrap_node_to_instance.rb +7 -0
  11. data/db/migrations/director/20151008232214_add_dns_records.rb +7 -0
  12. data/db/migrations/director/20151015172551_add_orphan_disks_and_snapshots.rb +29 -0
  13. data/db/migrations/director/20151030222853_add_templates_to_instance.rb +10 -0
  14. data/db/migrations/director/20151031001039_add_spec_to_instance.rb +19 -0
  15. data/db/migrations/director/20151109190602_rename_orphan_columns.rb +13 -0
  16. data/lib/bosh/director.rb +19 -9
  17. data/lib/bosh/director/agent_client.rb +0 -17
  18. data/lib/bosh/director/api/cloud_config_manager.rb +7 -5
  19. data/lib/bosh/director/api/controllers/base_controller.rb +3 -2
  20. data/lib/bosh/director/api/controllers/cleanup_controller.rb +15 -0
  21. data/lib/bosh/director/api/controllers/deployments_controller.rb +38 -26
  22. data/lib/bosh/director/api/controllers/disks_controller.rb +20 -0
  23. data/lib/bosh/director/api/controllers/info_controller.rb +2 -2
  24. data/lib/bosh/director/api/controllers/releases_controller.rb +1 -16
  25. data/lib/bosh/director/api/controllers/stemcells_controller.rb +1 -9
  26. data/lib/bosh/director/api/deployment_manager.rb +2 -1
  27. data/lib/bosh/director/api/instance_lookup.rb +17 -0
  28. data/lib/bosh/director/api/instance_manager.rb +20 -10
  29. data/lib/bosh/director/api/release_manager.rb +28 -8
  30. data/lib/bosh/director/api/resurrector_manager.rb +9 -2
  31. data/lib/bosh/director/api/route_configuration.rb +2 -0
  32. data/lib/bosh/director/api/snapshot_manager.rb +9 -5
  33. data/lib/bosh/director/api/stemcell_manager.rb +50 -0
  34. data/lib/bosh/director/app.rb +1 -1
  35. data/lib/bosh/director/cloudcheck_helper.rb +119 -132
  36. data/lib/bosh/director/compile_task.rb +1 -1
  37. data/lib/bosh/director/compile_task_generator.rb +2 -2
  38. data/lib/bosh/director/config.rb +21 -12
  39. data/lib/bosh/director/deployment_deleter.rb +69 -0
  40. data/lib/bosh/director/deployment_plan.rb +35 -4
  41. data/lib/bosh/director/deployment_plan/agent_state_migrator.rb +47 -0
  42. data/lib/bosh/director/deployment_plan/assembler.rb +115 -241
  43. data/lib/bosh/director/deployment_plan/availability_zone.rb +27 -0
  44. data/lib/bosh/director/deployment_plan/cloud_manifest_parser.rb +144 -35
  45. data/lib/bosh/director/deployment_plan/compilation_config.rb +21 -19
  46. data/lib/bosh/director/deployment_plan/compilation_instance_pool.rb +169 -0
  47. data/lib/bosh/director/deployment_plan/deployment_repo.rb +4 -8
  48. data/lib/bosh/director/deployment_plan/deployment_spec_parser.rb +13 -1
  49. data/lib/bosh/director/deployment_plan/deployment_validator.rb +17 -0
  50. data/lib/bosh/director/deployment_plan/desired_instance.rb +15 -0
  51. data/lib/bosh/director/deployment_plan/{disk_pool.rb → disk_type.rb} +14 -19
  52. data/lib/bosh/director/deployment_plan/dynamic_network.rb +105 -53
  53. data/lib/bosh/director/deployment_plan/dynamic_network_subnet.rb +13 -0
  54. data/lib/bosh/director/deployment_plan/env.rb +18 -0
  55. data/lib/bosh/director/deployment_plan/global_network_resolver.rb +77 -0
  56. data/lib/bosh/director/deployment_plan/instance.rb +222 -390
  57. data/lib/bosh/director/deployment_plan/instance_network_reservations.rb +71 -0
  58. data/lib/bosh/director/deployment_plan/instance_plan.rb +336 -0
  59. data/lib/bosh/director/deployment_plan/instance_plan_factory.rb +54 -0
  60. data/lib/bosh/director/deployment_plan/instance_plan_sorter.rb +61 -0
  61. data/lib/bosh/director/deployment_plan/instance_planner.rb +101 -0
  62. data/lib/bosh/director/deployment_plan/instance_repository.rb +36 -0
  63. data/lib/bosh/director/deployment_plan/instance_spec.rb +154 -0
  64. data/lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb +136 -0
  65. data/lib/bosh/director/deployment_plan/ip_provider/in_memory_ip_repo.rb +81 -0
  66. data/lib/bosh/director/deployment_plan/ip_provider/ip_provider.rb +153 -0
  67. data/lib/bosh/director/deployment_plan/ip_provider/ip_provider_factory.rb +22 -0
  68. data/lib/bosh/director/deployment_plan/job.rb +116 -53
  69. data/lib/bosh/director/deployment_plan/job_availability_zone_parser.rb +49 -0
  70. data/lib/bosh/director/deployment_plan/job_migrator.rb +90 -0
  71. data/lib/bosh/director/deployment_plan/job_network.rb +42 -0
  72. data/lib/bosh/director/deployment_plan/job_network_parser.rb +118 -0
  73. data/lib/bosh/director/deployment_plan/job_spec_parser.rb +123 -126
  74. data/lib/bosh/director/deployment_plan/links/link.rb +30 -0
  75. data/lib/bosh/director/deployment_plan/links/link_lookup.rb +66 -0
  76. data/lib/bosh/director/deployment_plan/links/link_path.rb +27 -0
  77. data/lib/bosh/director/deployment_plan/links/links_resolver.rb +70 -0
  78. data/lib/bosh/director/deployment_plan/links/template_link.rb +21 -0
  79. data/lib/bosh/director/deployment_plan/manifest_migrator.rb +3 -17
  80. data/lib/bosh/director/deployment_plan/manifest_validator.rb +46 -0
  81. data/lib/bosh/director/deployment_plan/manual_network.rb +70 -97
  82. data/lib/bosh/director/deployment_plan/manual_network_subnet.rb +148 -0
  83. data/lib/bosh/director/deployment_plan/network.rb +50 -39
  84. data/lib/bosh/director/deployment_plan/network_planner.rb +4 -0
  85. data/lib/bosh/director/deployment_plan/network_planner/plan.rb +26 -0
  86. data/lib/bosh/director/deployment_plan/network_planner/planner.rb +21 -0
  87. data/lib/bosh/director/deployment_plan/network_planner/reservation_reconciler.rb +81 -0
  88. data/lib/bosh/director/deployment_plan/network_planner/vip_static_ips_planner.rb +50 -0
  89. data/lib/bosh/director/deployment_plan/network_settings.rb +65 -0
  90. data/lib/bosh/director/deployment_plan/options/skip_drain.rb +7 -0
  91. data/lib/bosh/director/deployment_plan/package_validator.rb +79 -0
  92. data/lib/bosh/director/deployment_plan/placement_planner.rb +8 -0
  93. data/lib/bosh/director/deployment_plan/placement_planner/availability_zone_picker.rb +90 -0
  94. data/lib/bosh/director/deployment_plan/placement_planner/bruteforce_ip_allocation.rb +124 -0
  95. data/lib/bosh/director/deployment_plan/placement_planner/index_assigner.rb +32 -0
  96. data/lib/bosh/director/deployment_plan/placement_planner/networks_to_static_ips.rb +125 -0
  97. data/lib/bosh/director/deployment_plan/placement_planner/placed_desired_instances.rb +40 -0
  98. data/lib/bosh/director/deployment_plan/placement_planner/plan.rb +42 -0
  99. data/lib/bosh/director/deployment_plan/placement_planner/static_ips_availability_zone_picker.rb +237 -0
  100. data/lib/bosh/director/deployment_plan/placement_planner/unplaced_existing_instances.rb +53 -0
  101. data/lib/bosh/director/deployment_plan/planner.rb +186 -74
  102. data/lib/bosh/director/deployment_plan/planner_factory.rb +30 -147
  103. data/lib/bosh/director/deployment_plan/release_version.rb +3 -3
  104. data/lib/bosh/director/deployment_plan/resource_pool.rb +2 -174
  105. data/lib/bosh/director/deployment_plan/stemcell.rb +57 -14
  106. data/lib/bosh/director/deployment_plan/steps/package_compile_step.rb +28 -135
  107. data/lib/bosh/director/deployment_plan/steps/update_step.rb +23 -44
  108. data/lib/bosh/director/deployment_plan/template.rb +15 -4
  109. data/lib/bosh/director/deployment_plan/vip_network.rb +14 -42
  110. data/lib/bosh/director/deployment_plan/vm.rb +1 -99
  111. data/lib/bosh/director/deployment_plan/vm_type.rb +27 -0
  112. data/lib/bosh/director/disk_manager.rb +268 -0
  113. data/lib/bosh/director/dns/canonicalizer.rb +28 -0
  114. data/lib/bosh/director/dns/dns_manager.rb +163 -0
  115. data/lib/bosh/director/dns/local_dns_repo.rb +20 -0
  116. data/lib/bosh/director/dns/powerdns.rb +170 -0
  117. data/lib/bosh/director/errand/job_manager.rb +18 -29
  118. data/lib/bosh/director/error_ignorer.rb +16 -0
  119. data/lib/bosh/director/errors.rb +51 -20
  120. data/lib/bosh/director/event_log.rb +6 -0
  121. data/lib/bosh/director/instance_deleter.rb +53 -81
  122. data/lib/bosh/director/instance_reuser.rb +89 -0
  123. data/lib/bosh/director/instance_updater.rb +139 -281
  124. data/lib/bosh/director/instance_updater/preparer.rb +8 -5
  125. data/lib/bosh/director/instance_updater/state_applier.rb +21 -0
  126. data/lib/bosh/director/ip_util.rb +46 -26
  127. data/lib/bosh/director/job_renderer.rb +22 -10
  128. data/lib/bosh/director/job_runner.rb +1 -4
  129. data/lib/bosh/director/job_updater.rb +47 -35
  130. data/lib/bosh/director/job_updater_factory.rb +5 -4
  131. data/lib/bosh/director/jobs/base_job.rb +8 -0
  132. data/lib/bosh/director/jobs/cleanup_artifacts.rb +93 -0
  133. data/lib/bosh/director/jobs/delete_deployment.rb +10 -154
  134. data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +1 -1
  135. data/lib/bosh/director/jobs/delete_orphan_disks.rb +44 -0
  136. data/lib/bosh/director/jobs/delete_release.rb +19 -196
  137. data/lib/bosh/director/jobs/delete_stemcell.rb +10 -76
  138. data/lib/bosh/director/jobs/export_release.rb +41 -121
  139. data/lib/bosh/director/jobs/fetch_logs.rb +0 -6
  140. data/lib/bosh/director/jobs/helpers.rb +10 -0
  141. data/lib/bosh/director/jobs/helpers/blob_deleter.rb +24 -0
  142. data/lib/bosh/director/jobs/helpers/compiled_package_deleter.rb +24 -0
  143. data/lib/bosh/director/jobs/helpers/name_version_release_deleter.rb +48 -0
  144. data/lib/bosh/director/jobs/helpers/package_deleter.rb +33 -0
  145. data/lib/bosh/director/jobs/helpers/release_deleter.rb +52 -0
  146. data/lib/bosh/director/jobs/helpers/release_version_deleter.rb +115 -0
  147. data/lib/bosh/director/jobs/helpers/releases_to_delete_picker.rb +31 -0
  148. data/lib/bosh/director/jobs/helpers/stemcell_deleter.rb +61 -0
  149. data/lib/bosh/director/jobs/helpers/stemcells_to_delete_picker.rb +30 -0
  150. data/lib/bosh/director/jobs/helpers/template_deleter.rb +20 -0
  151. data/lib/bosh/director/jobs/release/release_job.rb +18 -7
  152. data/lib/bosh/director/jobs/run_errand.rb +57 -36
  153. data/lib/bosh/director/jobs/scheduled_orphan_cleanup.rb +46 -0
  154. data/lib/bosh/director/jobs/ssh.rb +50 -17
  155. data/lib/bosh/director/jobs/update_deployment.rb +29 -11
  156. data/lib/bosh/director/jobs/update_release.rb +25 -4
  157. data/lib/bosh/director/jobs/vm_state.rb +23 -32
  158. data/lib/bosh/director/lock.rb +13 -8
  159. data/lib/bosh/director/logs_fetcher.rb +1 -1
  160. data/lib/bosh/director/models.rb +3 -0
  161. data/lib/bosh/director/models/compiled_package.rb +3 -3
  162. data/lib/bosh/director/models/deployment.rb +10 -0
  163. data/lib/bosh/director/models/instance.rb +77 -1
  164. data/lib/bosh/director/models/ip_address.rb +26 -0
  165. data/lib/bosh/director/models/orphan_disk.rb +23 -0
  166. data/lib/bosh/director/models/orphan_snapshot.rb +14 -0
  167. data/lib/bosh/director/models/template.rb +32 -9
  168. data/lib/bosh/director/models/vm.rb +5 -8
  169. data/lib/bosh/director/network_reservation.rb +69 -99
  170. data/lib/bosh/director/problem_handlers/inactive_disk.rb +5 -20
  171. data/lib/bosh/director/problem_handlers/missing_disk.rb +2 -13
  172. data/lib/bosh/director/problem_resolver.rb +2 -2
  173. data/lib/bosh/director/problem_scanner/vm_scan_stage.rb +2 -21
  174. data/lib/bosh/director/scheduler.rb +23 -6
  175. data/lib/bosh/director/{instance_updater/stopper.rb → stopper.rb} +24 -18
  176. data/lib/bosh/director/tagged_logger.rb +30 -0
  177. data/lib/bosh/director/transactor.rb +9 -0
  178. data/lib/bosh/director/version.rb +1 -1
  179. data/lib/bosh/director/vm_creator.rb +91 -19
  180. data/lib/bosh/director/vm_deleter.rb +25 -0
  181. data/lib/bosh/director/vm_recreator.rb +15 -0
  182. data/lib/cloud/dummy.rb +381 -94
  183. metadata +110 -30
  184. data/lib/bosh/director/deployment_plan/dns_binder.rb +0 -45
  185. data/lib/bosh/director/deployment_plan/instance_vm_binder.rb +0 -37
  186. data/lib/bosh/director/deployment_plan/network_subnet.rb +0 -166
  187. data/lib/bosh/director/deployment_plan/resource_pools.rb +0 -68
  188. data/lib/bosh/director/dns_helper.rb +0 -223
  189. data/lib/bosh/director/instance_updater/network_updater.rb +0 -110
  190. data/lib/bosh/director/instance_updater/vm_updater.rb +0 -189
  191. data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +0 -64
  192. data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +0 -85
  193. data/lib/bosh/director/resource_pool_updater.rb +0 -174
  194. data/lib/bosh/director/vm_data.rb +0 -63
  195. data/lib/bosh/director/vm_reuser.rb +0 -63
@@ -1,15 +1,15 @@
1
+ require 'securerandom'
2
+
1
3
  module Bosh::Director
2
4
  module DeploymentPlan
3
5
  # Represents a single job instance.
4
6
  class Instance
5
- include DnsHelper
6
-
7
- # @return [DeploymentPlan::Job] Associated job
8
- attr_reader :job
9
7
 
10
8
  # @return [Integer] Instance index
11
9
  attr_reader :index
12
10
 
11
+ attr_reader :uuid
12
+
13
13
  # @return [Models::Instance] Instance model
14
14
  attr_reader :model
15
15
 
@@ -22,350 +22,251 @@ module Bosh::Director
22
22
  # @return [Bosh::Director::Core::Templates::RenderedTemplatesArchive]
23
23
  attr_accessor :rendered_templates_archive
24
24
 
25
- # @return [Hash<String, NetworkReservation>] network reservations
26
- attr_accessor :network_reservations
27
-
28
25
  # @return [String] job state
29
- attr_accessor :state
26
+ attr_reader :virtual_state
30
27
 
31
- # @return [Hash] current state as provided by the BOSH Agent
32
28
  attr_reader :current_state
33
29
 
30
+ attr_reader :availability_zone
31
+
34
32
  # @return [DeploymentPlan::Vm] Associated resource pool VM
35
33
  attr_reader :vm
36
34
 
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
- # Creates a new instance specification based on the job and index.
44
- # @param [DeploymentPlan::Job] job associated job
45
- # @param [Integer] index index for this instance
46
- def initialize(job, index, logger)
47
- @job = job
35
+ attr_reader :existing_network_reservations
36
+
37
+ def self.create_from_job(job, index, virtual_state, deployment_model, instance_state, availability_zone, logger)
38
+ new(
39
+ job.name,
40
+ index,
41
+ virtual_state,
42
+ job.vm_type,
43
+ job.stemcell,
44
+ job.env,
45
+ job.compilation?,
46
+ deployment_model,
47
+ instance_state,
48
+ availability_zone,
49
+ logger
50
+ )
51
+ end
52
+
53
+ def initialize(
54
+ job_name,
55
+ index,
56
+ virtual_state,
57
+ vm_type,
58
+ stemcell,
59
+ env,
60
+ compilation,
61
+ deployment_model,
62
+ instance_state,
63
+ availability_zone,
64
+ logger
65
+ )
48
66
  @index = index
67
+ @availability_zone = availability_zone
49
68
  @logger = logger
69
+ @deployment_model = deployment_model
70
+ @job_name = job_name
71
+ @name = "#{job_name}/#{@index}"
72
+ @vm_type = vm_type
73
+ @stemcell = stemcell
74
+ @env = env
75
+ @compilation = compilation
50
76
 
51
77
  @configuration_hash = nil
52
78
  @template_hashes = nil
53
79
  @vm = nil
54
- @current_state = nil
80
+ @current_state = instance_state || {}
55
81
 
56
- @network_reservations = {}
57
- @state = job.instance_state(@index)
82
+ # reservation generated from current state/DB
83
+ @existing_network_reservations = InstanceNetworkReservations.new(logger)
84
+ @dns_manager = DnsManager.create
58
85
 
59
- # Expanding virtual states
60
- case @state
61
- when 'recreate'
62
- @recreate = true
63
- @state = 'started'
64
- when 'restart'
65
- @restart = true
66
- @state = 'started'
67
- end
86
+ @virtual_state = virtual_state
87
+ end
88
+
89
+ def bootstrap?
90
+ @model && @model.bootstrap
91
+ end
92
+
93
+ def compilation?
94
+ @compilation
95
+ end
96
+
97
+ def job_name
98
+ @job_name
68
99
  end
69
100
 
70
101
  def to_s
71
- "#{@job.name}/#{@index}"
102
+ @name
72
103
  end
73
104
 
74
105
  # Looks up instance model in DB and binds it to this instance spec.
75
106
  # Instance model is created if it's not found in DB. New VM is
76
107
  # allocated if instance DB record doesn't reference one.
77
108
  # @return [void]
109
+ # TODO: This should just be responsible to allocating the VMs and not creating instance_models
78
110
  def bind_unallocated_vm
79
- @model ||= find_or_create_model
80
- if @model.vm.nil?
81
- allocate_vm
82
- end
111
+ ensure_model_bound
112
+ ensure_vm_allocated
83
113
  end
84
114
 
85
- ##
86
- # Updates this domain object to reflect an existing instance running on an existing vm
87
- def bind_existing_instance(instance_model, state, reservations)
88
- check_model_not_bound
89
-
90
- @model = instance_model
91
- @current_state = state
92
-
93
- take_network_reservations(reservations)
94
- add_allocated_vm(instance_model.vm, state)
115
+ def ensure_model_bound
116
+ @model ||= find_or_create_model
95
117
  end
96
118
 
97
- def apply_partial_vm_state
98
- @logger.info('Applying partial VM state')
99
-
100
- state = @vm.current_state
101
- state['job'] = job.spec
102
- state['index'] = index
103
-
104
- # Apply the assignment to the VM
105
- agent = AgentClient.with_defaults(@vm.model.agent_id)
106
- agent.apply(state)
107
-
108
- # Our assumption here is that director database access
109
- # is much less likely to fail than VM agent communication
110
- # so we only update database after we see a successful agent apply.
111
- # If database update fails subsequent deploy will try to
112
- # assign a new VM to this instance which is ok.
113
- @vm.model.db.transaction do
114
- @vm.model.update(:apply_spec => state)
115
- @model.update(:vm => @vm.model)
116
- end
117
-
118
- @current_state = state
119
+ def bind_new_instance_model
120
+ @model = Models::Instance.create({
121
+ deployment_id: @deployment_model.id,
122
+ job: @job_name,
123
+ index: index,
124
+ state: state,
125
+ compilation: @compilation,
126
+ uuid: SecureRandom.uuid,
127
+ bootstrap: false
128
+ })
129
+ @uuid = @model.uuid
119
130
  end
120
131
 
121
- def apply_vm_state
122
- @logger.info('Applying VM state')
123
-
124
- state = {
125
- 'deployment' => @job.deployment.name,
126
- 'networks' => network_settings,
127
- 'resource_pool' => @job.resource_pool.spec,
128
- 'job' => @job.spec,
129
- 'index' => @index,
130
- }
131
-
132
- if disk_size > 0
133
- state['persistent_disk'] = disk_size
132
+ def ensure_vm_allocated
133
+ @uuid = @model.uuid
134
+ if @model.vm.nil?
135
+ allocate_vm
134
136
  end
137
+ end
135
138
 
136
- @model.vm.update(:apply_spec => state)
139
+ def vm_type
140
+ @vm_type
141
+ end
137
142
 
138
- agent = AgentClient.with_defaults(@model.vm.agent_id)
139
- agent.apply(state)
143
+ def stemcell
144
+ @stemcell
145
+ end
140
146
 
141
- # Agent will potentially return modified version of state
142
- # with resolved dynamic networks information
143
- @current_state = agent.get_state
147
+ def env
148
+ @env.spec
144
149
  end
145
150
 
146
- ##
147
- # Syncs instance state with instance model in DB. This is needed because
148
- # not all instance states are available in the deployment manifest and we
149
- # we cannot really persist this data in the agent state (as VM might be
150
- # stopped or detached).
151
- # @return [void]
152
- def sync_state_with_db
153
- check_model_bound
154
-
155
- if @state
156
- # Deployment plan explicitly sets state for this instance
157
- @model.update(:state => @state)
158
- elsif @model.state
159
- # Instance has its state persisted from the previous deployment
160
- @state = @model.state
161
- else
162
- # Target instance state should either be persisted in DB or provided
163
- # via deployment plan, otherwise something is really wrong
164
- raise InstanceTargetStateUndefined,
165
- "Instance `#{self}' target state cannot be determined"
166
- end
151
+ def deployment_model
152
+ @deployment_model
167
153
  end
168
154
 
169
- ##
170
- # Adds a new network to this instance
171
- # @param [String] name network name
172
- # @param [NetworkReservation] reservation
173
- def add_network_reservation(name, reservation)
174
- old_reservation = @network_reservations[name]
175
-
176
- if old_reservation
177
- raise NetworkReservationAlreadyExists,
178
- "`#{self}' already has reservation " +
179
- "for network `#{name}', IP #{old_reservation.ip}"
180
- end
181
- @network_reservations[name] = reservation
155
+ # Updates this domain object to reflect an existing instance running on an existing vm
156
+ def bind_existing_instance_model(existing_instance_model)
157
+ @uuid = existing_instance_model.uuid
158
+ check_model_not_bound
159
+ @model = existing_instance_model
160
+ allocate_vm
161
+ @vm.model = existing_instance_model.vm
182
162
  end
183
163
 
184
- ##
185
- # @return [Hash] BOSH network settings used for Agent apply call
186
- def network_settings
187
- default_properties = {}
188
- @job.default_network.each do |key, value|
189
- (default_properties[value] ||= []) << key
190
- end
164
+ def bind_existing_reservations(reservations)
165
+ @existing_network_reservations = reservations
166
+ end
191
167
 
192
- network_settings = {}
193
- @network_reservations.each do |name, reservation|
194
- network = @job.deployment.network(name)
195
- network_settings[name] = network.network_settings(reservation, default_properties[name])
196
-
197
- # Temporary hack for running errands.
198
- # We need to avoid RunErrand task thinking that
199
- # network configuration for errand VM differs
200
- # from network configuration for its Instance.
201
- #
202
- # Obviously this does not account for other changes
203
- # in network configuration that errand job might need.
204
- # (e.g. errand job desires static ip)
205
- if @job.starts_on_deploy?
206
- network_settings[name]['dns_record_name'] = dns_record_name(name)
207
- end
168
+ def apply_vm_state(spec)
169
+ @logger.info('Applying VM state')
208
170
 
209
- # Somewhat of a hack: for dynamic networks we might know IP address, Netmask & Gateway
210
- # if they're featured in agent state, in that case we put them into network spec to satisfy
211
- # ConfigurationHasher in both agent and director.
212
- if @current_state.is_a?(Hash) &&
213
- @current_state['networks'].is_a?(Hash) &&
214
- @current_state['networks'][name].is_a?(Hash) &&
215
- network_settings[name]['type'] == 'dynamic'
216
- %w(ip netmask gateway).each do |key|
217
- network_settings[name][key] = @current_state['networks'][name][key]
218
- end
219
- end
220
- end
221
- network_settings
171
+ @current_state = spec.full_spec
172
+ agent_client.apply(spec.as_apply_spec)
173
+ @model.update(spec: @current_state)
222
174
  end
223
175
 
224
- ##
225
- # @return [Integer] persistent disk size
226
- def disk_size
227
- check_model_bound
176
+ def apply_initial_vm_state(spec)
177
+ # Agent will return dynamic network settings, we need to update spec with it
178
+ # so that we can render templates with new spec later.
179
+ agent_spec_keys = ['networks', 'deployment', 'job', 'index', 'id']
180
+ agent_partial_state = spec.as_apply_spec.select { |k, _| agent_spec_keys.include?(k) }
181
+ agent_client.apply(agent_partial_state)
228
182
 
229
- if @model.persistent_disk
230
- @model.persistent_disk.size
231
- else
232
- 0
183
+ instance_spec_keys = agent_spec_keys + ['stemcell', 'vm_type']
184
+ instance_partial_state = spec.full_spec.select { |k, _| instance_spec_keys.include?(k) }
185
+ @current_state.merge!(instance_partial_state)
186
+
187
+ agent_state = agent_client.get_state
188
+ unless agent_state.nil?
189
+ @current_state['networks'] = agent_state['networks']
190
+ @model.update(spec: @current_state)
233
191
  end
234
192
  end
235
193
 
236
- ##
237
- # @return [Hash] persistent disk cloud properties
238
- def disk_cloud_properties
239
- check_model_bound
194
+ def update_trusted_certs
195
+ agent_client.update_settings(Config.trusted_certs)
196
+ @model.vm.update(:trusted_certs_sha1 => Digest::SHA1.hexdigest(Config.trusted_certs))
197
+ end
240
198
 
241
- if @model.persistent_disk
242
- @model.persistent_disk.cloud_properties
243
- else
244
- {}
245
- end
199
+ def update_cloud_properties!
200
+ @model.update(cloud_properties: JSON.dump(cloud_properties))
246
201
  end
247
202
 
248
- ##
249
- # @return [Hash<String, String>] dns record hash of dns name and IP
250
- def dns_record_info
251
- dns_record_info = {}
252
- network_settings.each do |network_name, network|
253
- name = dns_record_name(network_name)
254
- dns_record_info[name] = network['ip']
255
- end
256
- dns_record_info
203
+ def agent_client
204
+ @agent_client ||= AgentClient.with_vm(@model.vm)
257
205
  end
258
206
 
259
207
  ##
260
208
  # @return [String] dns record name
261
- def dns_record_name(network_name)
262
- [index, job.canonical_name, canonical(network_name), job.deployment.canonical_name, dns_domain_name].join('.')
209
+ def dns_record_name(hostname, network_name)
210
+ [hostname, job.canonical_name, Canonicalizer.canonicalize(network_name), Canonicalizer.canonicalize(@deployment_model.name), @dns_manager.dns_domain_name].join('.')
263
211
  end
264
212
 
265
- ##
266
- # @return [Boolean] returns true if the persistent disk is attached to the VM
267
- def disk_currently_attached?
268
- current_state['persistent_disk'].to_i > 0
213
+ def cloud_properties_changed?
214
+ changed = cloud_properties != @model.cloud_properties_hash
215
+ log_changes(__method__, @model.cloud_properties_hash, cloud_properties) if changed
216
+ changed
269
217
  end
270
218
 
271
219
  ##
272
- # @return [Boolean] returns true if the network configuration changed
273
- def networks_changed?
274
- network_settings != @current_state['networks']
220
+ # @return [Boolean] returns true if the expected configuration hash
221
+ # differs from the one provided by the VM
222
+ def configuration_changed?
223
+ changed = configuration_hash != @current_state['configuration_hash']
224
+ log_changes(__method__, @current_state['configuration_hash'], configuration_hash) if changed
225
+ changed
275
226
  end
276
227
 
277
- ##
278
- # @return [Boolean] returns true if the expected resource pool differs from the one provided by the VM
279
- def resource_pool_changed?
280
- if @recreate || @job.deployment.recreate
281
- return true
282
- end
283
-
284
- if @job.resource_pool.spec != @current_state['resource_pool']
285
- return true
286
- end
287
-
288
- # env is not a part of a resource pool spec but rather gets persisted
289
- # in director DB, hence the check below
290
- # NOTE: we only update VMs that have env persisted to avoid recreating
291
- # everything, so if the director gets updated from the version that
292
- # doesn't persist VM env to the version that does, there needs to
293
- # be at least one deployment that recreates all VMs before the following
294
- # code path gets exercised.
295
- if @model && @model.vm && @model.vm.env && @job.resource_pool.env != @model.vm.env
296
- return true
297
- end
228
+ def current_job_spec
229
+ @current_state['job']
230
+ end
298
231
 
299
- false
232
+ def current_packages
233
+ @current_state['packages']
300
234
  end
301
235
 
302
- ##
303
- # @return [Boolean] returns true if the expected configuration hash
304
- # differs from the one provided by the VM
305
- def configuration_changed?
306
- configuration_hash != @current_state['configuration_hash']
236
+ def current_job_state
237
+ @current_state['job_state']
307
238
  end
308
239
 
309
- ##
310
- # @return [Boolean] returns true if the expected job configuration differs
311
- # from the one provided by the VM
312
- def job_changed?
313
- return true if @current_state.nil?
314
-
315
- job_spec = @job.spec
316
- if job_spec != @current_state['job']
317
- # The agent job spec could be in legacy form. job_spec cannot be,
318
- # though, because we got it from the spec function in job.rb which
319
- # automatically makes it non-legacy.
320
- return job_spec != Job.convert_from_legacy_spec(@current_state['job'])
321
- end
322
- return false
240
+ def update_state
241
+ @model.update(state: state)
323
242
  end
324
243
 
325
- ##
326
- # @return [Boolean] returns true if the expected packaged of the running
327
- # instance differ from the ones provided by the VM
328
- def packages_changed?
329
- @job.package_spec != @current_state['packages']
244
+ def update_description
245
+ @model.update(job: job_name, index: index)
330
246
  end
331
247
 
332
- ##
333
- # @return [Boolean] returns true if the expected persistent disk or cloud_properties differs
334
- # from the state currently configured on the VM
335
- def persistent_disk_changed?
336
- new_disk_size = @job.persistent_disk_pool ? @job.persistent_disk_pool.disk_size : 0
337
- new_disk_cloud_properties = @job.persistent_disk_pool ? @job.persistent_disk_pool.cloud_properties : {}
338
- return true if new_disk_size != disk_size
248
+ def mark_as_bootstrap
249
+ @model.update(bootstrap: true)
250
+ end
339
251
 
340
- new_disk_size != 0 && new_disk_cloud_properties != disk_cloud_properties
252
+ def unmark_as_bootstrap
253
+ @model.update(bootstrap: false)
341
254
  end
342
255
 
343
- ##
344
- # @return [Boolean] returns true if the DNS records configured for the
345
- # instance differ from the ones configured on the DNS server
346
- def dns_changed?
347
- if Config.dns_enabled?
348
- dns_record_info.any? do |name, ip|
349
- Models::Dns::Record.find(:name => name, :type => 'A',
350
- :content => ip).nil?
351
- end
352
- else
353
- false
354
- end
256
+ def assign_availability_zone(availability_zone)
257
+ @availability_zone = availability_zone
258
+ @model.update(availability_zone: availability_zone_name)
355
259
  end
356
260
 
357
- ##
358
- # Checks if agent view of the instance state is consistent with target
359
- # instance state.
360
- #
361
- # In case the instance current state is 'detached' we should never get to
362
- # this method call.
363
- # @return [Boolean] returns true if the expected job state differs from
364
- # the one provided by the VM
365
- def state_changed?
366
- @state == 'detached' ||
367
- @state == 'started' && @current_state['job_state'] != 'running' ||
368
- @state == 'stopped' && @current_state['job_state'] == 'running'
261
+ def state
262
+ case @virtual_state
263
+ when 'recreate'
264
+ 'started'
265
+ when 'restart'
266
+ 'started'
267
+ else
268
+ @virtual_state
269
+ end
369
270
  end
370
271
 
371
272
  ##
@@ -375,128 +276,86 @@ module Bosh::Director
375
276
  #
376
277
  # @return [Boolean] true if the VM needs to be sent a new set of trusted certificates
377
278
  def trusted_certs_changed?
378
- Digest::SHA1.hexdigest(Bosh::Director::Config.trusted_certs) != @model.vm.trusted_certs_sha1
279
+ model_trusted_certs = @model.vm ? @model.vm.trusted_certs_sha1 : nil
280
+ config_trusted_certs = Digest::SHA1.hexdigest(Bosh::Director::Config.trusted_certs)
281
+ changed = config_trusted_certs != model_trusted_certs
282
+ log_changes(__method__, model_trusted_certs, config_trusted_certs) if changed
283
+ changed
379
284
  end
380
285
 
381
- ##
382
- # @return [Boolean] returns true if the any of the expected specifications
383
- # differ from the ones provided by the VM
384
- def changed?
385
- !changes.empty?
286
+ def vm_created?
287
+ !@vm.model.nil? && @vm.model.vm_exists?
386
288
  end
387
289
 
388
- ##
389
- # @return [Set<Symbol>] returns a set of all of the specification differences
390
- def changes
391
- changes = Set.new
392
- unless @state == 'detached' && @current_state.nil?
393
- changes << :restart if @restart
394
- changes << :resource_pool if resource_pool_changed?
395
- changes << :network if networks_changed?
396
- changes << :packages if packages_changed?
397
- changes << :persistent_disk if persistent_disk_changed?
398
- changes << :configuration if configuration_changed?
399
- changes << :job if job_changed?
400
- changes << :state if state_changed?
401
- changes << :dns if dns_changed?
402
- changes << :trusted_certs if trusted_certs_changed?
403
- end
404
- changes
290
+ def bind_to_vm_model(vm_model)
291
+ @model.update(vm: vm_model)
292
+ @vm.model = vm_model
293
+ @vm.bound_instance = self
405
294
  end
406
295
 
407
- ##
408
- # Instance spec that's passed to the VM during the BOSH Agent apply call.
409
- # It's what's used for comparing the expected vs the actual state.
410
- # @return [Hash<String, Object>] instance spec
411
- def spec
412
- spec = {
413
- 'deployment' => @job.deployment.name,
414
- 'job' => job.spec,
415
- 'index' => index,
416
- 'networks' => network_settings,
417
- 'resource_pool' => job.resource_pool.spec,
418
- 'packages' => job.package_spec,
419
- 'configuration_hash' => configuration_hash,
420
- 'properties' => job.properties,
421
- 'dns_domain_name' => dns_domain_name
422
- }
296
+ # Allocates an VM in this job resource pool and binds current instance to that VM.
297
+ # @return [void]
298
+ def allocate_vm
299
+ vm = Vm.new
423
300
 
424
- if job.persistent_disk_pool
425
- # supply both for reverse compatibility with old agent
426
- spec['persistent_disk'] = job.persistent_disk_pool.disk_size
427
- # old agents will ignore this pool
428
- spec['persistent_disk_pool'] = job.persistent_disk_pool.spec
429
- else
430
- spec['persistent_disk'] = 0
431
- end
301
+ # VM is not created yet: let's just make it reference this instance
302
+ # so later it knows what it needs to become
303
+ vm.bound_instance = self
304
+ @vm = vm
305
+ end
432
306
 
433
- if template_hashes
434
- spec['template_hashes'] = template_hashes
307
+ def cloud_properties
308
+ if @availability_zone.nil?
309
+ vm_type.cloud_properties
310
+ else
311
+ @availability_zone.cloud_properties.merge(vm_type.cloud_properties)
435
312
  end
313
+ end
436
314
 
437
- # Ruby BOSH Agent does not look at 'rendered_templates_archive'
438
- # since it renders job templates and then compares template hashes.
439
- # Go BOSH Agent has no ability to render ERB so pre-rendered templates are provided.
440
- if rendered_templates_archive
441
- spec['rendered_templates_archive'] = rendered_templates_archive.spec
442
- end
315
+ def availability_zone_name
316
+ return nil if @availability_zone.nil?
443
317
 
444
- spec
318
+ @availability_zone.name
445
319
  end
446
320
 
447
- def bind_to_vm_model(vm_model)
448
- @model.update(vm: vm_model)
449
- @vm.model = vm_model
450
- @vm.bound_instance = self
321
+ def update_templates(templates)
322
+ transactor = Transactor.new
323
+ transactor.retryable_transaction(Bosh::Director::Config.db) do
324
+ @model.remove_all_templates
325
+ templates.map(&:model).each do |template_model|
326
+ @model.add_template(template_model)
327
+ end
328
+ end
451
329
  end
452
330
 
331
+ private
332
+
453
333
  # Looks up instance model in DB
454
334
  # @return [Models::Instance]
455
335
  def find_or_create_model
456
- if @job.deployment.model.nil?
336
+ if @deployment_model.nil?
457
337
  raise DirectorError, 'Deployment model is not bound'
458
338
  end
459
339
 
460
340
  conditions = {
461
- deployment_id: @job.deployment.model.id,
462
- job: @job.name,
341
+ deployment_id: @deployment_model.id,
342
+ job: @job_name,
463
343
  index: @index
464
344
  }
465
345
 
466
346
  Models::Instance.find_or_create(conditions) do |model|
467
347
  model.state = 'started'
348
+ model.compilation = @compilation
349
+ model.uuid = SecureRandom.uuid
468
350
  end
469
351
  end
470
352
 
471
- # Allocates an VM in this job resource pool and binds current instance to that VM.
472
- # @return [void]
473
- def allocate_vm
474
- resource_pool = @job.resource_pool
475
- vm = resource_pool.allocate_vm
476
- network = resource_pool.network
477
-
478
- if vm.model
479
- # There's already a resource pool VM that can become our instance,
480
- # so we can try to reuse its reservation
481
- instance_reservation = @network_reservations[network.name]
482
- if instance_reservation
483
- instance_reservation.take(vm.network_reservation)
484
- end
485
- else
486
- # VM is not created yet: let's just make it reference this instance
487
- # so later it knows what it needs to become
488
- vm.bound_instance = self
489
-
490
- # this also means we no longer need previous VM network reservation
491
- # (instance has its own)
492
- vm.release_reservation
493
- end
494
-
495
- @vm = vm
353
+ # @param [Hash] network_settings map of network name to settings
354
+ # @return [Hash] map of network name to IP address
355
+ def network_to_ip(network_settings)
356
+ Hash[network_settings.map { |network_name, settings| [network_name, settings['ip']] }]
496
357
  end
497
358
 
498
- private
499
-
500
359
  def check_model_bound
501
360
  if @model.nil?
502
361
  raise DirectorError, "Instance `#{self}' model is not bound"
@@ -507,35 +366,8 @@ module Bosh::Director
507
366
  raise DirectorError, "Instance `#{self}' model is already bound" if @model
508
367
  end
509
368
 
510
- ##
511
- # Take any existing valid network reservations
512
- # @param [Hash<String, NetworkReservation>] reservations
513
- # @return [void]
514
- def take_network_reservations(reservations)
515
- reservations.each do |name, provided_reservation|
516
- reservation = @network_reservations[name]
517
- if reservation
518
- @logger.debug("Copying job instance `#{self}' network reservation #{provided_reservation}")
519
- reservation.take(provided_reservation)
520
- end
521
- end
522
- end
523
-
524
- def add_allocated_vm(vm_model, state)
525
- resource_pool = @job.resource_pool
526
- vm = resource_pool.add_allocated_vm
527
-
528
- reservation = @network_reservations[vm.resource_pool.network.name]
529
-
530
- @logger.debug("Found VM '#{vm_model.cid}' running job instance '#{self}'" +
531
- " in resource pool `#{resource_pool.name}'" +
532
- " with reservation '#{reservation}'")
533
- vm.model = vm_model
534
- vm.bound_instance = self
535
- vm.current_state = state
536
- vm.use_reservation(reservation)
537
-
538
- @vm = vm
369
+ def log_changes(method_sym, old_state, new_state)
370
+ @logger.debug("#{method_sym} changed FROM: #{old_state} TO: #{new_state}")
539
371
  end
540
372
  end
541
373
  end