bosh-director 1.5.0.pre.1113
Sign up to get free protection for your applications and to get access to all the features.
- 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
|