bosh-director 1.3202.0 → 1.3213.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/db/migrations/director/20151223172000_rename_requires_json.rb +7 -0
  3. data/db/migrations/director/20160106162749_runtime_configs.rb +19 -0
  4. data/db/migrations/director/20160106163433_add_runtime_configs_to_deployments.rb +7 -0
  5. data/db/migrations/director/20160202162216_add_post_start_completed_to_instance.rb +7 -0
  6. data/db/migrations/director/20160210201838_denormalize_compiled_package_stemcell_id_to_stemcell_name_and_version.rb +57 -0
  7. data/db/migrations/director/20160219175840_add_column_teams_to_deployments.rb +8 -0
  8. data/db/migrations/director/20160224222508_add_deployment_name_to_task.rb +7 -0
  9. data/db/migrations/director/20160225182206_rename_post_start_completed.rb +8 -0
  10. data/lib/bosh/director.rb +9 -0
  11. data/lib/bosh/director/api.rb +1 -1
  12. data/lib/bosh/director/api/api_helper.rb +27 -0
  13. data/lib/bosh/director/api/controllers/base_controller.rb +28 -5
  14. data/lib/bosh/director/api/controllers/cloud_configs_controller.rb +4 -3
  15. data/lib/bosh/director/api/controllers/deployments_controller.rb +165 -81
  16. data/lib/bosh/director/api/controllers/locks_controller.rb +1 -1
  17. data/lib/bosh/director/api/controllers/packages_controller.rb +4 -35
  18. data/lib/bosh/director/api/controllers/releases_controller.rb +6 -4
  19. data/lib/bosh/director/api/controllers/runtime_configs_controller.rb +41 -0
  20. data/lib/bosh/director/api/controllers/stemcells_controller.rb +1 -1
  21. data/lib/bosh/director/api/controllers/tasks_controller.rb +72 -5
  22. data/lib/bosh/director/api/deployment_manager.rb +10 -42
  23. data/lib/bosh/director/api/extensions/scoping.rb +11 -24
  24. data/lib/bosh/director/api/instance_lookup.rb +10 -22
  25. data/lib/bosh/director/api/instance_manager.rb +27 -15
  26. data/lib/bosh/director/api/local_identity_provider.rb +0 -8
  27. data/lib/bosh/director/api/problem_manager.rb +7 -19
  28. data/lib/bosh/director/api/property_manager.rb +12 -21
  29. data/lib/bosh/director/api/resurrector_manager.rb +4 -4
  30. data/lib/bosh/director/api/route_configuration.rb +1 -0
  31. data/lib/bosh/director/api/runtime_config_manager.rb +35 -0
  32. data/lib/bosh/director/api/snapshot_manager.rb +2 -2
  33. data/lib/bosh/director/api/task_helper.rb +2 -1
  34. data/lib/bosh/director/api/task_manager.rb +2 -8
  35. data/lib/bosh/director/api/uaa_identity_provider.rb +0 -16
  36. data/lib/bosh/director/blob_util.rb +3 -2
  37. data/lib/bosh/director/cloudcheck_helper.rb +17 -3
  38. data/lib/bosh/director/compile_task.rb +53 -24
  39. data/lib/bosh/director/compile_task_generator.rb +6 -6
  40. data/lib/bosh/director/compiled_package_group.rb +4 -3
  41. data/lib/bosh/director/compiled_release.rb +6 -0
  42. data/lib/bosh/director/compiled_release/manifest.rb +30 -0
  43. data/lib/bosh/director/compiled_release_manifest.rb +3 -3
  44. data/lib/bosh/director/config.rb +11 -1
  45. data/lib/bosh/director/deployment_plan.rb +1 -0
  46. data/lib/bosh/director/deployment_plan/assembler.rb +6 -2
  47. data/lib/bosh/director/deployment_plan/cloud_manifest_parser.rb +26 -10
  48. data/lib/bosh/director/deployment_plan/compilation_config.rb +43 -7
  49. data/lib/bosh/director/deployment_plan/compilation_instance_pool.rb +10 -3
  50. data/lib/bosh/director/deployment_plan/deployment_repo.rb +4 -10
  51. data/lib/bosh/director/deployment_plan/dynamic_network.rb +1 -1
  52. data/lib/bosh/director/deployment_plan/instance.rb +36 -17
  53. data/lib/bosh/director/deployment_plan/instance_plan.rb +13 -2
  54. data/lib/bosh/director/deployment_plan/instance_spec.rb +12 -4
  55. data/lib/bosh/director/deployment_plan/job.rb +73 -39
  56. data/lib/bosh/director/deployment_plan/job_availability_zone_parser.rb +4 -4
  57. data/lib/bosh/director/deployment_plan/job_migrator.rb +7 -7
  58. data/lib/bosh/director/deployment_plan/job_network_parser.rb +6 -6
  59. data/lib/bosh/director/deployment_plan/job_spec_parser.rb +91 -33
  60. data/lib/bosh/director/deployment_plan/links/link.rb +9 -4
  61. data/lib/bosh/director/deployment_plan/links/link_lookup.rb +23 -15
  62. data/lib/bosh/director/deployment_plan/links/link_path.rb +168 -15
  63. data/lib/bosh/director/deployment_plan/links/links_resolver.rb +34 -32
  64. data/lib/bosh/director/deployment_plan/links/template_link.rb +28 -8
  65. data/lib/bosh/director/deployment_plan/manifest_validator.rb +1 -1
  66. data/lib/bosh/director/deployment_plan/network_settings.rb +27 -13
  67. data/lib/bosh/director/deployment_plan/package_validator.rb +9 -5
  68. data/lib/bosh/director/deployment_plan/placement_planner/networks_to_static_ips.rb +4 -4
  69. data/lib/bosh/director/deployment_plan/planner.rb +31 -7
  70. data/lib/bosh/director/deployment_plan/planner_factory.rb +147 -6
  71. data/lib/bosh/director/deployment_plan/runtime_manifest_parser.rb +142 -0
  72. data/lib/bosh/director/deployment_plan/stemcell.rb +2 -2
  73. data/lib/bosh/director/deployment_plan/steps/package_compile_step.rb +3 -2
  74. data/lib/bosh/director/deployment_plan/template.rb +93 -8
  75. data/lib/bosh/director/deployment_plan/update_config.rb +10 -0
  76. data/lib/bosh/director/deployment_plan/vm_extension.rb +27 -0
  77. data/lib/bosh/director/errand/runner.rb +1 -1
  78. data/lib/bosh/director/errors.rb +11 -1
  79. data/lib/bosh/director/instance_updater.rb +46 -57
  80. data/lib/bosh/director/instance_updater/instance_state.rb +9 -0
  81. data/lib/bosh/director/instance_updater/state_applier.rb +18 -5
  82. data/lib/bosh/director/job_queue.rb +2 -2
  83. data/lib/bosh/director/job_renderer.rb +2 -2
  84. data/lib/bosh/director/job_updater.rb +7 -1
  85. data/lib/bosh/director/jobs/attach_disk.rb +2 -2
  86. data/lib/bosh/director/jobs/cloud_check/apply_resolutions.rb +6 -1
  87. data/lib/bosh/director/jobs/cloud_check/scan_and_fix.rb +14 -3
  88. data/lib/bosh/director/jobs/export_release.rb +1 -1
  89. data/lib/bosh/director/jobs/fetch_logs.rb +1 -4
  90. data/lib/bosh/director/jobs/helpers/compiled_package_deleter.rb +1 -2
  91. data/lib/bosh/director/jobs/helpers/stemcell_deleter.rb +0 -16
  92. data/lib/bosh/director/jobs/release/release_job.rb +7 -7
  93. data/lib/bosh/director/jobs/run_errand.rb +5 -5
  94. data/lib/bosh/director/jobs/ssh.rb +3 -3
  95. data/lib/bosh/director/jobs/update_deployment.rb +41 -5
  96. data/lib/bosh/director/jobs/update_release.rb +78 -82
  97. data/lib/bosh/director/jobs/update_stemcell.rb +1 -1
  98. data/lib/bosh/director/jobs/vm_state.rb +34 -21
  99. data/lib/bosh/director/key_generator.rb +54 -0
  100. data/lib/bosh/director/lock.rb +2 -2
  101. data/lib/bosh/director/log_bundles_cleaner.rb +1 -0
  102. data/lib/bosh/director/manifest/changeset.rb +39 -22
  103. data/lib/bosh/director/manifest/diff_lines.rb +1 -27
  104. data/lib/bosh/director/manifest/manifest.rb +22 -7
  105. data/lib/bosh/director/manifest/redactor.rb +44 -0
  106. data/lib/bosh/director/models.rb +1 -0
  107. data/lib/bosh/director/models/compiled_package.rb +21 -15
  108. data/lib/bosh/director/models/deployment.rb +10 -0
  109. data/lib/bosh/director/models/instance.rb +2 -1
  110. data/lib/bosh/director/models/release_version.rb +0 -16
  111. data/lib/bosh/director/models/runtime_config.rb +19 -0
  112. data/lib/bosh/director/models/template.rb +4 -4
  113. data/lib/bosh/director/package_dependencies_manager.rb +22 -0
  114. data/lib/bosh/director/password_helper.rb +18 -0
  115. data/lib/bosh/director/permission_authorizer.rb +50 -30
  116. data/lib/bosh/director/post_deployment_script_runner.rb +40 -0
  117. data/lib/bosh/director/problem_handlers/missing_disk.rb +2 -2
  118. data/lib/bosh/director/problem_resolver.rb +8 -2
  119. data/lib/bosh/director/problem_scanner/scanner.rb +1 -1
  120. data/lib/bosh/director/problem_scanner/vm_scan_stage.rb +1 -1
  121. data/lib/bosh/director/validation_helper.rb +5 -5
  122. data/lib/bosh/director/version.rb +1 -1
  123. data/lib/bosh/director/vm_creator.rb +8 -0
  124. data/lib/cloud/dummy.rb +1 -0
  125. metadata +51 -19
  126. data/lib/bosh/director/api/vm_state_manager.rb +0 -9
  127. data/lib/bosh/director/compiled_package/blob_sha_mismatch_error.rb +0 -5
  128. data/lib/bosh/director/compiled_package/compiled_package.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c0a7cb66eb81b7bc267bfbe73d9c21b7493842a
