bosh-director 1.2989.0 → 1.2992.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f215637e0cd9049a0e14c0124379078a10a8100
4
- data.tar.gz: dc7e5c19309e2a290503437b01ac8823a1c8127b
3
+ metadata.gz: 77b59d978580198275ba946df8f880fcaa6e28b0
4
+ data.tar.gz: 51860050f654ff925193f6a37034a900cd58eb61
5
5
  SHA512:
6
- metadata.gz: 8cf3189968d508035f74271005f71e46dbf3249e3c712c1e52c84af13d48c48d5e1f376e62d2e18a5ef3d7f3d40faaa3e458bc35924b6fce1179ff297c9ba33f
7
- data.tar.gz: 94df18e413abef5467b2a8c82db328cf5e234bbbc8eb73d682bbc7e47ee3c62a6be78f14f2a4153cce5c3cc8c1934ea5268c07fc11f0cf291046209180d7d51a
6
+ metadata.gz: e02624596050a9fc81ecb3dcbbf35f908b20446556967b564211d5f1cdebd0ca7d98372fdd0a1ea04d38a5b074e0adad8cdaebacffb218dfd0ec622c934b7b35
7
+ data.tar.gz: bc13e1aeb80ea0f6cf1e3d4212891a8db9990c8618a65bcf2267c46eba5fb3a614a367a14bcd2818f5b0aa52bb5a46225466cbec39d617d8aefd796e79e64fb8
@@ -0,0 +1,9 @@
1
+ require 'digest/sha1'
2
+
3
+ Sequel.migration do
4
+ change do
5
+ alter_table(:vms) do
6
+ add_column :trusted_certs_sha1, String, { :default => Digest::SHA1.hexdigest('') }
7
+ end
8
+ end
9
+ end
data/lib/bosh/director.rb CHANGED
@@ -136,6 +136,7 @@ module Bosh::Director
136
136
  end
137
137
 
138
138
  require 'bosh/director/thread_pool'
139
+ require 'bosh/director/api/extensions/scoping'
139
140
  require 'bosh/director/api/controllers/backups_controller'
140
141
  require 'bosh/director/api/controllers/deployments_controller'
141
142
  require 'bosh/director/api/controllers/packages_controller'
@@ -4,7 +4,7 @@ module Bosh::Director
4
4
  module Api::Controllers
5
5
  class BackupsController < BaseController
6
6
  post '/' do
7
- start_task { @backup_manager.create_backup(@user) }
7
+ start_task { @backup_manager.create_backup(current_user) }
8
8
  end
9
9
 
10
10
  get '/' do
@@ -25,6 +25,8 @@ module Bosh::Director
25
25
  @logger = Config.logger
26
26
  end
27
27
 
28
+ register Bosh::Director::Api::Extensions::Scoping
29
+
28
30
  mime_type :tgz, 'application/x-compressed'
29
31
  mime_type :multipart, 'multipart/form-data'
30
32
 
@@ -46,24 +48,6 @@ module Bosh::Director
46
48
  true
47
49
  end
48
50
 
49
- before do
50
- auth_provided = %w(HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION).detect do |key|
51
- request.env.has_key?(key)
52
- end
53
-
54
- if auth_provided
55
- begin
56
- @user = @identity_provider.corroborate_user(request.env)
57
- rescue AuthenticationError
58
- end
59
- end
60
-
61
- if requires_authentication? && @user.nil?
62
- response['WWW-Authenticate'] = 'Basic realm="BOSH Director"'
63
- throw(:halt, [401, "Not authorized\n"])
64
- end
65
- end
66
-
67
51
  after { headers('Date' => Time.now.rfc822) } # As thin doesn't inject date
68
52
 
69
53
  configure do
@@ -10,7 +10,7 @@ module Bosh::Director
10
10
  status(201)
11
11
  end
12
12
 
13
- get '/' do
13
+ get '/', scope: [:read] do
14
14
  if params['limit'].nil? || params['limit'].empty?
15
15
  status(400)
16
16
  body("limit is required")
@@ -37,7 +37,7 @@ module Bosh::Director
37
37
  end
