bosh-director 1.3160.0 → 1.3163.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/bosh-director-worker +2 -14
- data/db/migrations/director/20150513225143_ip_addresses.rb +11 -0
- data/db/migrations/director/20150702004608_add_links.rb +8 -0
- data/db/migrations/director/20150708231924_add_link_spec.rb +7 -0
- data/db/migrations/director/20150724183256_add_debugging_to_ip_addresses.rb +8 -0
- data/db/migrations/director/20150730225029_add_uuid_to_instances.rb +16 -0
- data/db/migrations/director/20150803215805_add_availabililty_zone_and_cloud_properties_to_instances.rb +8 -0
- data/db/migrations/director/20150804211419_add_compilation_flag_to_instance.rb +7 -0
- data/db/migrations/director/20150918003455_add_bootstrap_node_to_instance.rb +7 -0
- data/db/migrations/director/20151008232214_add_dns_records.rb +7 -0
- data/db/migrations/director/20151015172551_add_orphan_disks_and_snapshots.rb +29 -0
- data/db/migrations/director/20151030222853_add_templates_to_instance.rb +10 -0
- data/db/migrations/director/20151031001039_add_spec_to_instance.rb +19 -0
- data/db/migrations/director/20151109190602_rename_orphan_columns.rb +13 -0
- data/lib/bosh/director.rb +19 -9
- data/lib/bosh/director/agent_client.rb +0 -17
- data/lib/bosh/director/api/cloud_config_manager.rb +7 -5
- data/lib/bosh/director/api/controllers/base_controller.rb +3 -2
- data/lib/bosh/director/api/controllers/cleanup_controller.rb +15 -0
- data/lib/bosh/director/api/controllers/deployments_controller.rb +38 -26
- data/lib/bosh/director/api/controllers/disks_controller.rb +20 -0
- data/lib/bosh/director/api/controllers/info_controller.rb +2 -2
- data/lib/bosh/director/api/controllers/releases_controller.rb +1 -16
- data/lib/bosh/director/api/controllers/stemcells_controller.rb +1 -9
- data/lib/bosh/director/api/deployment_manager.rb +2 -1
- data/lib/bosh/director/api/instance_lookup.rb +17 -0
- data/lib/bosh/director/api/instance_manager.rb +20 -10
- data/lib/bosh/director/api/release_manager.rb +28 -8
- data/lib/bosh/director/api/resurrector_manager.rb +9 -2
- data/lib/bosh/director/api/route_configuration.rb +2 -0
- data/lib/bosh/director/api/snapshot_manager.rb +9 -5
- data/lib/bosh/director/api/stemcell_manager.rb +50 -0
- data/lib/bosh/director/app.rb +1 -1
- data/lib/bosh/director/cloudcheck_helper.rb +119 -132
- data/lib/bosh/director/compile_task.rb +1 -1
- data/lib/bosh/director/compile_task_generator.rb +2 -2
- data/lib/bosh/director/config.rb +21 -12
- data/lib/bosh/director/deployment_deleter.rb +69 -0
- data/lib/bosh/director/deployment_plan.rb +35 -4
- data/lib/bosh/director/deployment_plan/agent_state_migrator.rb +47 -0
- data/lib/bosh/director/deployment_plan/assembler.rb +115 -241
- data/lib/bosh/director/deployment_plan/availability_zone.rb +27 -0
- data/lib/bosh/director/deployment_plan/cloud_manifest_parser.rb +144 -35
- data/lib/bosh/director/deployment_plan/compilation_config.rb +21 -19
- data/lib/bosh/director/deployment_plan/compilation_instance_pool.rb +169 -0
- data/lib/bosh/director/deployment_plan/deployment_repo.rb +4 -8
- data/lib/bosh/director/deployment_plan/deployment_spec_parser.rb +13 -1
- data/lib/bosh/director/deployment_plan/deployment_validator.rb +17 -0
- data/lib/bosh/director/deployment_plan/desired_instance.rb +15 -0
- data/lib/bosh/director/deployment_plan/{disk_pool.rb → disk_type.rb} +14 -19
- data/lib/bosh/director/deployment_plan/dynamic_network.rb +105 -53
- data/lib/bosh/director/deployment_plan/dynamic_network_subnet.rb +13 -0
- data/lib/bosh/director/deployment_plan/env.rb +18 -0
- data/lib/bosh/director/deployment_plan/global_network_resolver.rb +77 -0
- data/lib/bosh/director/deployment_plan/instance.rb +222 -390
- data/lib/bosh/director/deployment_plan/instance_network_reservations.rb +71 -0
- data/lib/bosh/director/deployment_plan/instance_plan.rb +336 -0
- data/lib/bosh/director/deployment_plan/instance_plan_factory.rb +54 -0
- data/lib/bosh/director/deployment_plan/instance_plan_sorter.rb +61 -0
- data/lib/bosh/director/deployment_plan/instance_planner.rb +101 -0
- data/lib/bosh/director/deployment_plan/instance_repository.rb +36 -0
- data/lib/bosh/director/deployment_plan/instance_spec.rb +154 -0
- data/lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb +136 -0
- data/lib/bosh/director/deployment_plan/ip_provider/in_memory_ip_repo.rb +81 -0
- data/lib/bosh/director/deployment_plan/ip_provider/ip_provider.rb +153 -0
- data/lib/bosh/director/deployment_plan/ip_provider/ip_provider_factory.rb +22 -0
- data/lib/bosh/director/deployment_plan/job.rb +116 -53
- data/lib/bosh/director/deployment_plan/job_availability_zone_parser.rb +49 -0
- data/lib/bosh/director/deployment_plan/job_migrator.rb +90 -0
- data/lib/bosh/director/deployment_plan/job_network.rb +42 -0
- data/lib/bosh/director/deployment_plan/job_network_parser.rb +118 -0
- data/lib/bosh/director/deployment_plan/job_spec_parser.rb +123 -126
- data/lib/bosh/director/deployment_plan/links/link.rb +30 -0
- data/lib/bosh/director/deployment_plan/links/link_lookup.rb +66 -0
- data/lib/bosh/director/deployment_plan/links/link_path.rb +27 -0
- data/lib/bosh/director/deployment_plan/links/links_resolver.rb +70 -0
- data/lib/bosh/director/deployment_plan/links/template_link.rb +21 -0
- data/lib/bosh/director/deployment_plan/manifest_migrator.rb +3 -17
- data/lib/bosh/director/deployment_plan/manifest_validator.rb +46 -0
- data/lib/bosh/director/deployment_plan/manual_network.rb +70 -97
- data/lib/bosh/director/deployment_plan/manual_network_subnet.rb +148 -0
- data/lib/bosh/director/deployment_plan/network.rb +50 -39
- data/lib/bosh/director/deployment_plan/network_planner.rb +4 -0
- data/lib/bosh/director/deployment_plan/network_planner/plan.rb +26 -0
- data/lib/bosh/director/deployment_plan/network_planner/planner.rb +21 -0
- data/lib/bosh/director/deployment_plan/network_planner/reservation_reconciler.rb +81 -0
- data/lib/bosh/director/deployment_plan/network_planner/vip_static_ips_planner.rb +50 -0
- data/lib/bosh/director/deployment_plan/network_settings.rb +65 -0
- data/lib/bosh/director/deployment_plan/options/skip_drain.rb +7 -0
- data/lib/bosh/director/deployment_plan/package_validator.rb +79 -0
- data/lib/bosh/director/deployment_plan/placement_planner.rb +8 -0
- data/lib/bosh/director/deployment_plan/placement_planner/availability_zone_picker.rb +90 -0
- data/lib/bosh/director/deployment_plan/placement_planner/bruteforce_ip_allocation.rb +124 -0
- data/lib/bosh/director/deployment_plan/placement_planner/index_assigner.rb +32 -0
- data/lib/bosh/director/deployment_plan/placement_planner/networks_to_static_ips.rb +125 -0
- data/lib/bosh/director/deployment_plan/placement_planner/placed_desired_instances.rb +40 -0
- data/lib/bosh/director/deployment_plan/placement_planner/plan.rb +42 -0
- data/lib/bosh/director/deployment_plan/placement_planner/static_ips_availability_zone_picker.rb +237 -0
- data/lib/bosh/director/deployment_plan/placement_planner/unplaced_existing_instances.rb +53 -0
- data/lib/bosh/director/deployment_plan/planner.rb +186 -74
- data/lib/bosh/director/deployment_plan/planner_factory.rb +30 -147
- data/lib/bosh/director/deployment_plan/release_version.rb +3 -3
- data/lib/bosh/director/deployment_plan/resource_pool.rb +2 -174
- data/lib/bosh/director/deployment_plan/stemcell.rb +57 -14
- data/lib/bosh/director/deployment_plan/steps/package_compile_step.rb +28 -135
- data/lib/bosh/director/deployment_plan/steps/update_step.rb +23 -44
- data/lib/bosh/director/deployment_plan/template.rb +15 -4
- data/lib/bosh/director/deployment_plan/vip_network.rb +14 -42
- data/lib/bosh/director/deployment_plan/vm.rb +1 -99
- data/lib/bosh/director/deployment_plan/vm_type.rb +27 -0
- data/lib/bosh/director/disk_manager.rb +268 -0
- data/lib/bosh/director/dns/canonicalizer.rb +28 -0
- data/lib/bosh/director/dns/dns_manager.rb +163 -0
- data/lib/bosh/director/dns/local_dns_repo.rb +20 -0
- data/lib/bosh/director/dns/powerdns.rb +170 -0
- data/lib/bosh/director/errand/job_manager.rb +18 -29
- data/lib/bosh/director/error_ignorer.rb +16 -0
- data/lib/bosh/director/errors.rb +51 -20
- data/lib/bosh/director/event_log.rb +6 -0
- data/lib/bosh/director/instance_deleter.rb +53 -81
- data/lib/bosh/director/instance_reuser.rb +89 -0
- data/lib/bosh/director/instance_updater.rb +139 -281
- data/lib/bosh/director/instance_updater/preparer.rb +8 -5
- data/lib/bosh/director/instance_updater/state_applier.rb +21 -0
- data/lib/bosh/director/ip_util.rb +46 -26
- data/lib/bosh/director/job_renderer.rb +22 -10
- data/lib/bosh/director/job_runner.rb +1 -4
- data/lib/bosh/director/job_updater.rb +47 -35
- data/lib/bosh/director/job_updater_factory.rb +5 -4
- data/lib/bosh/director/jobs/base_job.rb +8 -0
- data/lib/bosh/director/jobs/cleanup_artifacts.rb +93 -0
- data/lib/bosh/director/jobs/delete_deployment.rb +10 -154
- data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +1 -1
- data/lib/bosh/director/jobs/delete_orphan_disks.rb +44 -0
- data/lib/bosh/director/jobs/delete_release.rb +19 -196
- data/lib/bosh/director/jobs/delete_stemcell.rb +10 -76
- data/lib/bosh/director/jobs/export_release.rb +41 -121
- data/lib/bosh/director/jobs/fetch_logs.rb +0 -6
- data/lib/bosh/director/jobs/helpers.rb +10 -0
- data/lib/bosh/director/jobs/helpers/blob_deleter.rb +24 -0
- data/lib/bosh/director/jobs/helpers/compiled_package_deleter.rb +24 -0
- data/lib/bosh/director/jobs/helpers/name_version_release_deleter.rb +48 -0
- data/lib/bosh/director/jobs/helpers/package_deleter.rb +33 -0
- data/lib/bosh/director/jobs/helpers/release_deleter.rb +52 -0
- data/lib/bosh/director/jobs/helpers/release_version_deleter.rb +115 -0
- data/lib/bosh/director/jobs/helpers/releases_to_delete_picker.rb +31 -0
- data/lib/bosh/director/jobs/helpers/stemcell_deleter.rb +61 -0
- data/lib/bosh/director/jobs/helpers/stemcells_to_delete_picker.rb +30 -0
- data/lib/bosh/director/jobs/helpers/template_deleter.rb +20 -0
- data/lib/bosh/director/jobs/release/release_job.rb +18 -7
- data/lib/bosh/director/jobs/run_errand.rb +57 -36
- data/lib/bosh/director/jobs/scheduled_orphan_cleanup.rb +46 -0
- data/lib/bosh/director/jobs/ssh.rb +50 -17
- data/lib/bosh/director/jobs/update_deployment.rb +29 -11
- data/lib/bosh/director/jobs/update_release.rb +25 -4
- data/lib/bosh/director/jobs/vm_state.rb +23 -32
- data/lib/bosh/director/lock.rb +13 -8
- data/lib/bosh/director/logs_fetcher.rb +1 -1
- data/lib/bosh/director/models.rb +3 -0
- data/lib/bosh/director/models/compiled_package.rb +3 -3
- data/lib/bosh/director/models/deployment.rb +10 -0
- data/lib/bosh/director/models/instance.rb +77 -1
- data/lib/bosh/director/models/ip_address.rb +26 -0
- data/lib/bosh/director/models/orphan_disk.rb +23 -0
- data/lib/bosh/director/models/orphan_snapshot.rb +14 -0
- data/lib/bosh/director/models/template.rb +32 -9
- data/lib/bosh/director/models/vm.rb +5 -8
- data/lib/bosh/director/network_reservation.rb +69 -99
- data/lib/bosh/director/problem_handlers/inactive_disk.rb +5 -20
- data/lib/bosh/director/problem_handlers/missing_disk.rb +2 -13
- data/lib/bosh/director/problem_resolver.rb +2 -2
- data/lib/bosh/director/problem_scanner/vm_scan_stage.rb +2 -21
- data/lib/bosh/director/scheduler.rb +23 -6
- data/lib/bosh/director/{instance_updater/stopper.rb → stopper.rb} +24 -18
- data/lib/bosh/director/tagged_logger.rb +30 -0
- data/lib/bosh/director/transactor.rb +9 -0
- data/lib/bosh/director/version.rb +1 -1
- data/lib/bosh/director/vm_creator.rb +91 -19
- data/lib/bosh/director/vm_deleter.rb +25 -0
- data/lib/bosh/director/vm_recreator.rb +15 -0
- data/lib/cloud/dummy.rb +381 -94
- metadata +110 -30
- data/lib/bosh/director/deployment_plan/dns_binder.rb +0 -45
- data/lib/bosh/director/deployment_plan/instance_vm_binder.rb +0 -37
- data/lib/bosh/director/deployment_plan/network_subnet.rb +0 -166
- data/lib/bosh/director/deployment_plan/resource_pools.rb +0 -68
- data/lib/bosh/director/dns_helper.rb +0 -223
- data/lib/bosh/director/instance_updater/network_updater.rb +0 -110
- data/lib/bosh/director/instance_updater/vm_updater.rb +0 -189
- data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +0 -64
- data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +0 -85
- data/lib/bosh/director/resource_pool_updater.rb +0 -174
- data/lib/bosh/director/vm_data.rb +0 -63
- data/lib/bosh/director/vm_reuser.rb +0 -63
@@ -0,0 +1,65 @@
|
|
1
|
+
module Bosh::Director::DeploymentPlan
|
2
|
+
class NetworkSettings
|
3
|
+
def initialize(job_name, deployment_name, default_network, desired_reservations, state, availability_zone, instance_index, instance_id, dns_manager)
|
4
|
+
@job_name = job_name
|
5
|
+
@desired_reservations = desired_reservations
|
6
|
+
@default_network = default_network
|
7
|
+
@deployment_name = deployment_name
|
8
|
+
@state = state
|
9
|
+
@availability_zone = availability_zone
|
10
|
+
@instance_index = instance_index
|
11
|
+
@instance_id = instance_id
|
12
|
+
@dns_manager = dns_manager
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
default_properties = {}
|
17
|
+
@default_network.each do |key, value|
|
18
|
+
(default_properties[value] ||= []) << key
|
19
|
+
end
|
20
|
+
|
21
|
+
network_settings = {}
|
22
|
+
@desired_reservations.each do |reservation|
|
23
|
+
network_name = reservation.network.name
|
24
|
+
network_settings[network_name] = reservation.network.network_settings(reservation, default_properties[network_name], @availability_zone)
|
25
|
+
|
26
|
+
# Somewhat of a hack: for dynamic networks we might know IP address, Netmask & Gateway
|
27
|
+
# if they're featured in agent state, in that case we put them into network spec to satisfy
|
28
|
+
# ConfigurationHasher in both agent and director.
|
29
|
+
if @state.is_a?(Hash) &&
|
30
|
+
@state['networks'].is_a?(Hash) &&
|
31
|
+
@state['networks'][network_name].is_a?(Hash) &&
|
32
|
+
network_settings[network_name]['type'] == 'dynamic'
|
33
|
+
%w(ip netmask gateway).each do |key|
|
34
|
+
network_settings[network_name][key] = @state['networks'][network_name][key]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
network_settings
|
40
|
+
end
|
41
|
+
|
42
|
+
def dns_record_info
|
43
|
+
dns_record_info = {}
|
44
|
+
to_hash.each do |network_name, network|
|
45
|
+
index_dns_name = @dns_manager.dns_record_name(@instance_index, @job_name, network_name, @deployment_name)
|
46
|
+
dns_record_info[index_dns_name] = network['ip']
|
47
|
+
id_dns_name = @dns_manager.dns_record_name(@instance_id, @job_name, network_name, @deployment_name)
|
48
|
+
dns_record_info[id_dns_name] = network['ip']
|
49
|
+
end
|
50
|
+
dns_record_info
|
51
|
+
end
|
52
|
+
|
53
|
+
def network_addresses
|
54
|
+
network_addresses = {}
|
55
|
+
to_hash.each do |network_name, network|
|
56
|
+
network_addresses[network_name] = {
|
57
|
+
'address' => network['type'] == 'dynamic' ?
|
58
|
+
@dns_manager.dns_record_name(@instance_id, @job_name, network_name, @deployment_name) :
|
59
|
+
network['ip']
|
60
|
+
}
|
61
|
+
end
|
62
|
+
network_addresses
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Bosh::Director
|
2
|
+
module DeploymentPlan
|
3
|
+
class PackageValidator
|
4
|
+
def initialize(logger)
|
5
|
+
@faults = {}
|
6
|
+
@logger = logger
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate(release_version_model, stemcel_model)
|
10
|
+
release_desc = "#{release_version_model.release.name}/#{release_version_model.version}"
|
11
|
+
|
12
|
+
@logger.debug("Validating packages for release '#{release_desc}'")
|
13
|
+
release_version_model.packages.each do |package|
|
14
|
+
packages_list = release_version_model.transitive_dependencies(package)
|
15
|
+
packages_list << package
|
16
|
+
packages_list.each do |needed_package|
|
17
|
+
if needed_package.sha1.nil? || needed_package.blobstore_id.nil?
|
18
|
+
compiled_packages_list = Bosh::Director::Models::CompiledPackage[:package_id => needed_package.id, :stemcell_id => stemcel_model.id]
|
19
|
+
if compiled_packages_list.nil?
|
20
|
+
@faults[release_desc] ||= Set.new
|
21
|
+
@faults[release_desc] << Fault.new(needed_package, stemcel_model)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_faults
|
29
|
+
return if @faults.empty?
|
30
|
+
|
31
|
+
msg = "\n"
|
32
|
+
unique_stemcells = @faults.map { |_, faults| faults.map { |fault| fault.stemcell } }.flatten.to_set
|
33
|
+
|
34
|
+
@faults.each do |release_desc, faults|
|
35
|
+
if unique_stemcells.size > 1
|
36
|
+
msg += message_for_multiple_stemcells(release_desc, faults)
|
37
|
+
else
|
38
|
+
msg += message_for_single_stemcell(release_desc, faults)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
raise PackageMissingSourceCode, msg
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def message_for_multiple_stemcells(release_desc, faults)
|
48
|
+
msg = "Can't use release '#{release_desc}'. It references packages without source code and are not compiled against intended stemcells:\n"
|
49
|
+
sorted_faults = faults.to_a.sort_by { |fault| fault.package.name }
|
50
|
+
sorted_faults.each do |fault|
|
51
|
+
msg += " - '#{fault.package_desc}' against stemcell '#{fault.stemcell.desc}'\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
msg
|
55
|
+
end
|
56
|
+
|
57
|
+
def message_for_single_stemcell(release_desc, faults)
|
58
|
+
sorted_faults = faults.to_a.sort_by { |fault| fault.package.name }
|
59
|
+
stemcell_desc = faults.first.stemcell.desc
|
60
|
+
|
61
|
+
msg = "Can't use release '#{release_desc}'. It references packages without" +
|
62
|
+
" source code and are not compiled against stemcell '#{stemcell_desc}':\n"
|
63
|
+
sorted_faults.each do |fault|
|
64
|
+
msg += " - '#{fault.package_desc}'\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
msg
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
class Fault < Struct.new(:package, :stemcell)
|
73
|
+
def package_desc
|
74
|
+
"#{package.name}/#{package.version}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'bosh/director/deployment_plan/placement_planner/plan'
|
2
|
+
require 'bosh/director/deployment_plan/placement_planner/index_assigner'
|
3
|
+
require 'bosh/director/deployment_plan/placement_planner/availability_zone_picker'
|
4
|
+
require 'bosh/director/deployment_plan/placement_planner/static_ips_availability_zone_picker'
|
5
|
+
require 'bosh/director/deployment_plan/placement_planner/networks_to_static_ips'
|
6
|
+
require 'bosh/director/deployment_plan/placement_planner/bruteforce_ip_allocation'
|
7
|
+
require 'bosh/director/deployment_plan/placement_planner/placed_desired_instances'
|
8
|
+
require 'bosh/director/deployment_plan/placement_planner/unplaced_existing_instances'
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Director
|
3
|
+
module DeploymentPlan
|
4
|
+
module PlacementPlanner
|
5
|
+
class AvailabilityZonePicker
|
6
|
+
def initialize(instance_plan_factory, network_planner, networks, desired_azs)
|
7
|
+
@instance_plan_factory = instance_plan_factory
|
8
|
+
@network_planner = network_planner
|
9
|
+
@networks = networks
|
10
|
+
@desired_azs = desired_azs
|
11
|
+
@logger = Config.logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def place_and_match_in(desired_instances, existing_instance_models)
|
15
|
+
unplaced_existing_instances = UnplacedExistingInstances.new(existing_instance_models)
|
16
|
+
desired_azs_sorted = unplaced_existing_instances.azs_sorted_by_existing_instance_count_descending(@desired_azs)
|
17
|
+
@logger.debug("Desired azs: #{desired_azs_sorted.inspect}")
|
18
|
+
placed_instances = PlacedDesiredInstances.new(desired_azs_sorted)
|
19
|
+
|
20
|
+
remaining_desired_instances = place_instances_that_have_persistent_disk_in_existing_az(desired_azs_sorted, desired_instances, placed_instances, unplaced_existing_instances)
|
21
|
+
balance_across_desired_azs(remaining_desired_instances, placed_instances, unplaced_existing_instances)
|
22
|
+
|
23
|
+
obsolete_instance_plans(unplaced_existing_instances.unclaimed) +
|
24
|
+
desired_existing_instance_plans(placed_instances.existing) +
|
25
|
+
desired_new_instance_plans(placed_instances.absent)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def place_instances_that_have_persistent_disk_in_existing_az(desired_azs, desired_instances, placed_instances, unplaced_existing_instances)
|
31
|
+
desired_instances = desired_instances.dup
|
32
|
+
return desired_instances if desired_azs.nil?
|
33
|
+
unplaced_existing_instances.instances_with_persistent_disk.each do |existing_instance|
|
34
|
+
break if desired_instances.empty?
|
35
|
+
az = desired_azs.find { |az| az.name == existing_instance.availability_zone }
|
36
|
+
next if az.nil?
|
37
|
+
desired_instance = desired_instances.pop
|
38
|
+
unplaced_existing_instances.claim_instance(existing_instance)
|
39
|
+
placed_instances.record_placement(az, desired_instance, existing_instance)
|
40
|
+
end
|
41
|
+
desired_instances
|
42
|
+
end
|
43
|
+
|
44
|
+
def balance_across_desired_azs(desired_instances, placed_instances, unplaced_existing_instances)
|
45
|
+
desired_instances.each do |desired_instance|
|
46
|
+
azs_with_fewest_placed = placed_instances.azs_with_fewest_instances
|
47
|
+
@logger.debug("azs with fewest placed: #{azs_with_fewest_placed.inspect}")
|
48
|
+
az = unplaced_existing_instances.azs_sorted_by_existing_instance_count_descending(azs_with_fewest_placed).first
|
49
|
+
@logger.debug("az: #{az.inspect}")
|
50
|
+
|
51
|
+
existing_instance = unplaced_existing_instances.claim_instance_for_az(az)
|
52
|
+
placed_instances.record_placement(az, desired_instance, existing_instance)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def obsolete_instance_plans(obsolete_instances)
|
57
|
+
obsolete_instances.map do |existing_instance|
|
58
|
+
@instance_plan_factory.obsolete_instance_plan(existing_instance)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def desired_existing_instance_plans(desired_existing_instances)
|
63
|
+
desired_existing_instances.map do |desired_existing_instance|
|
64
|
+
instance_plan = @instance_plan_factory.desired_existing_instance_plan(
|
65
|
+
desired_existing_instance[:existing_instance_model],
|
66
|
+
desired_existing_instance[:desired_instance]
|
67
|
+
)
|
68
|
+
populate_network_plans(instance_plan)
|
69
|
+
instance_plan
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def desired_new_instance_plans(new_desired_instances)
|
74
|
+
new_desired_instances.map do |desired_instance|
|
75
|
+
instance_plan = @instance_plan_factory.desired_new_instance_plan(desired_instance)
|
76
|
+
populate_network_plans(instance_plan)
|
77
|
+
instance_plan
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def populate_network_plans(instance_plan)
|
82
|
+
@networks.each do |network|
|
83
|
+
instance_plan.network_plans << @network_planner.network_plan_with_dynamic_reservation(instance_plan, network)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'common/deep_copy'
|
2
|
+
|
3
|
+
module Bosh
|
4
|
+
module Director
|
5
|
+
module DeploymentPlan
|
6
|
+
module PlacementPlanner
|
7
|
+
class BruteForceIpAllocation
|
8
|
+
def initialize(networks_to_static_ips)
|
9
|
+
@networks_to_static_ips = networks_to_static_ips
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_best_combination
|
13
|
+
allocated_ips = AllocatedIps.new
|
14
|
+
try_combination(@networks_to_static_ips, allocated_ips)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def try_combination(networks_to_static_ips, allocated_ips)
|
20
|
+
if all_ips_belong_to_single_az(networks_to_static_ips)
|
21
|
+
if even_distribution_of_ips?(networks_to_static_ips)
|
22
|
+
return networks_to_static_ips
|
23
|
+
else
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
previous_network = nil
|
29
|
+
networks_to_static_ips.each do |network, static_ips_to_azs|
|
30
|
+
if previous_network
|
31
|
+
previous_assignment = PreviousAssignment.new(networks_to_static_ips[previous_network])
|
32
|
+
unless previous_assignment.has_same_distribution?(static_ips_to_azs)
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
previous_network = network
|
37
|
+
|
38
|
+
static_ips_to_azs.each_with_index do |static_ip_to_azs|
|
39
|
+
if static_ip_to_azs.az_names.size == 1
|
40
|
+
allocated_ips.allocate(static_ip_to_azs.az_names.first)
|
41
|
+
next
|
42
|
+
end
|
43
|
+
|
44
|
+
# prioritize AZs based on least number of allocated IPs
|
45
|
+
sorted_az_names = allocated_ips.sort_by_least_allocated_ips(static_ip_to_azs.az_names)
|
46
|
+
sorted_az_names.each do |az_name|
|
47
|
+
static_ip_to_azs.az_names = [az_name]
|
48
|
+
allocated_ips.allocate(az_name)
|
49
|
+
candidate_networks_to_static_ips = Bosh::Common::DeepCopy.copy(networks_to_static_ips)
|
50
|
+
result = try_combination(candidate_networks_to_static_ips, AllocatedIps.new)
|
51
|
+
next if result.nil?
|
52
|
+
return result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def even_distribution_of_ips?(networks_to_static_ips)
|
61
|
+
hash = {}
|
62
|
+
networks_to_static_ips.each do |network, static_ips_to_azs|
|
63
|
+
hash[network] ||= {}
|
64
|
+
static_ips_to_azs.each do |static_ip_to_azs|
|
65
|
+
static_ip_to_azs.az_names.each do |az_name|
|
66
|
+
hash[network][az_name] ||= 0
|
67
|
+
hash[network][az_name] += 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
hash.values.uniq.size > 1 ? false : true
|
74
|
+
end
|
75
|
+
|
76
|
+
def all_ips_belong_to_single_az(networks_to_static_ips)
|
77
|
+
!networks_to_static_ips.values.any? do |static_ips_to_azs|
|
78
|
+
static_ips_to_azs.any? do |static_ip_to_az|
|
79
|
+
static_ip_to_az.az_names.size > 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class AllocatedIps
|
85
|
+
def initialize
|
86
|
+
@allocated_ips = Hash.new {|h,k| h[k] = 0 }
|
87
|
+
end
|
88
|
+
|
89
|
+
def allocate(az_name)
|
90
|
+
@allocated_ips[az_name] += 1
|
91
|
+
end
|
92
|
+
|
93
|
+
def sort_by_least_allocated_ips(az_names)
|
94
|
+
az_names.sort_by do |az_name|
|
95
|
+
@allocated_ips[az_name]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class PreviousAssignment
|
101
|
+
def initialize(network_to_static_ips)
|
102
|
+
@previous_assignment = Hash.new {|h,k| h[k] = 0 }
|
103
|
+
network_to_static_ips.each do |previous_assignment_ip|
|
104
|
+
@previous_assignment[previous_assignment_ip.az_names.first] += 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_same_distribution?(static_ips_to_azs)
|
109
|
+
@previous_assignment.each do |az_name, required_number_of_ips_in_az|
|
110
|
+
ips_in_az = static_ips_to_azs.select { |static_ip_to_azs| static_ip_to_azs.az_names.include?(az_name) }
|
111
|
+
if ips_in_az.size < required_number_of_ips_in_az
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Director
|
3
|
+
module DeploymentPlan
|
4
|
+
module PlacementPlanner
|
5
|
+
class IndexAssigner
|
6
|
+
def initialize(deployment_model)
|
7
|
+
@deployment_model = deployment_model
|
8
|
+
end
|
9
|
+
|
10
|
+
def assign_index(job_name, existing_instance_model=nil)
|
11
|
+
if existing_instance_model && existing_instance_model.job == job_name
|
12
|
+
return existing_instance_model.index
|
13
|
+
end
|
14
|
+
|
15
|
+
sorted_indexes = Models::Instance.filter(job: job_name, deployment: @deployment_model).sort_by(&:index).map(&:index)
|
16
|
+
if sorted_indexes.empty?
|
17
|
+
0
|
18
|
+
else
|
19
|
+
find_unused_index(sorted_indexes)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_unused_index(sorted_indexes)
|
24
|
+
sorted_indexes.unshift(-1)
|
25
|
+
next_indexes = sorted_indexes.map { |i| i + 1 }
|
26
|
+
(next_indexes - sorted_indexes).min
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Director
|
3
|
+
module DeploymentPlan
|
4
|
+
module PlacementPlanner
|
5
|
+
class NetworksToStaticIps
|
6
|
+
extend Bosh::Director::IpUtil
|
7
|
+
include Bosh::Director::IpUtil
|
8
|
+
|
9
|
+
def self.create(job_networks, desired_azs, job_name)
|
10
|
+
networks_to_static_ips = {}
|
11
|
+
|
12
|
+
desired_az_names = desired_azs.nil? ? [nil] : desired_azs.to_a.map(&:name)
|
13
|
+
|
14
|
+
job_networks.each do |job_network|
|
15
|
+
next unless job_network.static?
|
16
|
+
subnets = job_network.deployment_network.subnets
|
17
|
+
|
18
|
+
job_network.static_ips.each do |static_ip|
|
19
|
+
subnet_for_ip = subnets.find { |subnet| subnet.static_ips.include?(static_ip) }
|
20
|
+
if subnet_for_ip.nil?
|
21
|
+
raise JobNetworkInstanceIpMismatch,
|
22
|
+
"Job '#{job_name}' with network '#{job_network.name}' declares static ip '#{format_ip(static_ip)}', " +
|
23
|
+
"which belongs to no subnet"
|
24
|
+
end
|
25
|
+
az_names = subnet_for_ip.availability_zone_names.nil? ? [nil] : subnet_for_ip.availability_zone_names
|
26
|
+
filtered_az_names = az_names.select { |static_ip_az_name| desired_az_names.include?(static_ip_az_name) }.uniq
|
27
|
+
networks_to_static_ips[job_network.name] ||= []
|
28
|
+
networks_to_static_ips[job_network.name] << StaticIpToAzs.new(static_ip, filtered_az_names)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
new(networks_to_static_ips, job_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(networks_to_static_ips, job_name)
|
36
|
+
@networks_to_static_ips = networks_to_static_ips
|
37
|
+
@job_name = job_name
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate_azs_are_declared_in_job_and_subnets(desired_azs)
|
41
|
+
if desired_azs.nil? &&
|
42
|
+
@networks_to_static_ips.any? do |_, static_ips_to_az|
|
43
|
+
static_ips_to_az.any? { |static_ip_to_az| !static_ip_to_az.az_names.any?(&:nil?) }
|
44
|
+
end
|
45
|
+
|
46
|
+
raise JobInvalidAvailabilityZone,
|
47
|
+
"Job '#{@job_name}' subnets declare availability zones and the job does not"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_ips_are_in_desired_azs(desired_azs)
|
52
|
+
return if desired_azs.to_a.empty?
|
53
|
+
|
54
|
+
desired_az_names = desired_azs.to_a.map(&:name)
|
55
|
+
@networks_to_static_ips.each do |_, static_ips_to_az|
|
56
|
+
non_desired_ip_to_az = static_ips_to_az.find do |static_ip_to_az|
|
57
|
+
!(desired_az_names & static_ip_to_az.az_names).any?
|
58
|
+
end
|
59
|
+
|
60
|
+
if non_desired_ip_to_az
|
61
|
+
raise JobStaticIpsFromInvalidAvailabilityZone,
|
62
|
+
"Job '#{@job_name}' declares static ip '#{format_ip(non_desired_ip_to_az.ip)}' which does not belong to any of the job's availability zones."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def azs_to_networks
|
68
|
+
result = {}
|
69
|
+
@networks_to_static_ips.each do |network_name, static_ips_to_azs|
|
70
|
+
static_ips_to_azs.each do |static_ip_to_azs|
|
71
|
+
static_ip_to_azs.az_names.each do |az_name|
|
72
|
+
result[az_name][network_name] ||= []
|
73
|
+
result[az_name][network_name] << static_ip_to_azs.ip
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def distribute_evenly_per_zone
|
80
|
+
best_combination = BruteForceIpAllocation.new(@networks_to_static_ips).find_best_combination
|
81
|
+
if best_combination.nil?
|
82
|
+
raise JobNetworkInstanceIpMismatch, "Failed to evenly distribute static IPs between zones for job '#{@job_name}'"
|
83
|
+
end
|
84
|
+
@networks_to_static_ips = best_combination
|
85
|
+
end
|
86
|
+
|
87
|
+
def next_ip_for_network(network)
|
88
|
+
unclaimed_networks_to_static_ips[network.name].first
|
89
|
+
end
|
90
|
+
|
91
|
+
def claim_in_az(ip, az_name)
|
92
|
+
@networks_to_static_ips.each do |_, static_ips_to_azs|
|
93
|
+
static_ips_to_azs.each do |static_ip_to_azs|
|
94
|
+
if static_ip_to_azs.ip == ip
|
95
|
+
static_ip_to_azs.claimed = true
|
96
|
+
static_ip_to_azs.az_names = [az_name]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete(ip)
|
103
|
+
@networks_to_static_ips.each do |_, static_ip_to_azs|
|
104
|
+
static_ip_to_azs.delete_if { |static_ip_to_az| static_ip_to_az.ip == ip }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def find_by_network_and_ip(network, ip)
|
109
|
+
unclaimed_networks_to_static_ips[network.name].find { |static_ip_to_azs| static_ip_to_azs.ip == ip }
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_by_network_and_az(network, az_name)
|
113
|
+
unclaimed_networks_to_static_ips[network.name].find { |static_ip_to_azs| static_ip_to_azs.az_names.include?(az_name) }
|
114
|
+
end
|
115
|
+
|
116
|
+
def unclaimed_networks_to_static_ips
|
117
|
+
Hash[@networks_to_static_ips.map { |network_name, static_ips_to_azs| [network_name, static_ips_to_azs.reject(&:claimed)] }]
|
118
|
+
end
|
119
|
+
|
120
|
+
class StaticIpToAzs < Struct.new(:ip, :az_names, :claimed); end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|