4
- data.tar.gz: cb26be183757635f946fc7db7b440e5d5cd745fa
3
+ metadata.gz: 80b916377f341047163e53997092a6df6ae2129e
4
+ data.tar.gz: ac33c1cd3698034c745895a8f60fd09dfd759e1a
5
5
  SHA512:
6
- metadata.gz: c007a923353b2face4ab79b4e11a5aee2a5ef8838433cd4bb4bdb3339336f4b8d54727fb2cf9f8761d9f0cae51b644ca42a8ba6e15b19c23a3a6fe2405f0f00c
7
- data.tar.gz: f4e508a6c6920cd4da88f4c614d07b09f690962ef900485bfda426f6e09159765595e0549530e96192b3dd9f7dc9722f84f156eb173ae7ecc3dafcb6184c877a
6
+ metadata.gz: 36df0a755fa74b497cde0c4e87c5c88f64b43cc63d384edd29e63675a5029bb95824f881c5910c6eb823fe723e1c28a1245faccaa4ce26be30fd306bc56c94e4
7
+ data.tar.gz: 1b1f672cb69232dad861cb533f8da0d1ff03664dd771a24dc245b65246ee3b8275938ece8172006c21f35f06f1d8237579ba3bfab87aeb8a11df35b8f61b1262
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table :templates do
4
+ rename_column :requires_json, :consumes_json
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ Sequel.migration do
2
+ change do
3
+ adapter_scheme = self.adapter_scheme
4
+
5
+ create_table :runtime_configs do
6
+ primary_key :id
7
+
8
+ if [:mysql2, :mysql].include?(adapter_scheme)
9
+ longtext :properties
10
+ else
11
+ text :properties
12
+ end
13
+
14
+ Time :created_at, null: false
15
+
16
+ index :created_at
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:deployments) do
4
+ add_foreign_key :runtime_config_id, :runtime_configs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:instances) do
4
+ add_column :post_start_completed, TrueClass, default: true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:compiled_packages) do
4
+ add_column :stemcell_os, String
5
+ add_column :stemcell_version, String
6
+ end
7
+
8
+ self[:compiled_packages].each do |compiled_package|
9
+ next unless compiled_package[:stemcell_id]
10
+
11
+ stemcell = self[:stemcells].filter(id: compiled_package[:stemcell_id]).first
12
+ stemcell_os = stemcell[:operating_system].to_s.empty? ? stemcell[:name] : stemcell[:operating_system]
13
+
14
+ self[:compiled_packages].filter(id: compiled_package[:id]).update(
15
+ stemcell_os: stemcell_os,
16
+ stemcell_version: stemcell[:version]
17
+ )
18
+ end
19
+
20
+ if [:mysql2, :mysql, :postgres].include?(adapter_scheme)
21
+ stemcell_foreign_keys = foreign_key_list(:compiled_packages).select { |constraint| constraint.fetch(:columns).include?(:stemcell_id) }
22
+ raise 'Failed to run migration, found more than 1 stemcell foreign key' if stemcell_foreign_keys.size != 1
23
+ stemcell_foreign_key_name = stemcell_foreign_keys.first.fetch(:name)
24
+
25
+ build_indexes = indexes(:compiled_packages).select { |_, value| value.fetch(:columns) == [:package_id, :stemcell_id, :build] }
26
+ raise 'Failed to run migration, found more than 1 build index' if build_indexes.size != 1
27
+ # build_indexes is an array, where each element is an array with first element being the name of index
28
+ build_index = build_indexes.first.first
29
+
30
+ stemcell_indexes = indexes(:compiled_packages).select { |_, value| value.fetch(:columns) == [:package_id, :stemcell_id, :dependency_key_sha1]}
31
+ raise 'Failed to run migration, found more than 1 stemcell_id index' if stemcell_indexes.size != 1
32
+ # stemcell_indexes is an array, where each element is an array with first element being the name of index
33
+ stemcell_index = stemcell_indexes.first.first
34
+
35
+ if [:mysql2, :mysql].include?(adapter_scheme)
36
+ alter_table(:compiled_packages) do
37
+ drop_index(nil, name: build_index)
38
+ end
39
+ elsif [:postgres].include?(adapter_scheme)
40
+ alter_table(:compiled_packages) do
41
+ drop_constraint(build_index)
42
+ end
43
+ end
44
+
45
+ alter_table(:compiled_packages) do
46
+ drop_constraint(stemcell_foreign_key_name, :type => :foreign_key)
47
+ add_index [:package_id, :stemcell_os, :stemcell_version, :build], unique: true, name: 'package_stemcell_build_idx'
48
+ add_index [:package_id, :stemcell_os, :stemcell_version, :dependency_key_sha1], unique: true, name: 'package_stemcell_dependency_idx'
49
+ drop_index(nil, name: stemcell_index)
50
+ end
51
+ end
52
+
53
+ alter_table(:compiled_packages) do
54
+ drop_column :stemcell_id
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,8 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:deployments) do
4
+ drop_column(:scopes)
5
+ add_column :teams, String
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:tasks) do
4
+ add_column :deployment_name, String, default: nil
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table :instances do
4
+ rename_column :post_start_completed, :update_completed
5
+ set_column_default :update_completed, false
6
+ end
7
+ end
8
+ end
data/lib/bosh/director.rb CHANGED
@@ -59,15 +59,20 @@ require 'bosh/director/blob_util'
59
59
  require 'bosh/director/agent_client'