38
38
 
39
39
  post '/import', consumes: :multipart do
40
- task = @compiled_package_group_manager.create_from_file_path(@user, params[:nginx_upload_path])
40
+ task = @compiled_package_group_manager.create_from_file_path(current_user, params[:nginx_upload_path])
41
41
  redirect "/tasks/#{task.id}"
42
42
  end
43
43
 
@@ -44,7 +44,7 @@ module Bosh::Director
44
44
  # the call returns a 404 if the deployment doesn't exist
45
45
  @deployment_manager.find_by_name(params[:deployment])
46
46
  latest_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
47
- task = @deployment_manager.create_deployment(@user, request.body, latest_cloud_config, options)
47
+ task = @deployment_manager.create_deployment(current_user, request.body, latest_cloud_config, options)
48
48
  redirect "/tasks/#{task.id}"
49
49
  end
50
50
 
@@ -69,7 +69,7 @@ module Bosh::Director
69
69
  deployment = @deployment_manager.find_by_name(params[:deployment])
70
70
  manifest = request.content_length.nil? ? StringIO.new(deployment.manifest) : request.body
71
71
  latest_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
72
- task = @deployment_manager.create_deployment(@user, manifest, latest_cloud_config, options)
72
+ task = @deployment_manager.create_deployment(current_user, manifest, latest_cloud_config, options)
73
73
  redirect "/tasks/#{task.id}"
74
74
  end
75
75
 
@@ -84,7 +84,7 @@ module Bosh::Director
84
84
  'filters' => params[:filters].to_s.strip.split(/[\s\,]+/)
85
85
  }
86
86
 
87
- task = @instance_manager.fetch_logs(@user, deployment, job, index, options)
87
+ task = @instance_manager.fetch_logs(current_user, deployment, job, index, options)
88
88
  redirect "/tasks/#{task.id}"
89
89
  end
90
90
 
@@ -103,7 +103,7 @@ module Bosh::Director
103
103
  # until we can tell the agent to flush and wait, all snapshots are considered dirty
104
104
  options = {clean: false}
105
105
 
106
- task = @snapshot_manager.create_deployment_snapshot_task(@user, deployment, options)
106
+ task = @snapshot_manager.create_deployment_snapshot_task(current_user, deployment, options)
107
107
  redirect "/tasks/#{task.id}"
108
108
  end
109
109
 
@@ -118,14 +118,14 @@ module Bosh::Director
118
118
  # until we can tell the agent to flush and wait, all snapshots are considered dirty
119
119
  options = {clean: false}
120
120
 
121
- task = @snapshot_manager.create_snapshot_task(@user, instance, options)
121
+ task = @snapshot_manager.create_snapshot_task(current_user, instance, options)
122
122
  redirect "/tasks/#{task.id}"
123
123
  end
124
124
 
125
125
  delete '/:deployment/snapshots' do
126
126
  deployment = @deployment_manager.find_by_name(params[:deployment])
127
127
 
128
- task = @snapshot_manager.delete_deployment_snapshots_task(@user, deployment)
128
+ task = @snapshot_manager.delete_deployment_snapshots_task(current_user, deployment)
129
129
  redirect "/tasks/#{task.id}"
130
130
  end
131
131
 
@@ -133,11 +133,11 @@ module Bosh::Director
133
133
  deployment = @deployment_manager.find_by_name(params[:deployment])
134
134
  snapshot = @snapshot_manager.find_by_cid(deployment, params[:cid])
135
135
 
136
- task = @snapshot_manager.delete_snapshots_task(@user, [params[:cid]])
136
+ task = @snapshot_manager.delete_snapshots_task(current_user, [params[:cid]])
137
137
  redirect "/tasks/#{task.id}"
138
138
  end
139
139
 
140
- get '/' do
140
+ get '/', scope: [:read] do
141
141
  latest_cloud_config = Api::CloudConfigManager.new.latest
142
142
  deployments = Models::Deployment.order_by(:name.asc).map do |deployment|
143
143
  cloud_config = if deployment.cloud_config.nil?
