bosh-director 1.5.0.pre.1113
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.
- data/CHANGELOG +34 -0
- data/bin/bosh-director +36 -0
- data/bin/bosh-director-console +84 -0
- data/bin/bosh-director-drain-workers +42 -0
- data/bin/bosh-director-migrate +58 -0
- data/bin/bosh-director-scheduler +27 -0
- data/bin/bosh-director-worker +76 -0
- data/db/migrations/README +1 -0
- data/db/migrations/director/20110209010747_initial.rb +118 -0
- data/db/migrations/director/20110406055800_add_task_user.rb +9 -0
- data/db/migrations/director/20110518225809_remove_cid_constrain.rb +13 -0
- data/db/migrations/director/20110617211923_add_deployments_release_versions.rb +32 -0
- data/db/migrations/director/20110622212607_add_task_checkpoint_timestamp.rb +9 -0
- data/db/migrations/director/20110628023039_add_state_to_instances.rb +21 -0
- data/db/migrations/director/20110709012332_add_disk_size_to_instances.rb +9 -0
- data/db/migrations/director/20110906183441_add_log_bundles.rb +11 -0
- data/db/migrations/director/20110907194830_add_logs_json_to_templates.rb +9 -0
- data/db/migrations/director/20110915205610_add_persistent_disks.rb +51 -0
- data/db/migrations/director/20111005180929_add_properties.rb +14 -0
- data/db/migrations/director/20111110024617_add_deployment_problems.rb +24 -0
- data/db/migrations/director/20111216214145_recreate_support_for_vms.rb +9 -0
- data/db/migrations/director/20120102084027_add_credentials_to_vms.rb +7 -0
- data/db/migrations/director/20120427235217_allow_multiple_releases_per_deployment.rb +36 -0
- data/db/migrations/director/20120524175805_add_task_type.rb +44 -0
- data/db/migrations/director/20120614001930_delete_redundant_deployment_release_relation.rb +34 -0
- data/db/migrations/director/20120822004528_add_fingerprint_to_templates_and_packages.rb +17 -0
- data/db/migrations/director/20120830191244_add_properties_to_templates.rb +9 -0
- data/db/migrations/director/20121106190739_persist_vm_env.rb +9 -0
- data/db/migrations/director/20130222232131_add_sha1_to_stemcells.rb +9 -0
- data/db/migrations/director/20130312211407_add_commit_hash_to_release_versions.rb +19 -0
- data/db/migrations/director/20130409235338_snapshot.rb +15 -0
- data/db/migrations/director/20130530164918_add_paused_flag_to_instance.rb +14 -0
- data/db/migrations/director/20130531172604_add_director_attributes.rb +13 -0
- data/db/migrations/dns/20120123234908_initial.rb +27 -0
- data/lib/bosh/director.rb +133 -0
- data/lib/bosh/director/agent_client.rb +78 -0
- data/lib/bosh/director/api.rb +29 -0
- data/lib/bosh/director/api/api_helper.rb +81 -0
- data/lib/bosh/director/api/backup_manager.rb +15 -0
- data/lib/bosh/director/api/controller.rb +639 -0
- data/lib/bosh/director/api/controller_helpers.rb +34 -0
- data/lib/bosh/director/api/deployment_lookup.rb +13 -0
- data/lib/bosh/director/api/deployment_manager.rb +60 -0
- data/lib/bosh/director/api/http_constants.rb +16 -0
- data/lib/bosh/director/api/instance_lookup.rb +44 -0
- data/lib/bosh/director/api/instance_manager.rb +63 -0
- data/lib/bosh/director/api/problem_manager.rb +40 -0
- data/lib/bosh/director/api/property_manager.rb +69 -0
- data/lib/bosh/director/api/release_manager.rb +59 -0
- data/lib/bosh/director/api/resource_manager.rb +69 -0
- data/lib/bosh/director/api/resurrector_manager.rb +15 -0
- data/lib/bosh/director/api/snapshot_manager.rb +94 -0
- data/lib/bosh/director/api/stemcell_manager.rb +50 -0
- data/lib/bosh/director/api/task_helper.rb +46 -0
- data/lib/bosh/director/api/task_manager.rb +64 -0
- data/lib/bosh/director/api/user_manager.rb +72 -0
- data/lib/bosh/director/api/vm_state_manager.rb +11 -0
- data/lib/bosh/director/app.rb +35 -0
- data/lib/bosh/director/blob_util.rb +87 -0
- data/lib/bosh/director/blobstores.rb +29 -0
- data/lib/bosh/director/client.rb +156 -0
- data/lib/bosh/director/cloudcheck_helper.rb +204 -0
- data/lib/bosh/director/compile_task.rb +157 -0
- data/lib/bosh/director/config.rb +370 -0
- data/lib/bosh/director/configuration_hasher.rb +114 -0
- data/lib/bosh/director/cycle_helper.rb +36 -0
- data/lib/bosh/director/db_backup.rb +22 -0
- data/lib/bosh/director/db_backup/adapter.rb +3 -0
- data/lib/bosh/director/db_backup/adapter/mysql2.rb +27 -0
- data/lib/bosh/director/db_backup/adapter/postgres.rb +36 -0
- data/lib/bosh/director/db_backup/adapter/sqlite.rb +17 -0
- data/lib/bosh/director/db_backup/error.rb +10 -0
- data/lib/bosh/director/deployment_plan.rb +26 -0
- data/lib/bosh/director/deployment_plan/assembler.rb +430 -0
- data/lib/bosh/director/deployment_plan/compilation_config.rb +54 -0
- data/lib/bosh/director/deployment_plan/compiled_package.rb +35 -0
- data/lib/bosh/director/deployment_plan/dynamic_network.rb +91 -0
- data/lib/bosh/director/deployment_plan/idle_vm.rb +109 -0
- data/lib/bosh/director/deployment_plan/instance.rb +413 -0
- data/lib/bosh/director/deployment_plan/job.rb +470 -0
- data/lib/bosh/director/deployment_plan/manual_network.rb +137 -0
- data/lib/bosh/director/deployment_plan/network.rb +74 -0
- data/lib/bosh/director/deployment_plan/network_subnet.rb +167 -0
- data/lib/bosh/director/deployment_plan/planner.rb +288 -0
- data/lib/bosh/director/deployment_plan/preparer.rb +52 -0
- data/lib/bosh/director/deployment_plan/release.rb +126 -0
- data/lib/bosh/director/deployment_plan/resource_pool.rb +143 -0
- data/lib/bosh/director/deployment_plan/resource_pools.rb +68 -0
- data/lib/bosh/director/deployment_plan/stemcell.rb +56 -0
- data/lib/bosh/director/deployment_plan/template.rb +94 -0
- data/lib/bosh/director/deployment_plan/update_config.rb +80 -0
- data/lib/bosh/director/deployment_plan/updater.rb +55 -0
- data/lib/bosh/director/deployment_plan/vip_network.rb +79 -0
- data/lib/bosh/director/dns_helper.rb +204 -0
- data/lib/bosh/director/download_helper.rb +44 -0
- data/lib/bosh/director/duration.rb +36 -0
- data/lib/bosh/director/encryption_helper.rb +10 -0
- data/lib/bosh/director/errors.rb +198 -0
- data/lib/bosh/director/event_log.rb +136 -0
- data/lib/bosh/director/ext.rb +64 -0
- data/lib/bosh/director/hash_string_vals.rb +13 -0
- data/lib/bosh/director/instance_deleter.rb +109 -0
- data/lib/bosh/director/instance_updater.rb +506 -0
- data/lib/bosh/director/ip_util.rb +67 -0
- data/lib/bosh/director/job_queue.rb +16 -0
- data/lib/bosh/director/job_runner.rb +162 -0
- data/lib/bosh/director/job_updater.rb +121 -0
- data/lib/bosh/director/jobs/backup.rb +86 -0
- data/lib/bosh/director/jobs/base_job.rb +66 -0
- data/lib/bosh/director/jobs/cloud_check/apply_resolutions.rb +46 -0
- data/lib/bosh/director/jobs/cloud_check/scan.rb +38 -0
- data/lib/bosh/director/jobs/cloud_check/scan_and_fix.rb +73 -0
- data/lib/bosh/director/jobs/create_snapshot.rb +23 -0
- data/lib/bosh/director/jobs/delete_deployment.rb +183 -0
- data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +34 -0
- data/lib/bosh/director/jobs/delete_release.rb +219 -0
- data/lib/bosh/director/jobs/delete_snapshots.rb +23 -0
- data/lib/bosh/director/jobs/delete_stemcell.rb +102 -0
- data/lib/bosh/director/jobs/fetch_logs.rb +99 -0
- data/lib/bosh/director/jobs/scheduled_backup.rb +38 -0
- data/lib/bosh/director/jobs/snapshot_deployment.rb +61 -0
- data/lib/bosh/director/jobs/snapshot_deployments.rb +23 -0
- data/lib/bosh/director/jobs/snapshot_self.rb +43 -0
- data/lib/bosh/director/jobs/ssh.rb +59 -0
- data/lib/bosh/director/jobs/update_deployment.rb +110 -0
- data/lib/bosh/director/jobs/update_release.rb +672 -0
- data/lib/bosh/director/jobs/update_stemcell.rb +109 -0
- data/lib/bosh/director/jobs/vm_state.rb +89 -0
- data/lib/bosh/director/lock.rb +133 -0
- data/lib/bosh/director/lock_helper.rb +92 -0
- data/lib/bosh/director/models.rb +29 -0
- data/lib/bosh/director/models/compiled_package.rb +33 -0
- data/lib/bosh/director/models/deployment.rb +22 -0
- data/lib/bosh/director/models/deployment_problem.rb +49 -0
- data/lib/bosh/director/models/deployment_property.rb +21 -0
- data/lib/bosh/director/models/director_attribute.rb +9 -0
- data/lib/bosh/director/models/dns.rb +9 -0
- data/lib/bosh/director/models/dns/domain.rb +9 -0
- data/lib/bosh/director/models/dns/record.rb +7 -0
- data/lib/bosh/director/models/helpers/model_helper.rb +7 -0
- data/lib/bosh/director/models/instance.rb +28 -0
- data/lib/bosh/director/models/log_bundle.rb +10 -0
- data/lib/bosh/director/models/package.rb +30 -0
- data/lib/bosh/director/models/persistent_disk.rb +13 -0
- data/lib/bosh/director/models/release.rb +17 -0
- data/lib/bosh/director/models/release_version.rb +16 -0
- data/lib/bosh/director/models/snapshot.rb +13 -0
- data/lib/bosh/director/models/stemcell.rb +18 -0
- data/lib/bosh/director/models/task.rb +10 -0
- data/lib/bosh/director/models/template.rb +44 -0
- data/lib/bosh/director/models/user.rb +11 -0
- data/lib/bosh/director/models/vm.rb +42 -0
- data/lib/bosh/director/nats_rpc.rb +54 -0
- data/lib/bosh/director/network_reservation.rb +121 -0
- data/lib/bosh/director/next_rebase_version.rb +20 -0
- data/lib/bosh/director/package_compiler.rb +423 -0
- data/lib/bosh/director/problem_handlers/base.rb +153 -0
- data/lib/bosh/director/problem_handlers/inactive_disk.rb +112 -0
- data/lib/bosh/director/problem_handlers/invalid_problem.rb +28 -0
- data/lib/bosh/director/problem_handlers/missing_vm.rb +34 -0
- data/lib/bosh/director/problem_handlers/mount_info_mismatch.rb +62 -0
- data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +64 -0
- data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +85 -0
- data/lib/bosh/director/problem_handlers/unresponsive_agent.rb +78 -0
- data/lib/bosh/director/problem_resolver.rb +103 -0
- data/lib/bosh/director/problem_scanner.rb +268 -0
- data/lib/bosh/director/resource_pool_updater.rb +216 -0
- data/lib/bosh/director/scheduler.rb +57 -0
- data/lib/bosh/director/sequel.rb +13 -0
- data/lib/bosh/director/tar_gzipper.rb +47 -0
- data/lib/bosh/director/task_result_file.rb +19 -0
- data/lib/bosh/director/thread_pool.rb +8 -0
- data/lib/bosh/director/validation_helper.rb +55 -0
- data/lib/bosh/director/version.rb +7 -0
- data/lib/bosh/director/vm_creator.rb +80 -0
- data/lib/bosh/director/vm_data.rb +63 -0
- data/lib/bosh/director/vm_metadata_updater.rb +29 -0
- data/lib/bosh/director/vm_reuser.rb +63 -0
- data/lib/cloud/dummy.rb +149 -0
- metadata +664 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director::CycleHelper
|
|
4
|
+
|
|
5
|
+
def self.check_for_cycle(vertices, options = {}, &block)
|
|
6
|
+
result = {}
|
|
7
|
+
result[:connected_vertices] = {} if options[:connected_vertices]
|
|
8
|
+
vertices.each do |vertex|
|
|
9
|
+
path = {}
|
|
10
|
+
connected_vertices = options[:connected_vertices] ? Set.new : nil
|
|
11
|
+
check_for_cycle_helper(path, vertices, vertex, connected_vertices, &block)
|
|
12
|
+
result[:connected_vertices][vertex] = connected_vertices.to_a if connected_vertices
|
|
13
|
+
end
|
|
14
|
+
result
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.check_for_cycle_helper(path, valid_vertices, vertex, connected_vertices, &block)
|
|
18
|
+
path[vertex] = path.size + 1
|
|
19
|
+
connected_vertices << vertex if connected_vertices && path.size > 1
|
|
20
|
+
edges = block.call(vertex)
|
|
21
|
+
if edges
|
|
22
|
+
edges.each do |edge|
|
|
23
|
+
raise "Invalid edge: #{edge}" unless valid_vertices.include?(edge)
|
|
24
|
+
if path.include?(edge)
|
|
25
|
+
vertex_path = []
|
|
26
|
+
path = path.invert
|
|
27
|
+
path.size.times { |index| vertex_path << path[index + 1] }
|
|
28
|
+
raise "Cycle: #{vertex_path.join("=>")}=>#{edge}"
|
|
29
|
+
end
|
|
30
|
+
check_for_cycle_helper(path, valid_vertices, edge, connected_vertices, &block)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
path.delete(vertex)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'bosh/director/db_backup/adapter'
|
|
2
|
+
require 'bosh/director/db_backup/error'
|
|
3
|
+
|
|
4
|
+
module Bosh
|
|
5
|
+
module Director
|
|
6
|
+
module DbBackup
|
|
7
|
+
def self.create(db_config)
|
|
8
|
+
adapter_to_module(db_config['adapter']).new(db_config)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.adapter_to_module(adapter)
|
|
12
|
+
adapter_module = adapter.capitalize
|
|
13
|
+
|
|
14
|
+
if Adapter.const_defined?(adapter_module)
|
|
15
|
+
Adapter.const_get adapter_module
|
|
16
|
+
else
|
|
17
|
+
raise Adapter::Error.new("backup for database adapter #{adapter} (module #{adapter_module}) is not implemented")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'open3'
|
|
2
|
+
|
|
3
|
+
module Bosh
|
|
4
|
+
module Director
|
|
5
|
+
module DbBackup
|
|
6
|
+
module Adapter
|
|
7
|
+
class Mysql2
|
|
8
|
+
def initialize(db_config)
|
|
9
|
+
@db_config = db_config
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def export(path)
|
|
13
|
+
out, err, status = Open3.capture3({'MYSQL_PWD' => @db_config.fetch('password')},
|
|
14
|
+
'mysqldump',
|
|
15
|
+
'--user', @db_config.fetch('user'),
|
|
16
|
+
'--host', @db_config.fetch('host'),
|
|
17
|
+
'--port', @db_config.fetch('port').to_s,
|
|
18
|
+
'--result-file', path,
|
|
19
|
+
@db_config.fetch('database'))
|
|
20
|
+
raise("mysqldump exited #{status.exitstatus}, output: '#{out}', error: '#{err}'") unless status.success?
|
|
21
|
+
path
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'open3'
|
|
2
|
+
|
|
3
|
+
module Bosh
|
|
4
|
+
module Director
|
|
5
|
+
module DbBackup
|
|
6
|
+
module Adapter
|
|
7
|
+
class Postgres
|
|
8
|
+
def initialize(db_config)
|
|
9
|
+
@db_config = db_config
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def export(path)
|
|
13
|
+
env = {}
|
|
14
|
+
env['PGPASSWORD'] = @db_config['password'] if @db_config.has_key?('password')
|
|
15
|
+
|
|
16
|
+
stdout, stderr, status = Open3.capture3(
|
|
17
|
+
env,
|
|
18
|
+
'pg_dump',
|
|
19
|
+
'--host', @db_config.fetch('host'),
|
|
20
|
+
'--port', @db_config.fetch('port').to_s,
|
|
21
|
+
'--username', @db_config.fetch('user'),
|
|
22
|
+
'--file', path,
|
|
23
|
+
@db_config.fetch('database'),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
unless status.success?
|
|
27
|
+
raise("pg_dump exited #{status.exitstatus}, output: '#{stdout}', error: '#{stderr}'")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
path
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Bosh
|
|
2
|
+
module Director
|
|
3
|
+
module DbBackup
|
|
4
|
+
module Adapter
|
|
5
|
+
class Sqlite
|
|
6
|
+
def initialize(db_config)
|
|
7
|
+
@db_config = db_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def export(output_path)
|
|
11
|
+
FileUtils.cp(@db_config.fetch('database'), output_path)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
module DeploymentPlan
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'bosh/director/deployment_plan/compilation_config'
|
|
9
|
+
require 'bosh/director/deployment_plan/idle_vm'
|
|
10
|
+
require 'bosh/director/deployment_plan/instance'
|
|
11
|
+
require 'bosh/director/deployment_plan/job'
|
|
12
|
+
require 'bosh/director/deployment_plan/network'
|
|
13
|
+
require 'bosh/director/deployment_plan/network_subnet'
|
|
14
|
+
require 'bosh/director/deployment_plan/compiled_package'
|
|
15
|
+
require 'bosh/director/deployment_plan/preparer'
|
|
16
|
+
require 'bosh/director/deployment_plan/resource_pools'
|
|
17
|
+
require 'bosh/director/deployment_plan/updater'
|
|
18
|
+
require 'bosh/director/deployment_plan/release'
|
|
19
|
+
require 'bosh/director/deployment_plan/resource_pool'
|
|
20
|
+
require 'bosh/director/deployment_plan/stemcell'
|
|
21
|
+
require 'bosh/director/deployment_plan/template'
|
|
22
|
+
require 'bosh/director/deployment_plan/update_config'
|
|
23
|
+
require 'bosh/director/deployment_plan/dynamic_network'
|
|
24
|
+
require 'bosh/director/deployment_plan/manual_network'
|
|
25
|
+
require 'bosh/director/deployment_plan/vip_network'
|
|
26
|
+
require 'bosh/director/deployment_plan/planner'
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
|
2
|
+
|
|
3
|
+
module Bosh::Director
|
|
4
|
+
# DeploymentPlan::Assembler is used to populate deployment plan with information
|
|
5
|
+
# about existing deployment and information from director DB
|
|
6
|
+
class DeploymentPlan::Assembler
|
|
7
|
+
include DnsHelper
|
|
8
|
+
include LockHelper
|
|
9
|
+
include IpUtil
|
|
10
|
+
|
|
11
|
+
# @param [DeploymentPlan] deployment_plan Deployment plan
|
|
12
|
+
def initialize(deployment_plan)
|
|
13
|
+
@deployment_plan = deployment_plan
|
|
14
|
+
@cloud = Config.cloud
|
|
15
|
+
@logger = Config.logger
|
|
16
|
+
@event_log = Config.event_log
|
|
17
|
+
@stemcell_manager = Api::StemcellManager.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Binds deployment DB record to a plan
|
|
21
|
+
# @return [void]
|
|
22
|
+
def bind_deployment
|
|
23
|
+
@deployment_plan.bind_model
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Binds release DB record(s) to a plan
|
|
27
|
+
# @return [void]
|
|
28
|
+
def bind_releases
|
|
29
|
+
with_release_locks(@deployment_plan) do
|
|
30
|
+
@deployment_plan.releases.each do |release|
|
|
31
|
+
release.bind_model
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Binds information about existing deployment to a plan
|
|
37
|
+
# @return [void]
|
|
38
|
+
def bind_existing_deployment
|
|
39
|
+
lock = Mutex.new
|
|
40
|
+
ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool|
|
|
41
|
+
@deployment_plan.vms.each do |vm|
|
|
42
|
+
pool.process do
|
|
43
|
+
with_thread_name("bind_existing_deployment(#{vm.agent_id})") do
|
|
44
|
+
bind_existing_vm(vm, lock)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Queries agent for VM state and updates deployment plan accordingly
|
|
52
|
+
# @param [Models::Vm] vm VM database model
|
|
53
|
+
# @param [Mutex] lock Lock to hold on to while updating deployment plan
|
|
54
|
+
def bind_existing_vm(vm, lock)
|
|
55
|
+
state = get_state(vm)
|
|
56
|
+
lock.synchronize do
|
|
57
|
+
@logger.debug("Processing network reservations")
|
|
58
|
+
reservations = get_network_reservations(state)
|
|
59
|
+
|
|
60
|
+
instance = vm.instance
|
|
61
|
+
if instance
|
|
62
|
+
bind_instance(instance, state, reservations)
|
|
63
|
+
else
|
|
64
|
+
@logger.debug("Binding resource pool VM")
|
|
65
|
+
resource_pool = @deployment_plan.resource_pool(
|
|
66
|
+
state["resource_pool"]["name"])
|
|
67
|
+
if resource_pool
|
|
68
|
+
bind_idle_vm(vm, resource_pool, state, reservations)
|
|
69
|
+
else
|
|
70
|
+
@logger.debug("Resource pool doesn't exist, marking for deletion")
|
|
71
|
+
@deployment_plan.delete_vm(vm)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
@logger.debug("Finished binding VM")
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Binds idle VM to a resource pool with a proper network reservation
|
|
79
|
+
# @param [Models::Vm] vm VM DB model
|
|
80
|
+
# @param [DeploymentPlan::ResourcePool] resource_pool Resource pool
|
|
81
|
+
# @param [Hash] state VM state according to its agent
|
|
82
|
+
# @param [Hash] reservations Network reservations
|
|
83
|
+
def bind_idle_vm(vm, resource_pool, state, reservations)
|
|
84
|
+
@logger.debug("Adding to resource pool")
|
|
85
|
+
idle_vm = resource_pool.add_idle_vm
|
|
86
|
+
idle_vm.vm = vm
|
|
87
|
+
idle_vm.current_state = state
|
|
88
|
+
|
|
89
|
+
reservation = reservations[resource_pool.network.name]
|
|
90
|
+
if reservation
|
|
91
|
+
if reservation.static?
|
|
92
|
+
@logger.debug("Releasing static network reservation for " +
|
|
93
|
+
"resource pool VM `#{vm.cid}'")
|
|
94
|
+
resource_pool.network.release(reservation)
|
|
95
|
+
else
|
|
96
|
+
idle_vm.use_reservation(reservation)
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
@logger.debug("No network reservation for VM `#{vm.cid}'")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @param [Models::Instance] instance_model Instance model
|
|
104
|
+
# @param [Hash] state Instance state according to agent
|
|
105
|
+
# @param [Hash] reservations Instance network reservations
|
|
106
|
+
def bind_instance(instance_model, state, reservations)
|
|
107
|
+
@logger.debug("Binding instance VM")
|
|
108
|
+
|
|
109
|
+
# Update instance, if we are renaming a job.
|
|
110
|
+
if @deployment_plan.rename_in_progress?
|
|
111
|
+
old_name = @deployment_plan.job_rename["old_name"]
|
|
112
|
+
new_name = @deployment_plan.job_rename["new_name"]
|
|
113
|
+
|
|
114
|
+
if instance_model.job == old_name
|
|
115
|
+
@logger.info("Renaming `#{old_name}' to `#{new_name}'")
|
|
116
|
+
instance_model.update(:job => new_name)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Does the job instance exist in the new deployment?
|
|
121
|
+
if (job = @deployment_plan.job(instance_model.job)) &&
|
|
122
|
+
(instance = job.instance(instance_model.index))
|
|
123
|
+
|
|
124
|
+
@logger.debug("Found job and instance spec")
|
|
125
|
+
instance.use_model(instance_model)
|
|
126
|
+
instance.current_state = state
|
|
127
|
+
|
|
128
|
+
@logger.debug("Copying network reservations")
|
|
129
|
+
instance.take_network_reservations(reservations)
|
|
130
|
+
|
|
131
|
+
@logger.debug("Copying resource pool reservation")
|
|
132
|
+
job.resource_pool.mark_active_vm
|
|
133
|
+
else
|
|
134
|
+
@logger.debug("Job/instance not found, marking for deletion")
|
|
135
|
+
@deployment_plan.delete_instance(instance_model)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def get_network_reservations(state)
|
|
140
|
+
reservations = {}
|
|
141
|
+
state["networks"].each do |name, network_config|
|
|
142
|
+
network = @deployment_plan.network(name)
|
|
143
|
+
if network
|
|
144
|
+
reservation = NetworkReservation.new(:ip => network_config["ip"])
|
|
145
|
+
network.reserve(reservation)
|
|
146
|
+
reservations[name] = reservation if reservation.reserved?
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
reservations
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def get_state(vm)
|
|
153
|
+
@logger.debug("Requesting current VM state for: #{vm.agent_id}")
|
|
154
|
+
agent = AgentClient.new(vm.agent_id)
|
|
155
|
+
state = agent.get_state
|
|
156
|
+
|
|
157
|
+
@logger.debug("Received VM state: #{state.pretty_inspect}")
|
|
158
|
+
verify_state(vm, state)
|
|
159
|
+
@logger.debug("Verified VM state")
|
|
160
|
+
|
|
161
|
+
migrate_legacy_state(vm, state)
|
|
162
|
+
state
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def verify_state(vm, state)
|
|
166
|
+
instance = vm.instance
|
|
167
|
+
|
|
168
|
+
if instance && instance.deployment_id != vm.deployment_id
|
|
169
|
+
# Both VM and instance should reference same deployment
|
|
170
|
+
raise VmInstanceOutOfSync,
|
|
171
|
+
"VM `#{vm.cid}' and instance " +
|
|
172
|
+
"`#{instance.job}/#{instance.index}' " +
|
|
173
|
+
"don't belong to the same deployment"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
unless state.kind_of?(Hash)
|
|
177
|
+
@logger.error("Invalid state for `#{vm.cid}': #{state.pretty_inspect}")
|
|
178
|
+
raise AgentInvalidStateFormat,
|
|
179
|
+
"VM `#{vm.cid}' returns invalid state: " +
|
|
180
|
+
"expected Hash, got #{state.class}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
actual_deployment_name = state["deployment"]
|
|
184
|
+
expected_deployment_name = @deployment_plan.name
|
|
185
|
+
|
|
186
|
+
if actual_deployment_name != expected_deployment_name
|
|
187
|
+
raise AgentWrongDeployment,
|
|
188
|
+
"VM `#{vm.cid}' is out of sync: " +
|
|
189
|
+
"expected to be a part of deployment " +
|
|
190
|
+
"`#{expected_deployment_name}' " +
|
|
191
|
+
"but is actually a part of deployment " +
|
|
192
|
+
"`#{actual_deployment_name}'"
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
actual_job = state["job"].is_a?(Hash) ? state["job"]["name"] : nil
|
|
196
|
+
actual_index = state["index"]
|
|
197
|
+
|
|
198
|
+
if instance.nil? && !actual_job.nil?
|
|
199
|
+
raise AgentUnexpectedJob,
|
|
200
|
+
"VM `#{vm.cid}' is out of sync: " +
|
|
201
|
+
"it reports itself as `#{actual_job}/#{actual_index}' but " +
|
|
202
|
+
"there is no instance reference in DB"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
if instance &&
|
|
206
|
+
(instance.job != actual_job || instance.index != actual_index)
|
|
207
|
+
# Check if we are resuming a previously unfinished rename
|
|
208
|
+
if actual_job == @deployment_plan.job_rename["old_name"] &&
|
|
209
|
+
instance.job == @deployment_plan.job_rename["new_name"] &&
|
|
210
|
+
instance.index == actual_index
|
|
211
|
+
|
|
212
|
+
# Rename already happened in the DB but then something happened
|
|
213
|
+
# and agent has never been updated.
|
|
214
|
+
unless @deployment_plan.job_rename["force"]
|
|
215
|
+
raise AgentRenameInProgress,
|
|
216
|
+
"Found a job `#{actual_job}' that seems to be " +
|
|
217
|
+
"in the middle of a rename to `#{instance.job}'. " +
|
|
218
|
+
"Run 'rename' again with '--force' to proceed."
|
|
219
|
+
end
|
|
220
|
+
else
|
|
221
|
+
raise AgentJobMismatch,
|
|
222
|
+
"VM `#{vm.cid}' is out of sync: " +
|
|
223
|
+
"it reports itself as `#{actual_job}/#{actual_index}' but " +
|
|
224
|
+
"according to DB it is `#{instance.job}/#{instance.index}'"
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def migrate_legacy_state(vm, state)
|
|
230
|
+
# Persisting apply spec for VMs that were introduced before we started
|
|
231
|
+
# persisting it on apply itself (this is for cloudcheck purposes only)
|
|
232
|
+
if vm.apply_spec.nil?
|
|
233
|
+
# The assumption is that apply_spec <=> VM state
|
|
234
|
+
vm.update(:apply_spec => state)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
instance = vm.instance
|
|
238
|
+
if instance
|
|
239
|
+
disk_size = state["persistent_disk"].to_i
|
|
240
|
+
persistent_disk = instance.persistent_disk
|
|
241
|
+
|
|
242
|
+
# This is to support legacy deployments where we did not have
|
|
243
|
+
# the disk_size specified.
|
|
244
|
+
if disk_size != 0 && persistent_disk && persistent_disk.size == 0
|
|
245
|
+
persistent_disk.update(:size => disk_size)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Takes a look at the current state of all resource pools in the deployment
|
|
251
|
+
# and schedules adding any new VMs if needed. VMs are NOT created at this
|
|
252
|
+
# stage, only data structures are being allocated. {ResourcePoolUpdater}
|
|
253
|
+
# will later perform actual changes based on this data.
|
|
254
|
+
# @return [void]
|
|
255
|
+
def bind_resource_pools
|
|
256
|
+
@deployment_plan.resource_pools.each do |resource_pool|
|
|
257
|
+
resource_pool.process_idle_vms
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Looks at every job instance in the deployment plan and binds it to the
|
|
262
|
+
# instance database model (idle VM is also created in the appropriate
|
|
263
|
+
# resource pool if necessary)
|
|
264
|
+
# @return [void]
|
|
265
|
+
def bind_unallocated_vms
|
|
266
|
+
@deployment_plan.jobs.each do |job|
|
|
267
|
+
job.instances.each do |instance|
|
|
268
|
+
instance.bind_unallocated_vm
|
|
269
|
+
# Now that we know every VM has been allocated and instance models are
|
|
270
|
+
# bound, we can sync the state.
|
|
271
|
+
instance.sync_state_with_db
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def bind_instance_networks
|
|
277
|
+
@deployment_plan.jobs.each do |job|
|
|
278
|
+
job.instances.each do |instance|
|
|
279
|
+
instance.network_reservations.each do |name, reservation|
|
|
280
|
+
unless reservation.reserved?
|
|
281
|
+
network = @deployment_plan.network(name)
|
|
282
|
+
network.reserve!(reservation, "`#{job.name}/#{instance.index}'")
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Binds template models for each release spec in the deployment plan
|
|
290
|
+
# @return [void]
|
|
291
|
+
def bind_templates
|
|
292
|
+
@deployment_plan.releases.each do |release|
|
|
293
|
+
release.bind_templates
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Binds properties for all templates in the deployment
|
|
298
|
+
# @return [void]
|
|
299
|
+
def bind_properties
|
|
300
|
+
@deployment_plan.jobs.each do |job|
|
|
301
|
+
job.bind_properties
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Binds stemcell model for each stemcell spec in each resource pool in
|
|
306
|
+
# the deployment plan
|
|
307
|
+
# @return [void]
|
|
308
|
+
def bind_stemcells
|
|
309
|
+
@deployment_plan.resource_pools.each do |resource_pool|
|
|
310
|
+
stemcell = resource_pool.stemcell
|
|
311
|
+
|
|
312
|
+
if stemcell.nil?
|
|
313
|
+
raise DirectorError,
|
|
314
|
+
"Stemcell not bound for resource pool `#{resource_pool.name}'"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
stemcell.bind_model
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Calculates configuration checksums for all jobs in this deployment plan
|
|
322
|
+
# @return [void]
|
|
323
|
+
def bind_configuration
|
|
324
|
+
@deployment_plan.jobs.each do |job|
|
|
325
|
+
ConfigurationHasher.new(job).hash
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def bind_dns
|
|
330
|
+
domain = Models::Dns::Domain.find_or_create(:name => dns_domain_name,
|
|
331
|
+
:type => "NATIVE")
|
|
332
|
+
@deployment_plan.dns_domain = domain
|
|
333
|
+
|
|
334
|
+
soa_record = Models::Dns::Record.find_or_create(:domain_id => domain.id,
|
|
335
|
+
:name => dns_domain_name,
|
|
336
|
+
:type => "SOA")
|
|
337
|
+
soa_record.content = SOA
|
|
338
|
+
soa_record.ttl = 300
|
|
339
|
+
soa_record.save
|
|
340
|
+
|
|
341
|
+
# add NS record
|
|
342
|
+
Models::Dns::Record.find_or_create(:domain_id => domain.id,
|
|
343
|
+
:name => dns_domain_name,
|
|
344
|
+
:type =>'NS', :ttl => TTL_4H,
|
|
345
|
+
:content => dns_ns_record)
|
|
346
|
+
# add A record for name server
|
|
347
|
+
Models::Dns::Record.find_or_create(:domain_id => domain.id,
|
|
348
|
+
:name => dns_ns_record,
|
|
349
|
+
:type =>'A', :ttl => TTL_4H,
|
|
350
|
+
:content => Config.dns["address"])
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def bind_instance_vms
|
|
354
|
+
unbound_instances = []
|
|
355
|
+
|
|
356
|
+
@deployment_plan.jobs.each do |job|
|
|
357
|
+
job.instances.each do |instance|
|
|
358
|
+
# Don't allocate resource pool VMs to instances in detached state
|
|
359
|
+
next if instance.state == "detached"
|
|
360
|
+
# Skip bound instances
|
|
361
|
+
next if instance.model.vm
|
|
362
|
+
unbound_instances << instance
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
return if unbound_instances.empty?
|
|
367
|
+
|
|
368
|
+
@event_log.begin_stage("Binding instance VMs", unbound_instances.size)
|
|
369
|
+
|
|
370
|
+
ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool|
|
|
371
|
+
unbound_instances.each do |instance|
|
|
372
|
+
pool.process do
|
|
373
|
+
bind_instance_vm(instance)
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# @param [DeploymentPlan::Instance]
|
|
380
|
+
def bind_instance_vm(instance)
|
|
381
|
+
job = instance.job
|
|
382
|
+
idle_vm = instance.idle_vm
|
|
383
|
+
|
|
384
|
+
instance.model.update(:vm => idle_vm.vm)
|
|
385
|
+
|
|
386
|
+
@event_log.track("#{job.name}/#{instance.index}") do
|
|
387
|
+
# Apply the assignment to the VM
|
|
388
|
+
state = idle_vm.current_state
|
|
389
|
+
state["job"] = job.spec
|
|
390
|
+
state["index"] = instance.index
|
|
391
|
+
state["release"] = job.release.spec
|
|
392
|
+
|
|
393
|
+
idle_vm.vm.update(:apply_spec => state)
|
|
394
|
+
|
|
395
|
+
agent = AgentClient.new(idle_vm.vm.agent_id)
|
|
396
|
+
agent.apply(state)
|
|
397
|
+
instance.current_state = state
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def delete_unneeded_vms
|
|
402
|
+
unneeded_vms = @deployment_plan.unneeded_vms
|
|
403
|
+
return if unneeded_vms.empty?
|
|
404
|
+
|
|
405
|
+
@event_log.begin_stage("Deleting unneeded VMs", unneeded_vms.size)
|
|
406
|
+
|
|
407
|
+
ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool|
|
|
408
|
+
unneeded_vms.each do |vm|
|
|
409
|
+
pool.process do
|
|
410
|
+
@event_log.track(vm.cid) do
|
|
411
|
+
@logger.info("Delete unneeded VM #{vm.cid}")
|
|
412
|
+
@cloud.delete_vm(vm.cid)
|
|
413
|
+
vm.destroy
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def delete_unneeded_instances
|
|
421
|
+
unneeded_instances = @deployment_plan.unneeded_instances
|
|
422
|
+
return if unneeded_instances.empty?
|
|
423
|
+
|
|
424
|
+
@event_log.begin_stage("Deleting unneeded instances",
|
|
425
|
+
unneeded_instances.size)
|
|
426
|
+
InstanceDeleter.new(@deployment_plan).delete_instances(unneeded_instances)
|
|
427
|
+
@logger.info("Deleted no longer needed instances")
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
end
|