60
60
  require 'cloud'
61
61
  require 'bosh/director/compile_task'
62
+ require 'bosh/director/key_generator'
63
+ require 'bosh/director/package_dependencies_manager'
64
+
62
65
  require 'bosh/director/job_renderer'
63
66
  require 'bosh/director/cycle_helper'
64
67
  require 'bosh/director/encryption_helper'
68
+ require 'bosh/director/password_helper'
65
69
  require 'bosh/director/vm_creator'
66
70
  require 'bosh/director/vm_recreator'
67
71
  require 'bosh/director/vm_deleter'
68
72
  require 'bosh/director/vm_metadata_updater'
69
73
  require 'bosh/director/instance_reuser'
70
74
  require 'bosh/director/deployment_plan'
75
+ require 'bosh/director/compiled_release'
71
76
  require 'bosh/director/errand'
72
77
  require 'bosh/director/duration'
73
78
  require 'bosh/director/hash_string_vals'
@@ -75,6 +80,7 @@ require 'bosh/director/instance_deleter'
75
80
  require 'bosh/director/instance_updater'
76
81
  require 'bosh/director/instance_updater/preparer'
77
82
  require 'bosh/director/instance_updater/state_applier'
83
+ require 'bosh/director/instance_updater/instance_state'
78
84
  require 'bosh/director/disk_manager'
79
85
  require 'bosh/director/stopper'
80
86
  require 'bosh/director/job_runner'
@@ -86,6 +92,7 @@ require 'bosh/director/nats_rpc'
86
92
  require 'bosh/director/network_reservation'
