bosh-director 1.3202.0 → 1.3213.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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