@@ -169,17 +169,17 @@ module Bosh::Director
169
169
  json_encode(deployments)
170
170
  end
171
171
 
172
- get '/:name' do
172
+ get '/:name', scope: [:read] do
173
173
  deployment = @deployment_manager.find_by_name(params[:name])
174
174
  @deployment_manager.deployment_to_json(deployment)
175
175
  end
176
176
 
177
- get '/:name/vms' do
177
+ get '/:name/vms', scope: [:read] do
178
178
  deployment = @deployment_manager.find_by_name(params[:name])
179
179
 
180
180
  format = params[:format]
181
181
  if format == 'full'
182
- task = @vm_state_manager.fetch_vm_state(@user, deployment, format)
182
+ task = @vm_state_manager.fetch_vm_state(current_user, deployment, format)
183
183
  redirect "/tasks/#{task.id}"
184
184
  else
185
185
  @deployment_manager.deployment_vms_to_json(deployment)
@@ -192,7 +192,7 @@ module Bosh::Director
192
192
  options = {}
193
193
  options['force'] = true if params['force'] == 'true'
194
194
  options['keep_snapshots'] = true if params['keep_snapshots'] == 'true'
195
- task = @deployment_manager.delete_deployment(@user, deployment, options)
195
+ task = @deployment_manager.delete_deployment(current_user, deployment, options)
196
196
  redirect "/tasks/#{task.id}"
197
197
  end
198
198
 
@@ -217,7 +217,7 @@ module Bosh::Director
217
217
 
218
218
  post '/:deployment/ssh', :consumes => [:json] do
219
219
  payload = json_decode(request.body)
220
- task = @instance_manager.ssh(@user, payload)
220
+ task = @instance_manager.ssh(current_user, payload)
221
221
  redirect "/tasks/#{task.id}"
222
222
  end
223
223
 
@@ -236,7 +236,7 @@ module Bosh::Director
236
236
 
237
237
  # Initiate deployment scan
238
238
  post '/:deployment/scans' do
239
- start_task { @problem_manager.perform_scan(@user, params[:deployment]) }
239
+ start_task { @problem_manager.perform_scan(current_user, params[:deployment]) }
240
240
  end
241
241
 
242
242
  # Get the list of problems for a particular deployment
@@ -256,14 +256,14 @@ module Bosh::Director
256
256
 
257
257
  put '/:deployment/problems', :consumes => [:json] do
258
258
  payload = json_decode(request.body)
259
- start_task { @problem_manager.apply_resolutions(@user, params[:deployment], payload['resolutions']) }
259
+ start_task { @problem_manager.apply_resolutions(current_user, params[:deployment], payload['resolutions']) }
260
260
  end
261
261
 
262
262
  put '/:deployment/scan_and_fix', :consumes => :json do
263
263
  jobs_json = json_decode(request.body)['jobs']
264
264
  payload = convert_job_instance_hash(jobs_json)
265
265
 
266
- start_task { @problem_manager.scan_and_fix(@user, params[:deployment], payload) }
266
+ start_task { @problem_manager.scan_and_fix(current_user, params[:deployment], payload) }
267
267
  end
268
268
 
269
269
  post '/', :consumes => :yaml do
@@ -271,7 +271,7 @@ module Bosh::Director
271
271
  options['recreate'] = true if params['recreate'] == 'true'
272
272
  latest_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
273
273
 
274
- task = @deployment_manager.create_deployment(@user, request.body, latest_cloud_config, options)
274
+ task = @deployment_manager.create_deployment(current_user, request.body, latest_cloud_config, options)
275
275
  redirect "/tasks/#{task.id}"
276
276
  end
277
277
 
@@ -281,7 +281,7 @@ module Bosh::Director
281
281
  keep_alive = json_decode(request.body)['keep-alive'] || FALSE
282
282
 