87
93
  require 'bosh/director/problem_scanner/scanner'
88
94
  require 'bosh/director/problem_resolver'
95
+ require 'bosh/director/post_deployment_script_runner'
89
96
  require 'bosh/director/error_ignorer'
90
97
  require 'bosh/director/deployment_deleter'
91
98
  require 'bosh/director/permission_authorizer'
@@ -94,6 +101,7 @@ require 'bosh/director/sequel'
94
101
  require 'common/thread_pool'
95
102
 
96
103
  require 'bosh/director/manifest/manifest'
104
+ require 'bosh/director/manifest/redactor'
97
105
  require 'bosh/director/manifest/changeset'
98
106
  require 'bosh/director/manifest/diff_lines'
99
107
 
@@ -168,6 +176,7 @@ require 'bosh/director/api/controllers/tasks_controller'
168
176
  require 'bosh/director/api/controllers/task_controller'
169
177
  require 'bosh/director/api/controllers/users_controller'
170
178
  require 'bosh/director/api/controllers/cloud_configs_controller'
179
+ require 'bosh/director/api/controllers/runtime_configs_controller'
171
180
  require 'bosh/director/api/controllers/locks_controller'
172
181
  require 'bosh/director/api/controllers/restore_controller'
173
182
  require 'bosh/director/api/route_configuration'
@@ -23,11 +23,11 @@ require 'bosh/director/api/task_manager'
23
23
  require 'bosh/director/api/user/config_user_manager'
24
24
  require 'bosh/director/api/user/database_user_manager'
25
25
  require 'bosh/director/api/user/user_manager_provider'
26
- require 'bosh/director/api/vm_state_manager'
27
26
  require 'bosh/director/api/backup_manager'
28
27
  require 'bosh/director/api/resurrector_manager'
29
28
  require 'bosh/director/api/restore_manager'
30
29
  require 'bosh/director/api/cloud_config_manager'
30
+ require 'bosh/director/api/runtime_config_manager'
31
31
 
32
32
  require 'bosh/director/api/instance_lookup'
33
33
  require 'bosh/director/api/deployment_lookup'
@@ -76,6 +76,33 @@ module Bosh::Director
76
76
  rescue SystemCallError => e
77
77
  raise SystemError, e.message
78
78
  end
79
+
80
+ def prepare_yml_file(yml_stream, manifest_type, skip_validation = false)
81
+ random_file_name = "#{manifest_type}-#{SecureRandom.uuid}"
82
+ tmp_manifest_dir = Dir::tmpdir
83
+
84
+ manifest_file_path = File.join(tmp_manifest_dir, random_file_name)
85
+ unless check_available_disk_space(tmp_manifest_dir, yml_stream.size)
86
+ raise NotEnoughDiskSpace, 'Uploading manifest failed. ' +
87
+ "Insufficient space on BOSH director in #{tmp_manifest_dir}"
88
+ end
89
+
90
+ write_file(manifest_file_path, yml_stream)
91
+
92
+ validate_manifest_yml(File.read(manifest_file_path)) unless skip_validation
93
+
94
+ manifest_file_path
95
+ end
96
+
97
+ def validate_manifest_yml(yml_string)
98
+ raise BadManifest, 'Manifest should not be empty' unless yml_string.to_s != ''
99
+
100
+ begin
101
+ Psych.parse(yml_string)
102
+ rescue Psych::SyntaxError => e
103
+ raise BadManifest, "Incorrect YAML structure of the uploaded manifest: #{e.inspect}"
104
+ end
105
+ end
79
106
  end
80
107
  end
81
108
  end
@@ -10,18 +10,14 @@ module Bosh::Director
10
10
  @config = config
11
11
  @logger = Config.logger
12
12
  @identity_provider = config.identity_provider
13
- @deployment_manager = DeploymentManager.new
13
+ @permission_authorizer = PermissionAuthorizer.new(config.get_uuid_provider)
14
14
  @backup_manager = BackupManager.new
15
15
  @restore_manager = RestoreManager.new
16
- @instance_manager = InstanceManager.new
17
16
  @resurrector_manager = ResurrectorManager.new
18
- @problem_manager = ProblemManager.new(@deployment_manager)
19
- @property_manager = PropertyManager.new(@deployment_manager)
20
17
  @release_manager = ReleaseManager.new
21
18
  @snapshot_manager = SnapshotManager.new
22
19
  @stemcell_manager = StemcellManager.new
23
20
  @task_manager = TaskManager.new
24
- @vm_state_manager = VmStateManager.new
25
21
  @dns_manager = DnsManagerProvider.create
26
22
  @disk_manager = DiskManager.new(nil, @logger)
27
23
  end
@@ -31,6 +27,8 @@ module Bosh::Director
31
27
  mime_type :tgz, 'application/x-compressed'
32
28
  mime_type :multipart, 'multipart/form-data'
33
29
 
30
+ ROUTES_WITH_EXTENDED_TIMEOUT = ['/stemcells', '/releases', '/restore']
31
+
34
32
  attr_reader :identity_provider
35
33
 
36
34
  def self.consumes(*types)
@@ -45,6 +43,31 @@ module Bosh::Director
45
43
  end
46
44
  end
47
45
 
46
+ before do
47
+ auth_provided = %w(HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION).detect do |key|
48
+ request.env.has_key?(key)
49
+ end
50
+
51
+ if auth_provided
52
+ begin
53
+ extended_token_timeout = ROUTES_WITH_EXTENDED_TIMEOUT.include?(request.path) &&
54
+ request.media_type == mime_type(:multipart) &&
55
+ request.request_method == 'POST'
56
+
57
+ @user = identity_provider.get_user(request.env, extended_token_timeout: extended_token_timeout)
58
+ rescue AuthenticationError
59
+ end
60
+ end
61
+
62
+ if requires_authentication?
63
+ response['WWW-Authenticate'] = 'Basic realm="BOSH Director"'
64
+ if @user.nil?
65
+ message = "Not authorized: '#{request.path}'\n"
66
+ throw(:halt, [401, message])
67
+ end
68
+ end
69
+ end
70
+
48
71
  def requires_authentication?
49
72
  true
50
73
  end
@@ -4,16 +4,17 @@ module Bosh::Director
4
4
  module Api::Controllers
5
5
  class CloudConfigsController < BaseController
6
6
  post '/', :consumes => :yaml do
7
- properties = request.body.string
8
- Bosh::Director::Api::CloudConfigManager.new.update(properties)
7
+ manifest_text = request.body.read
8
+ validate_manifest_yml(manifest_text)
9
9
 
10
+ Bosh::Director::Api::CloudConfigManager.new.update(manifest_text)
10
11
  status(201)
11
12
  end
12
13
 
13
14
  get '/', scope: :read do
14
15
  if params['limit'].nil? || params['limit'].empty?
15
16
  status(400)
16
- body("limit is required")
17
+ body('limit is required')
17
18
  return
18
19
  end
19
20
 
@@ -2,17 +2,62 @@ require 'bosh/director/api/controllers/base_controller'
2
2
 
3
3
  module Bosh::Director
4
4
  module Api::Controllers
5
+ module DeploymentsSecurity
6
+ def route(verb, path, options = {}, &block)
7
+ options[:scope] ||= :authorization
8
+ options[:authorization] ||= :admin
9
+ super(verb, path, options, &block)
10
+ end
11
+
12
+ def authorization(perm)
13
+ return unless perm
14
+
15
+ condition do
16
+ subject = :director
17
+ permission = perm
18
+
19
+ if :diff == permission
20
+ begin
21
+ @deployment = Bosh::Director::Api::DeploymentLookup.new.by_name(params[:deployment])
22
+ subject = @deployment
23
+ permission = :admin
24
+ rescue DeploymentNotFound
25
+ permission = :create_deployment
26
+ end
27
+ else
28
+ if params.has_key?('deployment')
29
+ @deployment = Bosh::Director::Api::DeploymentLookup.new.by_name(params[:deployment])
30
+ subject = @deployment
31
+ end
32
+ end
33
+
34
+ @permission_authorizer.granted_or_raise(subject, permission, token_scopes)
35
+ end
36
+ end
37
+ end
38
+
5
39
  class DeploymentsController < BaseController
40
+ register DeploymentsSecurity
41
+
42
+ def initialize(config)
43
+ super(config)
44
+ @deployment_manager = Api::DeploymentManager.new
45
+ @problem_manager = Api::ProblemManager.new
46
+ @property_manager = Api::PropertyManager.new
47
+ @instance_manager = Api::InstanceManager.new
48
+ @deployments_repo = DeploymentPlan::DeploymentRepo.new
49
+ end
50
+
6
51
  get '/:deployment/jobs/:job/:index_or_id' do
7
- instance = @instance_manager.find_by_name(params[:deployment], params[:job], params[:index_or_id])
52
+ instance = @instance_manager.find_by_name(deployment, params[:job], params[:index_or_id])
8
53
 
9
54
  response = {
10
- deployment: params[:deployment],
55
+ deployment: deployment.name,
11
56
  job: instance.job,
12
57
  index: instance.index,
13
58
  id: instance.uuid,
14
59
  state: instance.state,
15
- disks: instance.persistent_disks.map {|d| d.disk_cid}
60
+ disks: instance.persistent_disks.map { |d| d.disk_cid }
16
61
  }
17
62
 
18
63
  json_encode(response)
@@ -30,11 +75,15 @@ module Bosh::Director
30
75
  }
31
76
  options['skip_drain'] = params[:job] if params['skip_drain'] == 'true'
32
77
 
33
- deployment = @deployment_manager.find_by_name(params[:deployment])
34
- manifest = ((request.content_length.nil? || request.content_length.to_i == 0) && (params['state'])) ? StringIO.new(deployment.manifest) : request.body
78
+ if (request.content_length.nil? || request.content_length.to_i == 0) && (params['state'])
79
+ manifest_file_path = prepare_yml_file(StringIO.new(deployment.manifest), 'deployment', true)
80
+ else
81
+ manifest_file_path = prepare_yml_file(request.body, 'deployment')
82
+ end
35
83
 
36
84
  latest_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
37
- task = @deployment_manager.create_deployment(current_user, manifest, latest_cloud_config, options)
85
+ latest_runtime_config = Bosh::Director::Api::RuntimeConfigManager.new.latest
86
+ task = @deployment_manager.create_deployment(current_user, manifest_file_path, latest_cloud_config, latest_runtime_config, deployment.name, options)
38
87
  redirect "/tasks/#{task.id}"
39
88
  end
40
89
 
@@ -42,7 +91,7 @@ module Bosh::Director
42
91
  put '/:deployment/jobs/:job/:index_or_id', :consumes => :yaml do
43
92
  validate_instance_index_or_id(params[:index_or_id])
44
93
 
45
- instance = @instance_manager.find_by_name(params[:deployment], params[:job], params[:index_or_id])
94
+ instance = @instance_manager.find_by_name(deployment, params[:job], params[:index_or_id])
46
95
  index = instance.index
47
96
 
48
97
  options = {
@@ -56,16 +105,20 @@ module Bosh::Director
56
105
  }
57
106
  options['skip_drain'] = params[:job] if params['skip_drain'] == 'true'
58
107
 