283
283
  task = JobQueue.new.enqueue(
284
- @user,
284
+ current_user,
285
285
  Jobs::RunErrand,
286
286
  "run errand #{errand_name} from deployment #{deployment_name}",
287
287
  [deployment_name, errand_name, keep_alive],
@@ -290,7 +290,7 @@ module Bosh::Director
290
290
  redirect "/tasks/#{task.id}"
291
291
  end
292
292
 
293
- get '/:deployment_name/errands' do
293
+ get '/:deployment_name/errands', scope: [:read] do
294
294
  deployment_plan = load_deployment_plan_without_binding
295
295
 
296
296
  errands = deployment_plan.jobs.select(&:can_run_as_errand?)
@@ -7,12 +7,12 @@ module Bosh::Director
7
7
  false
8
8
  end
9
9
 
10
- get '/' do
10
+ get '/', scope: [:read] do
11
11
  status = {
12
12
  'name' => Config.name,
13
13
  'uuid' => Config.uuid,
14
14
  'version' => "#{VERSION} (#{Config.revision})",
15
- 'user' => @user,
15
+ 'user' => current_user,
16
16
  'cpi' => Config.cloud_type,
17
17
  'user_authentication' => @config.identity_provider.client_info,
18
18
  'features' => {
@@ -1,7 +1,7 @@
1
1
  module Bosh::Director
2
2
  module Api::Controllers
3
3
  class LocksController < BaseController
4
- get '/' do
4
+ get '/', scope: [:read] do
5
5
  redis = Config.redis
6
6
 
7
7
  locks = []
@@ -9,7 +9,7 @@ module Bosh::Director
9
9
  rebase: params['rebase'] == 'true',
10
10
  skip_if_exists: params['skip_if_exists'] == 'true',
11
11
  }
12
- task = @release_manager.create_release_from_url(@user, payload['location'], options)
12
+ task = @release_manager.create_release_from_url(current_user, payload['location'], options)
13
13
  redirect "/tasks/#{task.id}"
14
14
  end
15
15
 
@@ -17,11 +17,11 @@ module Bosh::Director
17
17
  options = {
18
18
  rebase: params['rebase'] == 'true',
19
19
  }
20
- task = @release_manager.create_release_from_file_path(@user, params[:nginx_upload_path], options)
20
+ task = @release_manager.create_release_from_file_path(current_user, params[:nginx_upload_path], options)
21
21
  redirect "/tasks/#{task.id}"
22
22
  end
23
23
 
24
- get '/' do
24
+ get '/', scope: [:read] do
25
25
  releases = Models::Release.order_by(:name.asc).map do |release|
26
26
  release_versions = release.versions_dataset.order_by(:version.asc).map do |rv|
27
27
  {
@@ -42,7 +42,7 @@ module Bosh::Director
42
42
  json_encode(releases)
43
43
  end
44
44
 
45
- get '/:name' do
45
+ get '/:name', scope: [:read] do
46
46
  name = params[:name].to_s.strip
47
47
  release = @release_manager.find_by_name(name)
48
48
 
@@ -81,7 +81,7 @@ module Bosh::Director
81
81
  options['force'] = true if params['force'] == 'true'
82
82
  options['version'] = params['version']
83
83
 
84
- task = @release_manager.delete_release(@user, release, options)
84
+ task = @release_manager.delete_release(current_user, release, options)
85
85
  redirect "/tasks/#{task.id}"
86
86
  end
87
87
  end
@@ -5,16 +5,16 @@ module Bosh::Director
5
5
  class StemcellsController < BaseController
6
6
  post '/', :consumes => :json do
7
7
  payload = json_decode(request.body)
8
- task = @stemcell_manager.create_stemcell_from_url(@user, payload['location'])
8
+ task = @stemcell_manager.create_stemcell_from_url(current_user, payload['location'])
9
9
  redirect "/tasks/#{task.id}"
10
10
  end
11
11
 
12
12
  post '/', :consumes => :multipart do
13
- task = @stemcell_manager.create_stemcell_from_file_path(@user, params[:nginx_upload_path])
13
+ task = @stemcell_manager.create_stemcell_from_file_path(current_user, params[:nginx_upload_path])
14
14
  redirect "/tasks/#{task.id}"
15
15
  end
16
16
 
17
- get '/' do
17
+ get '/', scope: [:read] do
18
18
  stemcells = Models::Stemcell.order_by(:name.asc).map do |stemcell|
19
19
  {
20
20
  'name' => stemcell.name,
@@ -31,7 +31,7 @@ module Bosh::Director
31
31
  options = {}
32
32
  options['force'] = true if params['force'] == 'true'
33
33
  stemcell = @stemcell_manager.find_by_name_and_version(name, version)
34
- task = @stemcell_manager.delete_stemcell(@user, stemcell, options)
34
+ task = @stemcell_manager.delete_stemcell(current_user, stemcell, options)
35
35
  redirect "/tasks/#{task.id}"
36
36
  end
37
37
  end
@@ -0,0 +1,45 @@
1
+ module Bosh::Director
2
+ module Api
3
+ module Extensions
4
+ module Scoping
5
+ module Helpers
6
+ def current_user
7
+ @user
8
+ end
9
+ end
10
+
11
+ def self.registered(app)
12
+ app.set default_scope: :write
13
+ app.helpers(Helpers)
14
+ end
15
+
16
+ def scope(*roles)
17
+ condition do
18
+ roles = [settings.default_scope] if roles == [:default]
19
+
20
+ auth_provided = %w(HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION).detect do |key|
21
+ request.env.has_key?(key)
22
+ end
23
+
24
+ if auth_provided
25
+ begin
26
+ @user = identity_provider.corroborate_user(request.env, roles)
27
+ rescue AuthenticationError
28
+ end
29
+ end
30
+
31
+ if requires_authentication? && @user.nil?
32
+ response['WWW-Authenticate'] = 'Basic realm="BOSH Director"'
33
+ throw(:halt, [401, "Not authorized\n"])
34
+ end
35
+ end
36
+ end
37
+
38
+ def route(verb, path, options = {}, &block)
39
+ options[:scope] ||= :default
40
+ super(verb, path, options, &block)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -10,7 +10,7 @@ module Bosh
10
10
  {'type' => 'basic', 'options' => {}}
11
11
  end
12
12
 
13
- def corroborate_user(request_env)
13
+ def corroborate_user(request_env, _)
14
14
  auth ||= Rack::Auth::Basic::Request.new(request_env)
15
15
  raise AuthenticationError unless auth.provided? && auth.basic? && auth.credentials
16
16
 
@@ -4,9 +4,10 @@ module Bosh
4
4
  module Director
5
5
  module Api
6
6
  class UAAIdentityProvider
7
- def initialize(options)
7
+ def initialize(options, director_uuid)
8
8
  @url = options.fetch('url')
9
9
  Config.logger.debug "Initializing UAA Identity provider with url #{@url}"
10
+ @director_uuid = director_uuid
10
11
  @token_coder = CF::UAA::TokenCoder.new(skey: options.fetch('symmetric_key', nil), pkey: options.fetch('public_key', nil), scope: [])
11
12
  end
12
13
 
@@ -19,13 +20,39 @@ module Bosh
19
20
  }
20
21
  end
21
22
 
22
- def corroborate_user(request_env)
23
+ def corroborate_user(request_env, requested_access)
23
24
  auth_header = request_env['HTTP_AUTHORIZATION']
24
25
  token = @token_coder.decode(auth_header)
26
+ validate_access(token, requested_access)
27
+
25
28
  token['user_name'] || token['client_id']
26
29
  rescue CF::UAA::DecodeError, CF::UAA::AuthError => e
27
30
  raise AuthenticationError, e.message
28
31
  end
32
+
33
+ private
34
+
35
+ def validate_access(token, requested_access)
36
+ if token['scope']
37
+ if token_has_admin_scope?(token['scope'])
38
+ return
39
+ end
40
+
41
+ if requested_access.include?(:read) && token_has_read_scope?(token['scope'])
42
+ return
43
+ end
44
+ end
45
+
46
+ raise AuthenticationError, 'Requested access is not allowed by the scope'
47
+ end
48
+
49
+ def token_has_read_scope?(token_scope)
50
+ token_scope.include?('bosh.read') || token_scope.include?("bosh.#{@director_uuid}.read")
51
+ end
52
+
53
+ def token_has_admin_scope?(token_scope)
54
+ token_scope.include?('bosh.admin') || token_scope.include?("bosh.#{@director_uuid}.admin")
55
+ end
29
56
  end
30
57
  end
31
58
  end
@@ -130,7 +130,9 @@ module Bosh::Director
130
130
  end
131
131
 
132
132
  agent_client(new_vm).wait_until_ready
133
+
133
134
  agent_client(new_vm).update_settings(Bosh::Director::Config.trusted_certs)
135
+ new_vm.update(:trusted_certs_sha1 => Digest::SHA1.hexdigest(Bosh::Director::Config.trusted_certs))
134
136
 
135
137
  # After this point agent is actually responding to
136
138
  # pings, so if the rest of this handler fails
@@ -388,7 +388,7 @@ module Bosh::Director
388
388
  end
389
389
 
390
390
  Config.logger.debug("Director configured with '#{provider_name}' user management provider")
391
- provider_class.new(user_management['options'] || {})
391
+ provider_class.new(user_management['options'] || {}, @uuid)
392
392
  end
393
393
  end
394
394
 
@@ -368,6 +368,16 @@ module Bosh::Director
368
368
  @state == 'stopped' && @current_state['job_state'] == 'running'
369
369
  end
370
370
 
371
+ ##
372
+ # Checks if the target VM already has the same set of trusted SSL certificates
373
+ # as the director currently wants to install on all managed VMs. This will
374
+ # differ for VMs that existed before the director's configuration changed.
375
+ #
376
+ # @return [Boolean] true if the VM needs to be sent a new set of trusted certificates
377
+ def trusted_certs_changed?
378
+ Digest::SHA1.hexdigest(Bosh::Director::Config.trusted_certs) != @model.vm.trusted_certs_sha1
379
+ end
380
+
371
381
  ##
372
382
  # @return [Boolean] returns true if the any of the expected specifications
373
383
  # differ from the ones provided by the VM
@@ -389,6 +399,7 @@ module Bosh::Director
389
399
  changes << :job if job_changed?
390
400
  changes << :state if state_changed?
391
401
  changes << :dns if dns_changed?
402
+ changes << :trusted_certs if trusted_certs_changed?
392
403
  end
393
404
  changes
394
405
  end
@@ -1,4 +1,5 @@
1
1
  require 'bosh/director/compile_task_generator'
2
+ require 'digest/sha1'
2
3
 
3
4
  module Bosh::Director
4
5
  module DeploymentPlan
@@ -160,6 +161,7 @@ module Bosh::Director
160
161
  agent = AgentClient.with_defaults(vm.agent_id)
161
162
  agent.wait_until_ready
162
163
  agent.update_settings(Bosh::Director::Config.trusted_certs)
164
+ vm.update(:trusted_certs_sha1 => Digest::SHA1.hexdigest(Bosh::Director::Config.trusted_certs))
163
165
 
164
166
  configure_vm(vm, agent, network_settings)
165
167
  vm_data.agent = agent
@@ -4,7 +4,6 @@ module Bosh::Director
4
4
  class InstanceUpdater
5
5
  include DnsHelper
6
6
 
7
- UPDATE_STEPS = 7
8
7
  WATCH_INTERVALS = 10
9
8
 
10
9
  attr_reader :current_state
@@ -33,53 +32,59 @@ module Bosh::Director
33
32
  @agent = AgentClient.with_defaults(@vm.agent_id)
34
33
  end
35
34
 
36
- def step
37
- yield
38
- report_progress
35
+ def report_progress(num_steps)
36
+ @event_log_task.advance(100.0 / num_steps)
39
37
  end
40
38
 
41
- def report_progress
42
- @event_log_task.advance(100.0 / update_steps())
43
- end
44
-
45
- def update_steps
46
- @instance.job_changed? || @instance.packages_changed? ? UPDATE_STEPS + 1 : UPDATE_STEPS
47
- end
48
-
49
- def update(options = {})
39
+ def update_steps(options = {})
40
+ steps = []
50
41
  @canary = options.fetch(:canary, false)
51
42
 
52
- @logger.info("Updating instance #{@instance}, changes: #{@instance.changes.to_a.join(', ')}")
53
-
54
43
  # Optimization to only update DNS if nothing else changed.
55
44
  if dns_change_only?
56
- update_dns
57
- return
45
+ steps << proc { update_dns }
46
+ return steps
58
47
  end
59
48
 
60
- step { Preparer.new(@instance, agent, @logger).prepare }
61
- step { stop }
62
- step { take_snapshot }
49
+ steps << proc { Preparer.new(@instance, agent, @logger).prepare }
50
+ steps << proc { stop }
51
+ steps << proc { take_snapshot }
63
52
 
64
53
  if @target_state == "detached"
65
- vm_updater.detach
66
- return
54
+ steps << proc { vm_updater.detach }
55
+ return steps
56
+ end
57
+
58
+ steps << proc { recreate_vm(nil) }
59
+ steps << proc { update_networks }
60
+ steps << proc { update_dns }
61
+ steps << proc { update_persistent_disk }
62
+ steps << proc { update_settings }
63
+
64
+ if !trusted_certs_change_only?
65
+ steps << proc {
66
+ VmMetadataUpdater.build.update(@vm, {})
67
+ apply_state(@instance.spec)
68
+ RenderedJobTemplatesCleaner.new(@instance.model, @blobstore).clean
69
+ }
67
70
  end
68
71
 
69
- step { recreate_vm(nil) }
70
- step { update_networks }
71
- step { update_dns }
72
- step { update_persistent_disk }
72
+ steps << proc { start! if need_start? }
73
73
 
74
- VmMetadataUpdater.build.update(@vm, {})
74
+ steps << proc { wait_until_running }
75
75
 
76
- step { apply_state(@instance.spec) }
76
+ steps
77
+ end
77
78
 
78
- RenderedJobTemplatesCleaner.new(@instance.model, @blobstore).clean
79
+ def update(options = {})
80
+ steps = update_steps(options)
79
81
 
80
- start! if need_start?
82
+ @logger.info("Updating instance #{@instance}, changes: #{@instance.changes.to_a.join(', ')}")
81
83
 
82
- step { wait_until_running }
84
+ steps.each do |step|
85
+ step.call
86
+ report_progress(steps.length)
87
+ end
83
88
 
84
89
  if @target_state == "started" && current_state["job_state"] != "running"
85
90
  raise AgentJobNotRunning, "`#{@instance}' is not running after update"
@@ -133,6 +138,10 @@ module Bosh::Director
133
138
  @instance.changes.include?(:dns) && @instance.changes.size == 1
134
139
  end
135
140
 
141
+ def trusted_certs_change_only?
142
+ @instance.changes.include?(:trusted_certs) && @instance.changes.size == 1
143
+ end
144
+
136
145
  def stop
137
146
  stopper = Stopper.new(@instance, agent, @target_state, Config, @logger)
138
147
  stopper.stop
@@ -268,6 +277,13 @@ module Bosh::Director
268
277
  @vm, @agent = network_updater.update
269
278
  end
270
279
 
280
+ def update_settings
281
+ if @instance.trusted_certs_changed?
282
+ @agent.update_settings(Config.trusted_certs)
283
+ @vm.update(:trusted_certs_sha1 => Digest::SHA1.hexdigest(Config.trusted_certs))
284
+ end
285
+ end
286
+
271
287
  # Returns an array of wait times distributed
272
288
  # on the [min_watch_time..max_watch_time] interval.
273
289
  #
@@ -85,7 +85,6 @@ module Bosh::Director
85
85
 
86
86
  def create(new_disk_id)
87
87
  @logger.info('Creating VM')
88
-
89
88
  vm_model = new_vm_model(new_disk_id)
90
89
 
91
90
  begin
@@ -94,6 +93,7 @@ module Bosh::Director
94
93
  agent_client = AgentClient.with_defaults(vm_model.agent_id)
95
94
  agent_client.wait_until_ready
96
95
  agent_client.update_settings(Bosh::Director::Config.trusted_certs)
96
+ vm_model.update(:trusted_certs_sha1 => Digest::SHA1.hexdigest(Bosh::Director::Config.trusted_certs))
97
97
  rescue Exception => e
98
98
  @logger.error("Failed to create/contact VM #{vm_model.cid}: #{e.inspect}")
99
99
  VmDeleter.new(@instance, vm_model, @cloud, @logger).delete
@@ -6,6 +6,7 @@ module Bosh::Director::Models
6
6
  def validate
7
7
  validates_presence [:deployment_id, :agent_id]
8
8
  validates_unique :agent_id
9
+
9
10
  end
10
11
 
11
12
  def apply_spec
@@ -54,6 +54,7 @@ module Bosh::Director
54
54
  agent = AgentClient.with_defaults(vm_model.agent_id)
55
55
  agent.wait_until_ready
56
56
  agent.update_settings(Config.trusted_certs)
57
+ vm_model.update(:trusted_certs_sha1 => Digest::SHA1.hexdigest(Config.trusted_certs))
57
58
 
58
59
  update_state(agent, vm_model, vm)
59
60
 
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Director
3
- VERSION = '1.2989.0'
3
+ VERSION = '1.2992.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh-director
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2989.0
4
+ version: 1.2992.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - VMware
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-16 00:00:00.000000000 Z
11
+ date: 2015-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcrypt-ruby
@@ -30,126 +30,126 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2989.0
33
+ version: 1.2992.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.2989.0
40
+ version: 1.2992.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bosh-core
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.2989.0
47
+ version: 1.2992.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.2989.0
54
+ version: 1.2992.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bosh-director-core
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.2989.0
61
+ version: 1.2992.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.2989.0
68
+ version: 1.2992.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bosh_common
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 1.2989.0
75
+ version: 1.2992.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 1.2989.0
82
+ version: 1.2992.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: bosh-template
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.2989.0
89
+ version: 1.2992.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.2989.0
96
+ version: 1.2992.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: bosh_cpi
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.2989.0
103
+ version: 1.2992.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.2989.0
110
+ version: 1.2992.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: bosh_openstack_cpi
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.2989.0
117
+ version: 1.2992.0
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.2989.0
124
+ version: 1.2992.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: bosh_aws_cpi
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.2989.0
131
+ version: 1.2992.0
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.2989.0
138
+ version: 1.2992.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: bosh_vsphere_cpi
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 1.2989.0
145
+ version: 1.2992.0
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 1.2989.0
152
+ version: 1.2992.0
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: bosh_vcloud_cpi
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -572,7 +572,7 @@ dependencies:
572
572
  version: '0'
573
573
  description: |-
574
574
  BOSH Director
575
- 0c4ecd
575
+ 2996bb
576
576
  email: support@cloudfoundry.com
577
577
  executables:
578
578
  - bosh-director
@@ -627,6 +627,7 @@ files:
627
627
  - db/migrations/director/20150224193313_use_larger_text_types.rb
628
628
  - db/migrations/director/20150331002413_add_cloud_configs.rb
629
629
  - db/migrations/director/20150401184803_add_cloud_config_to_deployments.rb
630
+ - db/migrations/director/20150611193110_add_trusted_certs_sha1_to_vms.rb
630
631
  - db/migrations/dns/20120123234908_initial.rb
631
632
  - lib/bosh/director.rb
632
633
  - lib/bosh/director/agent_client.rb
@@ -653,6 +654,7 @@ files:
653
654
  - lib/bosh/director/api/controllers/users_controller.rb
654
655
  - lib/bosh/director/api/deployment_lookup.rb
655
656
  - lib/bosh/director/api/deployment_manager.rb
657
+ - lib/bosh/director/api/extensions/scoping.rb
656
658
  - lib/bosh/director/api/http_constants.rb
657
659
  - lib/bosh/director/api/instance_lookup.rb
658
660
  - lib/bosh/director/api/instance_manager.rb