59
- deployment = @deployment_manager.find_by_name(params[:deployment])
60
- manifest = (request.content_length.nil? || request.content_length.to_i == 0) ? StringIO.new(deployment.manifest) : request.body
108
+ if (request.content_length.nil? || request.content_length.to_i == 0)
109
+ manifest_file_path = prepare_yml_file(StringIO.new(deployment.manifest), 'deployment', true)
110
+ else
111
+ manifest_file_path = prepare_yml_file(request.body, 'deployment')
112
+ end
113
+
61
114
  latest_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
62
- task = @deployment_manager.create_deployment(current_user, manifest, latest_cloud_config, options)
115
+ latest_runtime_config = Bosh::Director::Api::RuntimeConfigManager.new.latest
116
+ task = @deployment_manager.create_deployment(current_user, manifest_file_path, latest_cloud_config, latest_runtime_config, deployment.name, options)
63
117
  redirect "/tasks/#{task.id}"
64
118
  end
65
119
 
66
120
  # GET /deployments/foo/jobs/dea/2/logs
67
121
  get '/:deployment/jobs/:job/:index_or_id/logs' do
68
- deployment = params[:deployment]
69
122
  job = params[:job]
70
123
  index_or_id = params[:index_or_id]
71
124
 
@@ -79,17 +132,14 @@ module Bosh::Director
79
132
  end
80
133
 
81
134
  get '/:deployment/snapshots' do
82
- deployment = @deployment_manager.find_by_name(params[:deployment])
83
135
  json_encode(@snapshot_manager.snapshots(deployment))
84
136
  end
85
137
 
86
138
  get '/:deployment/jobs/:job/:index/snapshots' do
87
- deployment = @deployment_manager.find_by_name(params[:deployment])
88
139
  json_encode(@snapshot_manager.snapshots(deployment, params[:job], params[:index]))
89
140
  end
90
141
 
91
142
  post '/:deployment/snapshots' do
92
- deployment = @deployment_manager.find_by_name(params[:deployment])
93
143
  # until we can tell the agent to flush and wait, all snapshots are considered dirty
94
144
  options = {clean: false}
95
145
 
@@ -98,16 +148,16 @@ module Bosh::Director
98
148
  end
99
149
 
100
150
  put '/:deployment/jobs/:job/:index_or_id/resurrection', consumes: :json do
101
- payload = json_decode(request.body)
102
151
 
103
- @resurrector_manager.set_pause_for_instance(params[:deployment], params[:job], params[:index_or_id], payload['resurrection_paused'])
152
+ payload = json_decode(request.body)
153
+ @resurrector_manager.set_pause_for_instance(deployment, params[:job], params[:index_or_id], payload['resurrection_paused'])
104
154
  end
105
155
 
106
156
  post '/:deployment/jobs/:job/:index_or_id/snapshots' do
107
157
  if params[:index_or_id].to_s =~ /^\d+$/
108
- instance = @instance_manager.find_by_name(params[:deployment], params[:job], params[:index_or_id])
158
+ instance = @instance_manager.find_by_name(deployment, params[:job], params[:index_or_id])
109
159
  else
110
- instance = @instance_manager.filter_by(uuid: params[:index_or_id]).first
160
+ instance = @instance_manager.filter_by(deployment, uuid: params[:index_or_id]).first
111
161
  end
112
162
  # until we can tell the agent to flush and wait, all snapshots are considered dirty
113
163
  options = {clean: false}
@@ -117,23 +167,22 @@ module Bosh::Director
117
167
  end
118
168
 
119
169
  delete '/:deployment/snapshots' do
120
- deployment = @deployment_manager.find_by_name(params[:deployment])
121
-
122
170
  task = @snapshot_manager.delete_deployment_snapshots_task(current_user, deployment)
123
171
  redirect "/tasks/#{task.id}"
124
172
  end
125
173
 
126
174
  delete '/:deployment/snapshots/:cid' do
127
- deployment = @deployment_manager.find_by_name(params[:deployment])
128
175
  @snapshot_manager.find_by_cid(deployment, params[:cid])
129
176
 
130
177
  task = @snapshot_manager.delete_snapshots_task(current_user, [params[:cid]])
131
178
  redirect "/tasks/#{task.id}"
132
179
  end
133
180
 
134
- get '/', scope: :read do
181
+ get '/', authorization: :list_deployments do
135
182
  latest_cloud_config = Api::CloudConfigManager.new.latest
136
- deployments = @deployment_manager.find_available(token_scopes).map do |deployment|
183
+ deployments = @deployment_manager.all_by_name_asc
184
+ .select { |deployment| @permission_authorizer.is_granted?(deployment, :read, token_scopes) }
185
+ .map do |deployment|
137
186
  cloud_config = if deployment.cloud_config.nil?
138
187
  'none'
139
188
  elsif deployment.cloud_config == latest_cloud_config
@@ -163,26 +212,33 @@ module Bosh::Director
163
212
  json_encode(deployments)
164
213
  end
165
214
 
166
- get '/:name', scope: :read do
167
- deployment = @deployment_manager.find_by_name(params[:name])
168
- @deployment_manager.deployment_to_json(deployment)
215
+ get '/:deployment', authorization: :read do
216
+ Yajl::Encoder.encode({'manifest' => deployment.manifest})
169
217
  end
170
218
 
171
- get '/:name/vms', scope: :read do
172
- deployment = @deployment_manager.find_by_name(params[:name])
173
-
219
+ get '/:deployment/vms', authorization: :read do
174
220
  format = params[:format]
175
221
  if format == 'full'
176
- task = @vm_state_manager.fetch_vm_state(current_user, deployment, format)
222
+ task = @instance_manager.fetch_instances_with_vm(current_user, deployment, format)
177
223
  redirect "/tasks/#{task.id}"
178
224
  else
179
- @deployment_manager.deployment_instances_to_json(deployment)
225
+ instances = @deployment_manager.deployment_instances_with_vms(deployment)
226
+ Yajl::Encoder.encode(create_instances_response(instances))
180
227
  end
181
228
  end
182
229
 
183
- delete '/:name' do
184
- deployment = @deployment_manager.find_by_name(params[:name])
230
+ get '/:deployment/instances', authorization: :read do
231
+ format = params[:format]
232
+ if format == 'full'
233
+ task = @instance_manager.fetch_instances(current_user, deployment, format)
234
+ redirect "/tasks/#{task.id}"
235
+ else
236
+ instances = @instance_manager.find_instances_by_deployment(deployment)
237
+ Yajl::Encoder.encode(create_instances_response(instances))
238
+ end
239
+ end
185
240
 
241
+ delete '/:deployment' do
186
242
  options = {}
187
243
  options['force'] = true if params['force'] == 'true'
188
244
  options['keep_snapshots'] = true if params['keep_snapshots'] == 'true'
@@ -190,39 +246,39 @@ module Bosh::Director
190
246
  redirect "/tasks/#{task.id}"
191
247
  end
192
248
 
249
+ post '/:deployment/ssh', :consumes => [:json] do
250
+ payload = json_decode(request.body)
251
+ task = @instance_manager.ssh(current_user, deployment, payload)
252
+ redirect "/tasks/#{task.id}"
253
+ end
254
+
193
255
  # Property management
194
256
  get '/:deployment/properties' do
195
- properties = @property_manager.get_properties(params[:deployment]).map do |property|
196
- { 'name' => property.name, 'value' => property.value }
257
+ properties = @property_manager.get_properties(deployment).map do |property|
258
+ {'name' => property.name, 'value' => property.value}
197
259
  end
198
260
  json_encode(properties)
199
261
  end
200
262
 
201
263
  get '/:deployment/properties/:property' do
202
- property = @property_manager.get_property(params[:deployment], params[:property])
264
+ property = @property_manager.get_property(deployment, params[:property])
203
265
  json_encode('value' => property.value)
204
266
  end
205
267
 
206
268
  post '/:deployment/properties', :consumes => [:json] do
207
269
  payload = json_decode(request.body)
208
- @property_manager.create_property(params[:deployment], payload['name'], payload['value'] )
270
+ @property_manager.create_property(deployment, payload['name'], payload['value'])
209
271
  status(204)
210
272
  end
211
273
 
212
- post '/:deployment/ssh', :consumes => [:json] do
213
- payload = json_decode(request.body)
214
- task = @instance_manager.ssh(current_user, payload)
215
- redirect "/tasks/#{task.id}"
216
- end
217
-
218
274
  put '/:deployment/properties/:property', :consumes => [:json] do
219
275
  payload = json_decode(request.body)
220
- @property_manager.update_property(params[:deployment], params[:property], payload['value'])
276
+ @property_manager.update_property(deployment, params[:property], payload['value'])
221
277
  status(204)
222
278
  end
223
279
 
224
280
  delete '/:deployment/properties/:property' do
225
- @property_manager.delete_property(params[:deployment], params[:property])
281
+ @property_manager.delete_property(deployment, params[:property])
226
282
  status(204)
227
283
  end
228
284
 
@@ -230,12 +286,12 @@ module Bosh::Director
230
286
 
231
287
  # Initiate deployment scan
232
288
  post '/:deployment/scans' do
233
- start_task { @problem_manager.perform_scan(current_user, params[:deployment]) }
289
+ start_task { @problem_manager.perform_scan(current_user, deployment) }
234
290
  end
235
291
 
236
292
  # Get the list of problems for a particular deployment
237
293
  get '/:deployment/problems' do
238
- problems = @problem_manager.get_problems(params[:deployment]).map do |problem|
294
+ problems = @problem_manager.get_problems(deployment).map do |problem|
239
295
  {
240
296
  'id' => problem.id,
241
297
  'type' => problem.type,
@@ -250,84 +306,104 @@ module Bosh::Director
250
306
 
251
307
  put '/:deployment/problems', :consumes => [:json] do
252
308
  payload = json_decode(request.body)
253
- start_task { @problem_manager.apply_resolutions(current_user, params[:deployment], payload['resolutions']) }
309
+ start_task { @problem_manager.apply_resolutions(current_user, deployment, payload['resolutions']) }
254
310
  end
255
311
 
256
312
  put '/:deployment/scan_and_fix', :consumes => :json do
257
313
  jobs_json = json_decode(request.body)['jobs']
258
314
  payload = convert_job_instance_hash(jobs_json)
259
-
260
- deployment = @deployment_manager.find_by_name(params[:deployment])
261
315
  if deployment_has_instance_to_resurrect?(deployment)
262
- start_task { @problem_manager.scan_and_fix(current_user, params[:deployment], payload) }
316
+ start_task { @problem_manager.scan_and_fix(current_user, deployment, payload) }
263
317
  end
264
318
  end
265
319
 
266
- post '/', :consumes => :yaml do
320
+ post '/', authorization: :create_deployment, :consumes => :yaml do
321
+ manifest_file_path = prepare_yml_file(request.body, 'deployment')
322
+
267
323
  options = {}
268
324
  options['recreate'] = true if params['recreate'] == 'true'
269
325
  options['skip_drain'] = params['skip_drain'] if params['skip_drain']
326
+ options.merge!('scopes' => token_scopes)
327
+
270
328
  if params['context']
271
329
  @logger.debug("Deploying with context #{params['context']}")
272
330
  context = JSON.parse(params['context'])
273
331
  cloud_config = Api::CloudConfigManager.new.find_by_id(context['cloud_config_id'])
332
+ runtime_config = Api::RuntimeConfigManager.new.find_by_id(context['runtime_config_id'])
274
333
  else
275
334
  cloud_config = Api::CloudConfigManager.new.latest
335
+ runtime_config = Api::RuntimeConfigManager.new.latest
276
336
  end
277
337
 
278
- options.merge!('scopes' => token_scopes)
279
- task = @deployment_manager.create_deployment(current_user, request.body, cloud_config, options)
338
+ deployment = Psych.load(File.read(manifest_file_path), manifest_file_path)
339
+
340
+ if deployment
341
+ deployment_name = deployment['name']
342
+ if deployment_name
343
+ @deployments_repo.find_or_create_by_name(deployment_name, options)
344
+ end
345
+ end
346
+
347
+ task = @deployment_manager.create_deployment(current_user, manifest_file_path, cloud_config, runtime_config, deployment_name, options)
348
+
280
349
  redirect "/tasks/#{task.id}"
281
350
  end
282
351
 
283
- post '/:deployment/diff', :consumes => :yaml do
284
- deployment = Models::Deployment[name: params[:deployment]]
352
+ post '/:deployment/diff', authorization: :diff, :consumes => :yaml do
353
+ manifest_text = request.body.read
354
+ validate_manifest_yml(manifest_text)
355
+
285
356
  if deployment
286
- before_manifest = Manifest.load_from_text(deployment.manifest, deployment.cloud_config)
357
+ before_manifest = Manifest.load_from_text(deployment.manifest, deployment.cloud_config, deployment.runtime_config)
287
358
  before_manifest.resolve_aliases
288
359
  else
289
- before_manifest = Manifest.load_from_text(nil, nil)
360
+ before_manifest = Manifest.load_from_text(nil, nil, nil)
290
361
  end
291
362
 
292
363
  after_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
364
+ after_runtime_config = Bosh::Director::Api::RuntimeConfigManager.new.latest
293
365
  after_manifest = Manifest.load_from_text(
294
- request.body,
295
- after_cloud_config
366
+ manifest_text,
367
+ after_cloud_config,
368
+ after_runtime_config
296
369
  )
297
370
  after_manifest.resolve_aliases
298
371
 
299
- diff = before_manifest.diff(after_manifest)
372
+ redact = params['redact'] != 'false'
373
+
374
+ diff = before_manifest.diff(after_manifest, redact)
300
375
 
301
376
  json_encode({
302
- 'context' => {
303
- 'cloud_config_id' => after_cloud_config ? after_cloud_config.id : nil,
304
- },
305
- 'diff' => diff.map { |l| [l.to_s, l.status] }
306
- })
377
+ 'context' => {
378
+ 'cloud_config_id' => after_cloud_config ? after_cloud_config.id : nil,
379
+ 'runtime_config_id' => after_runtime_config ? after_runtime_config.id : nil
380
+ },
381
+ 'diff' => diff.map { |l| [l.to_s, l.status] }
382
+ })
307
383
  end
308
384
 
309
- post '/:deployment_name/errands/:errand_name/runs' do
310
- deployment_name = params[:deployment_name]
385
+ post '/:deployment/errands/:errand_name/runs' do
311
386
  errand_name = params[:errand_name]
312
387
  keep_alive = json_decode(request.body)['keep-alive'] || FALSE
313
388
 
314
389
  task = JobQueue.new.enqueue(
315
390
  current_user,
316
391
  Jobs::RunErrand,
317
- "run errand #{errand_name} from deployment #{deployment_name}",
318
- [deployment_name, errand_name, keep_alive],
392
+ "run errand #{errand_name} from deployment #{deployment.name}",
393
+ [deployment.name, errand_name, keep_alive],
394
+ deployment.name
319
395
  )
320
396
 
321
397
  redirect "/tasks/#{task.id}"
322
398
  end
323
399
 
324
- get '/:deployment_name/errands', scope: :read do
400
+ get '/:deployment/errands', authorization: :read do
325
401
  deployment_plan = load_deployment_plan
326
402
 
327
- errands = deployment_plan.jobs.select(&:can_run_as_errand?)
403
+ errands = deployment_plan.jobs.select(&:is_errand?)
328
404
 
329
405
  errand_data = errands.map do |errand|
330
- { "name" => errand.name }
406
+ {"name" => errand.name}
331
407
  end
332
408
 
333
409
  json_encode(errand_data)
@@ -335,11 +411,11 @@ module Bosh::Director
335
411
 
336
412
  private
337
413
 
338
- def load_deployment_plan
339
- deployment_model = @deployment_manager.find_by_name(params[:deployment_name])
414
+ attr_accessor :deployment
340
415
 
416
+ def load_deployment_plan
341
417
  planner_factory = Bosh::Director::DeploymentPlan::PlannerFactory.create(Config.logger)
342
- planner_factory.create_from_model(deployment_model)
418
+ planner_factory.create_from_model(deployment)
343
419
  end
344
420
 
345
421
  def convert_job_instance_hash(hash)
@@ -351,11 +427,7 @@ module Bosh::Director
351
427
 
352
428
  def deployment_has_instance_to_resurrect?(deployment)
353
429
  false if deployment.nil?
354
- filter = {
355
- deployment_id: deployment.id,
356
- resurrection_paused: false
357
- }
358
- instances = @instance_manager.filter_by(filter)
430
+ instances = @instance_manager.filter_by(deployment, resurrection_paused: false)
359
431
  instances.any?
360
432
  end
361
433
 
@@ -368,6 +440,18 @@ module Bosh::Director
368
440
  end
369
441
  end
370
442
  end
443
+
444
+ def create_instances_response(instances)
445
+ instances.map do |instance|
446
+ {
447
+ 'agent_id' => instance.agent_id,
448
+ 'cid' => instance.vm_cid,
449
+ 'job' => instance.job,
450
+ 'index' => instance.index,
451
+ 'id' => instance.uuid
452
+ }
453
+ end
454
+ end
371
455
  end
372
456
  end
373
457
  end