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,14 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
up do
|
3
|
+
alter_table :instances do
|
4
|
+
add_column :resurrection_paused, TrueClass
|
5
|
+
set_column_default :resurrection_paused, false
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
down do
|
10
|
+
alter_table :instances do
|
11
|
+
drop_column :resurrection_paused
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
Sequel.migration do
|
4
|
+
change do
|
5
|
+
create_table :domains do
|
6
|
+
primary_key :id
|
7
|
+
String :name, :size => 255, :null => false, :unique => true
|
8
|
+
String :master, :size => 128, :null => true, :default => nil
|
9
|
+
Integer :last_check, :null => true, :default => nil
|
10
|
+
String :type, :size => 6, :null => false
|
11
|
+
Integer :notified_serial, :null => true, :default => nil
|
12
|
+
String :account, :size=> 40, :null => true, :default => nil
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :records do
|
16
|
+
primary_key :id
|
17
|
+
String :name, :size => 255, :null => true, :default => nil, :index => true
|
18
|
+
String :type, :size => 10, :null => true, :default => nil
|
19
|
+
String :content, :size => 4098, :null => true, :default => nil
|
20
|
+
Integer :ttl, :null => true, :default => nil
|
21
|
+
Integer :prio, :null => true, :default => nil
|
22
|
+
Integer :change_date, :null => true, :default => nil
|
23
|
+
foreign_key :domain_id, :domains, :on_delete => :cascade, :null => true, :default => nil, :index => true
|
24
|
+
index [:name, :type]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh
|
4
|
+
module Director
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'digest/sha1'
|
9
|
+
require 'erb'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'forwardable'
|
12
|
+
require 'logger'
|
13
|
+
require 'monitor'
|
14
|
+
require 'optparse'
|
15
|
+
require 'ostruct'
|
16
|
+
require 'pathname'
|
17
|
+
require 'pp'
|
18
|
+
require 'thread'
|
19
|
+
require 'tmpdir'
|
20
|
+
require 'yaml'
|
21
|
+
require 'time'
|
22
|
+
require 'zlib'
|
23
|
+
|
24
|
+
require 'common/runs_commands'
|
25
|
+
require 'common/exec'
|
26
|
+
require 'common/properties'
|
27
|
+
|
28
|
+
require 'bcrypt'
|
29
|
+
require 'blobstore_client'
|
30
|
+
require 'eventmachine'
|
31
|
+
require 'netaddr'
|
32
|
+
require 'resque'
|
33
|
+
require 'sequel'
|
34
|
+
require 'sinatra/base'
|
35
|
+
require 'securerandom'
|
36
|
+
require 'yajl'
|
37
|
+
require 'nats/client'
|
38
|
+
require 'securerandom'
|
39
|
+
|
40
|
+
require 'common/thread_formatter'
|
41
|
+
require 'bosh/core/encryption_handler'
|
42
|
+
require 'bosh/director/api'
|
43
|
+
require 'bosh/director/dns_helper'
|
44
|
+
require 'bosh/director/errors'
|
45
|
+
require 'bosh/director/ext'
|
46
|
+
require 'bosh/director/ip_util'
|
47
|
+
require 'bosh/director/lock_helper'
|
48
|
+
require 'bosh/director/validation_helper'
|
49
|
+
require 'bosh/director/download_helper'
|
50
|
+
|
51
|
+
require 'bosh/director/version'
|
52
|
+
require 'bosh/director/next_rebase_version'
|
53
|
+
require 'bosh/director/config'
|
54
|
+
require 'bosh/director/event_log'
|
55
|
+
require 'bosh/director/task_result_file'
|
56
|
+
require 'bosh/director/blob_util'
|
57
|
+
|
58
|
+
require 'bosh/director/client'
|
59
|
+
require 'bosh/director/agent_client'
|
60
|
+
require 'cloud'
|
61
|
+
require 'bosh/director/compile_task'
|
62
|
+
require 'bosh/director/configuration_hasher'
|
63
|
+
require 'bosh/director/cycle_helper'
|
64
|
+
require 'bosh/director/encryption_helper'
|
65
|
+
require 'bosh/director/vm_creator'
|
66
|
+
require 'bosh/director/vm_metadata_updater'
|
67
|
+
require 'bosh/director/vm_data'
|
68
|
+
require 'bosh/director/vm_reuser'
|
69
|
+
require 'bosh/director/deployment_plan'
|
70
|
+
require 'bosh/director/deployment_plan/assembler'
|
71
|
+
require 'bosh/director/duration'
|
72
|
+
require 'bosh/director/hash_string_vals'
|
73
|
+
require 'bosh/director/instance_deleter'
|
74
|
+
require 'bosh/director/instance_updater'
|
75
|
+
require 'bosh/director/job_runner'
|
76
|
+
require 'bosh/director/job_updater'
|
77
|
+
require 'bosh/director/job_queue'
|
78
|
+
require 'bosh/director/tar_gzipper'
|
79
|
+
require 'bosh/director/lock'
|
80
|
+
require 'bosh/director/nats_rpc'
|
81
|
+
require 'bosh/director/network_reservation'
|
82
|
+
require 'bosh/director/package_compiler'
|
83
|
+
require 'bosh/director/problem_scanner'
|
84
|
+
require 'bosh/director/problem_resolver'
|
85
|
+
require 'bosh/director/resource_pool_updater'
|
86
|
+
require 'bosh/director/sequel'
|
87
|
+
require 'common/thread_pool'
|
88
|
+
|
89
|
+
require 'bosh/director/cloudcheck_helper'
|
90
|
+
require 'bosh/director/problem_handlers/base'
|
91
|
+
require 'bosh/director/problem_handlers/invalid_problem'
|
92
|
+
require 'bosh/director/problem_handlers/inactive_disk'
|
93
|
+
require 'bosh/director/problem_handlers/out_of_sync_vm'
|
94
|
+
require 'bosh/director/problem_handlers/unresponsive_agent'
|
95
|
+
require 'bosh/director/problem_handlers/unbound_instance_vm'
|
96
|
+
require 'bosh/director/problem_handlers/mount_info_mismatch'
|
97
|
+
require 'bosh/director/problem_handlers/missing_vm'
|
98
|
+
|
99
|
+
require 'bosh/director/jobs/base_job'
|
100
|
+
require 'bosh/director/jobs/backup'
|
101
|
+
require 'bosh/director/jobs/scheduled_backup'
|
102
|
+
require 'bosh/director/jobs/create_snapshot'
|
103
|
+
require 'bosh/director/jobs/snapshot_deployment'
|
104
|
+
require 'bosh/director/jobs/snapshot_deployments'
|
105
|
+
require 'bosh/director/jobs/snapshot_self'
|
106
|
+
require 'bosh/director/jobs/delete_deployment'
|
107
|
+
require 'bosh/director/jobs/delete_deployment_snapshots'
|
108
|
+
require 'bosh/director/jobs/delete_release'
|
109
|
+
require 'bosh/director/jobs/delete_snapshots'
|
110
|
+
require 'bosh/director/jobs/delete_stemcell'
|
111
|
+
require 'bosh/director/jobs/update_deployment'
|
112
|
+
require 'bosh/director/jobs/update_release'
|
113
|
+
require 'bosh/director/jobs/update_stemcell'
|
114
|
+
require 'bosh/director/jobs/fetch_logs'
|
115
|
+
require 'bosh/director/jobs/vm_state'
|
116
|
+
require 'bosh/director/jobs/cloud_check/scan'
|
117
|
+
require 'bosh/director/jobs/cloud_check/scan_and_fix'
|
118
|
+
require 'bosh/director/jobs/cloud_check/apply_resolutions'
|
119
|
+
require 'bosh/director/jobs/ssh'
|
120
|
+
|
121
|
+
require 'bosh/director/models/helpers/model_helper'
|
122
|
+
|
123
|
+
require 'bosh/director/db_backup'
|
124
|
+
require 'bosh/director/blobstores'
|
125
|
+
require 'bosh/director/app'
|
126
|
+
|
127
|
+
module Bosh::Director
|
128
|
+
autoload :Models, 'bosh/director/models' # Defining model classes relies on a database connection
|
129
|
+
end
|
130
|
+
|
131
|
+
require 'bosh/director/thread_pool'
|
132
|
+
require 'bosh/director/api/controller_helpers'
|
133
|
+
require 'bosh/director/api/controller'
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Director
|
4
|
+
class AgentClient < Client
|
5
|
+
|
6
|
+
DEFAULT_POLL_INTERVAL = 1.0
|
7
|
+
|
8
|
+
def initialize(id, options = {})
|
9
|
+
# Retry 'get_state' and 'get_task' in case of timeout errors
|
10
|
+
defaults = {
|
11
|
+
:retry_methods => { :get_state => 2, :get_task => 2}
|
12
|
+
}
|
13
|
+
|
14
|
+
credentials = Bosh::Director::Models::Vm.find(:agent_id => id).credentials
|
15
|
+
if credentials
|
16
|
+
defaults.merge!({
|
17
|
+
:credentials => credentials
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
super("agent", id, defaults.merge(options))
|
22
|
+
end
|
23
|
+
|
24
|
+
# This converts the old agent response format to the new. This can be taken
|
25
|
+
# out once the agents never reply with the old message format.
|
26
|
+
# The old message format is just to pass the return object as JSON. That
|
27
|
+
# means it could be any type -- array, hash, string, int, etc.
|
28
|
+
# The new format is:
|
29
|
+
# {"state"=>"task_state", "value"=><task_return_object>,
|
30
|
+
# "agent_task_id"=>123}
|
31
|
+
# This is a class method to make testing easier.
|
32
|
+
# @param [Object] msg The agent message to convert to the new format.
|
33
|
+
# @return [Hash] The message in the new message format.
|
34
|
+
def self.convert_old_message_to_new(msg)
|
35
|
+
if msg && msg.is_a?(Hash)
|
36
|
+
if !msg.has_key?("value")
|
37
|
+
# There's no value but there is state and agent_task_id.
|
38
|
+
# Just leave it.
|
39
|
+
if msg.has_key?("state") && msg.has_key?("agent_task_id")
|
40
|
+
return msg
|
41
|
+
end
|
42
|
+
# There's no value and either one or both of state/agent_task_id don't
|
43
|
+
# exist. Assume that the whole message response was meant to be the
|
44
|
+
# value.
|
45
|
+
return {"value" => msg,
|
46
|
+
"state" => msg["state"] || "done",
|
47
|
+
"agent_task_id" => msg["agent_task_id"] || nil}
|
48
|
+
elsif !msg.has_key?("state")
|
49
|
+
# The message has a value section but no "state". Mark state as
|
50
|
+
# done.
|
51
|
+
return {"value" => msg["value"],
|
52
|
+
"state" => "done",
|
53
|
+
"agent_task_id" => msg["agent_task_id"] || nil}
|
54
|
+
else
|
55
|
+
# The message was good from the start!
|
56
|
+
return msg
|
57
|
+
end
|
58
|
+
end
|
59
|
+
# If the message was anything other than a hash (float, int, string,
|
60
|
+
# array, etc.) then we want to just make that be the "value".
|
61
|
+
{"state" => "done", "value" => msg, "agent_task_id" => nil}
|
62
|
+
end
|
63
|
+
|
64
|
+
[:apply, :compile_package, :drain, :fetch_logs, :migrate_disk, :mount_disk,
|
65
|
+
:stop, :unmount_disk].each do |method|
|
66
|
+
define_method (method) do |*args|
|
67
|
+
task = AgentClient.convert_old_message_to_new(super(*args))
|
68
|
+
while task["state"] == "running"
|
69
|
+
sleep(DEFAULT_POLL_INTERVAL)
|
70
|
+
task = AgentClient.convert_old_message_to_new(
|
71
|
+
get_task(task["agent_task_id"]))
|
72
|
+
end
|
73
|
+
task["value"]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Director
|
4
|
+
module Api
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'bosh/director/api/http_constants'
|
9
|
+
|
10
|
+
require 'bosh/director/api/api_helper'
|
11
|
+
require 'bosh/director/api/task_helper'
|
12
|
+
|
13
|
+
require 'bosh/director/api/backup_manager'
|
14
|
+
require 'bosh/director/api/deployment_manager'
|
15
|
+
require 'bosh/director/api/instance_manager'
|
16
|
+
require 'bosh/director/api/problem_manager'
|
17
|
+
require 'bosh/director/api/property_manager'
|
18
|
+
require 'bosh/director/api/release_manager'
|
19
|
+
require 'bosh/director/api/resource_manager'
|
20
|
+
require 'bosh/director/api/snapshot_manager'
|
21
|
+
require 'bosh/director/api/stemcell_manager'
|
22
|
+
require 'bosh/director/api/task_manager'
|
23
|
+
require 'bosh/director/api/user_manager'
|
24
|
+
require 'bosh/director/api/vm_state_manager'
|
25
|
+
require 'bosh/director/api/backup_manager'
|
26
|
+
require 'bosh/director/api/resurrector_manager'
|
27
|
+
|
28
|
+
require 'bosh/director/api/instance_lookup'
|
29
|
+
require 'bosh/director/api/deployment_lookup'
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
require 'sys/filesystem'
|
3
|
+
include Sys
|
4
|
+
|
5
|
+
module Bosh::Director
|
6
|
+
module Api
|
7
|
+
module ApiHelper
|
8
|
+
READ_CHUNK_SIZE = 16384
|
9
|
+
|
10
|
+
class DisposableFile < ::Rack::File
|
11
|
+
def close
|
12
|
+
FileUtils.rm_rf(self.path) if File.exists?(self.path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Adapted from Sinatra::Base#send_file. There is one difference:
|
17
|
+
# it uses DisposableFile instead of Rack::File.
|
18
|
+
# DisposableFile gets removed on "close" call. This is primarily
|
19
|
+
# meant to serve temporary files fetched from the blobstore.
|
20
|
+
# We CANNOT use a Sinatra after filter, as the filter is called before
|
21
|
+
# the contents of the file is sent to the client.
|
22
|
+
def send_disposable_file(path, opts = {})
|
23
|
+
if opts[:type] || !response['Content-Type']
|
24
|
+
content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
|
25
|
+
end
|
26
|
+
|
27
|
+
disposition = opts[:disposition]
|
28
|
+
filename = opts[:filename]
|
29
|
+
disposition = 'attachment' if disposition.nil? && filename
|
30
|
+
filename = path if filename.nil?
|
31
|
+
attachment(filename, disposition) if disposition
|
32
|
+
|
33
|
+
last_modified opts[:last_modified] if opts[:last_modified]
|
34
|
+
|
35
|
+
file = DisposableFile.new nil
|
36
|
+
file.path = path
|
37
|
+
result = file.serving env
|
38
|
+
result[1].each { |k,v| headers[k] ||= v }
|
39
|
+
headers['Content-Length'] = result[1]['Content-Length']
|
40
|
+
halt opts[:status] || result[0], result[2]
|
41
|
+
rescue Errno::ENOENT
|
42
|
+
not_found
|
43
|
+
end
|
44
|
+
|
45
|
+
def json_encode(payload)
|
46
|
+
Yajl::Encoder.encode(payload)
|
47
|
+
end
|
48
|
+
|
49
|
+
def json_decode(payload)
|
50
|
+
Yajl::Parser.parse(payload)
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_task
|
54
|
+
task = yield
|
55
|
+
unless task.kind_of?(Models::Task)
|
56
|
+
raise "Block didn't return Task object"
|
57
|
+
end
|
58
|
+
redirect "/tasks/#{task.id}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_available_disk_space(dir, size)
|
62
|
+
begin
|
63
|
+
stat = Sys::Filesystem.stat(dir)
|
64
|
+
available_space = stat.block_size * stat.blocks_available
|
65
|
+
available_space > size ? true : false
|
66
|
+
rescue
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def write_file(path, stream, chunk_size = READ_CHUNK_SIZE)
|
72
|
+
buffer = ""
|
73
|
+
File.open(path, "w") do |file|
|
74
|
+
file.write(buffer) until stream.read(chunk_size, buffer).nil?
|
75
|
+
end
|
76
|
+
rescue SystemCallError => e
|
77
|
+
raise SystemError, e.message
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bosh::Director
|
2
|
+
module Api
|
3
|
+
class BackupManager
|
4
|
+
attr_accessor :destination_path
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@destination_path = '/var/vcap/store/director/backup.tgz'
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_backup(user)
|
11
|
+
JobQueue.new.enqueue(user, Jobs::Backup, 'bosh backup', [destination_path])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,639 @@
|
|
1
|
+
module Bosh::Director
|
2
|
+
module Api
|
3
|
+
class Controller < Sinatra::Base
|
4
|
+
PUBLIC_URLS = %w(/info)
|
5
|
+
|
6
|
+
include ApiHelper
|
7
|
+
include Http
|
8
|
+
include DnsHelper
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
@deployment_manager = DeploymentManager.new
|
13
|
+
@backup_manager = BackupManager.new
|
14
|
+
@instance_manager = InstanceManager.new
|
15
|
+
@resurrector_manager = ResurrectorManager.new
|
16
|
+
@problem_manager = ProblemManager.new
|
17
|
+
@property_manager = PropertyManager.new
|
18
|
+
@resource_manager = ResourceManager.new
|
19
|
+
@release_manager = ReleaseManager.new
|
20
|
+
@snapshot_manager = SnapshotManager.new
|
21
|
+
@stemcell_manager = StemcellManager.new
|
22
|
+
@task_manager = TaskManager.new
|
23
|
+
@user_manager = UserManager.new
|
24
|
+
@vm_state_manager = VmStateManager.new
|
25
|
+
@logger = Config.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
mime_type :tgz, 'application/x-compressed'
|
29
|
+
|
30
|
+
def self.consumes(*types)
|
31
|
+
types = Set.new(types)
|
32
|
+
types.map! { |t| mime_type(t) }
|
33
|
+
|
34
|
+
condition do
|
35
|
+
types.include?(request.content_type)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def authenticate(user, password)
|
40
|
+
if @user_manager.authenticate(user, password)
|
41
|
+
@user = user
|
42
|
+
true
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
helpers ControllerHelpers
|
49
|
+
|
50
|
+
before do
|
51
|
+
auth_provided = %w(HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION).detect do |key|
|
52
|
+
request.env.has_key?(key)
|
53
|
+
end
|
54
|
+
|
55
|
+
protected! if auth_provided || !PUBLIC_URLS.include?(request.path_info)
|
56
|
+
end
|
57
|
+
|
58
|
+
after { headers('Date' => Time.now.rfc822) } # As thin doesn't inject date
|
59
|
+
|
60
|
+
configure do
|
61
|
+
set(:show_exceptions, false)
|
62
|
+
set(:raise_errors, false)
|
63
|
+
set(:dump_errors, false)
|
64
|
+
end
|
65
|
+
|
66
|
+
error do
|
67
|
+
exception = request.env['sinatra.error']
|
68
|
+
if exception.kind_of?(DirectorError)
|
69
|
+
@logger.debug('Request failed, ' +
|
70
|
+
"response code: #{exception.response_code}, " +
|
71
|
+
"error code: #{exception.error_code}, " +
|
72
|
+
"error message: #{exception.message}")
|
73
|
+
status(exception.response_code)
|
74
|
+
error_payload = {
|
75
|
+
'code' => exception.error_code,
|
76
|
+
'description' => exception.message
|
77
|
+
}
|
78
|
+
json_encode(error_payload)
|
79
|
+
else
|
80
|
+
msg = ["#{exception.class} - #{exception.message}:"]
|
81
|
+
msg.concat(exception.backtrace)
|
82
|
+
@logger.error(msg.join("\n"))
|
83
|
+
status(500)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
post '/users', :consumes => [:json] do
|
88
|
+
user = @user_manager.get_user_from_request(request)
|
89
|
+
@user_manager.create_user(user)
|
90
|
+
status(204)
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
put '/users/:username', :consumes => [:json] do
|
95
|
+
user = @user_manager.get_user_from_request(request)
|
96
|
+
if user.username != params[:username]
|
97
|
+
raise UserImmutableUsername, 'The username is immutable'
|
98
|
+
end
|
99
|
+
@user_manager.update_user(user)
|
100
|
+
status(204)
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
104
|
+
delete '/users/:username' do
|
105
|
+
@user_manager.delete_user(params[:username])
|
106
|
+
status(204)
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
post '/packages/matches', :consumes => :yaml do
|
111
|
+
manifest = Psych.load(request.body)
|
112
|
+
unless manifest.is_a?(Hash) && manifest['packages'].is_a?(Array)
|
113
|
+
raise BadManifest, "Manifest doesn't have a usable packages section"
|
114
|
+
end
|
115
|
+
|
116
|
+
fp_list = []
|
117
|
+
sha1_list = []
|
118
|
+
|
119
|
+
manifest['packages'].each do |package|
|
120
|
+
fp_list << package['fingerprint'] if package['fingerprint']
|
121
|
+
sha1_list << package['sha1'] if package['sha1']
|
122
|
+
end
|
123
|
+
|
124
|
+
filter = {:fingerprint => fp_list, :sha1 => sha1_list}.sql_or
|
125
|
+
|
126
|
+
result = Models::Package.where(filter).all.map { |package|
|
127
|
+
[package.sha1, package.fingerprint]
|
128
|
+
}.flatten.compact.uniq
|
129
|
+
|
130
|
+
json_encode(result)
|
131
|
+
end
|
132
|
+
|
133
|
+
post '/releases', :consumes => :tgz do
|
134
|
+
options = {}
|
135
|
+
options['remote'] = false
|
136
|
+
options['rebase'] = true if params['rebase'] == 'true'
|
137
|
+
|
138
|
+
task = @release_manager.create_release(@user, request.body, options)
|
139
|
+
redirect "/tasks/#{task.id}"
|
140
|
+
end
|
141
|
+
|
142
|
+
post '/releases', :consumes => :json do
|
143
|
+
options = {}
|
144
|
+
options['remote'] = true
|
145
|
+
options['rebase'] = true if params['rebase'] == 'true'
|
146
|
+
payload = json_decode(request.body)
|
147
|
+
|
148
|
+
task = @release_manager.create_release(@user, payload['location'], options)
|
149
|
+
redirect "/tasks/#{task.id}"
|
150
|
+
end
|
151
|
+
|
152
|
+
get '/releases' do
|
153
|
+
releases = Models::Release.order_by(:name.asc).map do |release|
|
154
|
+
release_versions = release.versions_dataset.order_by(:version.asc).map do |rv|
|
155
|
+
Hash['version', rv.version.to_s,
|
156
|
+
'commit_hash', rv.commit_hash,
|
157
|
+
'uncommitted_changes', rv.uncommitted_changes,
|
158
|
+
'currently_deployed', !rv.deployments.empty?,
|
159
|
+
'job_names', rv.templates.map(&:name)]
|
160
|
+
end
|
161
|
+
|
162
|
+
Hash['name', release.name,
|
163
|
+
'release_versions', release_versions]
|
164
|
+
end
|
165
|
+
|
166
|
+
json_encode(releases)
|
167
|
+
end
|
168
|
+
|
169
|
+
get '/releases/:name' do
|
170
|
+
name = params[:name].to_s.strip
|
171
|
+
release = @release_manager.find_by_name(name)
|
172
|
+
|
173
|
+
result = { }
|
174
|
+
|
175
|
+
result['packages'] = release.packages.map do |package|
|
176
|
+
{
|
177
|
+
'name' => package.name,
|
178
|
+
'sha1' => package.sha1,
|
179
|
+
'version' => package.version.to_s,
|
180
|
+
'dependencies' => package.dependency_set.to_a
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
184
|
+
result['jobs'] = release.templates.map do |template|
|
185
|
+
{
|
186
|
+
'name' => template.name,
|
187
|
+
'sha1' => template.sha1,
|
188
|
+
'version' => template.version.to_s,
|
189
|
+
'packages' => template.package_names
|
190
|
+
}
|
191
|
+
end
|
192
|
+
|
193
|
+
result['versions'] = release.versions.map do |rv|
|
194
|
+
rv.version.to_s
|
195
|
+
end
|
196
|
+
|
197
|
+
content_type(:json)
|
198
|
+
json_encode(result)
|
199
|
+
end
|
200
|
+
|
201
|
+
delete '/releases/:name' do
|
202
|
+
release = @release_manager.find_by_name(params[:name])
|
203
|
+
|
204
|
+
options = {}
|
205
|
+
options['force'] = true if params['force'] == 'true'
|
206
|
+
options['version'] = params['version']
|
207
|
+
|
208
|
+
task = @release_manager.delete_release(@user, release, options)
|
209
|
+
redirect "/tasks/#{task.id}"
|
210
|
+
end
|
211
|
+
|
212
|
+
post '/stemcells', :consumes => :tgz do
|
213
|
+
task = @stemcell_manager.create_stemcell(@user, request.body, :remote => false)
|
214
|
+
redirect "/tasks/#{task.id}"
|
215
|
+
end
|
216
|
+
|
217
|
+
post '/stemcells', :consumes => :json do
|
218
|
+
payload = json_decode(request.body)
|
219
|
+
task = @stemcell_manager.create_stemcell(@user, payload['location'], :remote => true)
|
220
|
+
redirect "/tasks/#{task.id}"
|
221
|
+
end
|
222
|
+
|
223
|
+
get '/stemcells' do
|
224
|
+
stemcells = Models::Stemcell.order_by(:name.asc).map do |stemcell|
|
225
|
+
{
|
226
|
+
'name' => stemcell.name,
|
227
|
+
'version' => stemcell.version,
|
228
|
+
'cid' => stemcell.cid
|
229
|
+
}
|
230
|
+
end
|
231
|
+
json_encode(stemcells)
|
232
|
+
end
|
233
|
+
|
234
|
+
delete '/stemcells/:name/:version' do
|
235
|
+
name, version = params[:name], params[:version]
|
236
|
+
options = {}
|
237
|
+
options['force'] = true if params['force'] == 'true'
|
238
|
+
stemcell = @stemcell_manager.find_by_name_and_version(name, version)
|
239
|
+
task = @stemcell_manager.delete_stemcell(@user, stemcell, options)
|
240
|
+
redirect "/tasks/#{task.id}"
|
241
|
+
end
|
242
|
+
|
243
|
+
post '/deployments', :consumes => :yaml do
|
244
|
+
options = {}
|
245
|
+
options['recreate'] = true if params['recreate'] == 'true'
|
246
|
+
|
247
|
+
task = @deployment_manager.create_deployment(@user, request.body, options)
|
248
|
+
redirect "/tasks/#{task.id}"
|
249
|
+
end
|
250
|
+
|
251
|
+
get '/deployments/:deployment/jobs/:job/:index' do
|
252
|
+
instance = @instance_manager.find_by_name(params[:deployment], params[:job], params[:index])
|
253
|
+
|
254
|
+
response = {
|
255
|
+
deployment: params[:deployment],
|
256
|
+
job: instance.job,
|
257
|
+
index: instance.index,
|
258
|
+
state: instance.state,
|
259
|
+
disks: instance.persistent_disks.map {|d| d.disk_cid}
|
260
|
+
}
|
261
|
+
|
262
|
+
json_encode(response)
|
263
|
+
end
|
264
|
+
|
265
|
+
# PUT /deployments/foo/jobs/dea?new_name=dea_new
|
266
|
+
put '/deployments/:deployment/jobs/:job', :consumes => :yaml do
|
267
|
+
if params['state']
|
268
|
+
options = {
|
269
|
+
'job_states' => {
|
270
|
+
params[:job] => {
|
271
|
+
'state' => params['state']
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
else
|
276
|
+
unless params['new_name']
|
277
|
+
raise DirectorError, "Missing operation on job `#{params[:job]}'"
|
278
|
+
end
|
279
|
+
options = {
|
280
|
+
'job_rename' => {
|
281
|
+
'old_name' => params[:job],
|
282
|
+
'new_name' => params['new_name']
|
283
|
+
}
|
284
|
+
}
|
285
|
+
options['job_rename']['force'] = true if params['force'] == 'true'
|
286
|
+
end
|
287
|
+
|
288
|
+
# we get the deployment here even though it isn't used here, to make sure
|
289
|
+
# the call returns a 404 if the deployment doesn't exist
|
290
|
+
@deployment_manager.find_by_name(params[:deployment])
|
291
|
+
task = @deployment_manager.create_deployment(@user, request.body, options)
|
292
|
+
redirect "/tasks/#{task.id}"
|
293
|
+
end
|
294
|
+
|
295
|
+
# PUT /deployments/foo/jobs/dea/2?state={started,stopped,detached,restart,recreate}
|
296
|
+
put '/deployments/:deployment/jobs/:job/:index', :consumes => :yaml do
|
297
|
+
begin
|
298
|
+
index = Integer(params[:index])
|
299
|
+
rescue ArgumentError
|
300
|
+
raise InstanceInvalidIndex, "Invalid instance index `#{params[:index]}'"
|
301
|
+
end
|
302
|
+
|
303
|
+
options = {
|
304
|
+
'job_states' => {
|
305
|
+
params[:job] => {
|
306
|
+
'instance_states' => {
|
307
|
+
index => params['state']
|
308
|
+
}
|
309
|
+
}
|
310
|
+
}
|
311
|
+
}
|
312
|
+
|
313
|
+
deployment = @deployment_manager.find_by_name(params[:deployment])
|
314
|
+
manifest = request.content_length.nil? ? StringIO.new(deployment.manifest) : request.body
|
315
|
+
task = @deployment_manager.create_deployment(@user, manifest, options)
|
316
|
+
redirect "/tasks/#{task.id}"
|
317
|
+
end
|
318
|
+
|
319
|
+
# GET /deployments/foo/jobs/dea/2/logs
|
320
|
+
get '/deployments/:deployment/jobs/:job/:index/logs' do
|
321
|
+
deployment = params[:deployment]
|
322
|
+
job = params[:job]
|
323
|
+
index = params[:index]
|
324
|
+
|
325
|
+
options = {
|
326
|
+
'type' => params[:type].to_s.strip,
|
327
|
+
'filters' => params[:filters].to_s.strip.split(/[\s\,]+/)
|
328
|
+
}
|
329
|
+
|
330
|
+
task = @instance_manager.fetch_logs(@user, deployment, job, index, options)
|
331
|
+
redirect "/tasks/#{task.id}"
|
332
|
+
end
|
333
|
+
|
334
|
+
get '/deployments/:deployment/snapshots' do
|
335
|
+
deployment = @deployment_manager.find_by_name(params[:deployment])
|
336
|
+
json_encode(@snapshot_manager.snapshots(deployment))
|
337
|
+
end
|
338
|
+
|
339
|
+
get '/deployments/:deployment/jobs/:job/:index/snapshots' do
|
340
|
+
deployment = @deployment_manager.find_by_name(params[:deployment])
|
341
|
+
json_encode(@snapshot_manager.snapshots(deployment, params[:job], params[:index]))
|
342
|
+
end
|
343
|
+
|
344
|
+
post '/deployments/:deployment/snapshots' do
|
345
|
+
deployment = @deployment_manager.find_by_name(params[:deployment])
|
346
|
+
# until we can tell the agent to flush and wait, all snapshots are considered dirty
|
347
|
+
options = {clean: false}
|
348
|
+
|
349
|
+
task = @snapshot_manager.create_deployment_snapshot_task(@user, deployment, options)
|
350
|
+
redirect "/tasks/#{task.id}"
|
351
|
+
end
|
352
|
+
|
353
|
+
put '/deployments/:deployment/jobs/:job/:index/resurrection', consumes: :json do
|
354
|
+
payload = json_decode(request.body)
|
355
|
+
|
356
|
+
@resurrector_manager.set_pause_for_instance(params[:deployment], params[:job], params[:index], payload['resurrection_paused'])
|
357
|
+
end
|
358
|
+
|
359
|
+
post '/deployments/:deployment/jobs/:job/:index/snapshots' do
|
360
|
+
instance = @instance_manager.find_by_name(params[:deployment], params[:job], params[:index])
|
361
|
+
# until we can tell the agent to flush and wait, all snapshots are considered dirty
|
362
|
+
options = {clean: false}
|
363
|
+
|
364
|
+
task = @snapshot_manager.create_snapshot_task(@user, instance, options)
|
365
|
+
redirect "/tasks/#{task.id}"
|
366
|
+
end
|
367
|
+
|
368
|
+
delete '/deployments/:deployment/snapshots' do
|
369
|
+
deployment = @deployment_manager.find_by_name(params[:deployment])
|
370
|
+
|
371
|
+
task = @snapshot_manager.delete_deployment_snapshots_task(@user, deployment)
|
372
|
+
redirect "/tasks/#{task.id}"
|
373
|
+
end
|
374
|
+
|
375
|
+
delete '/deployments/:deployment/snapshots/:cid' do
|
376
|
+
deployment = @deployment_manager.find_by_name(params[:deployment])
|
377
|
+
snapshot = @snapshot_manager.find_by_cid(deployment, params[:cid])
|
378
|
+
|
379
|
+
task = @snapshot_manager.delete_snapshots_task(@user, [params[:cid]])
|
380
|
+
redirect "/tasks/#{task.id}"
|
381
|
+
end
|
382
|
+
|
383
|
+
get '/deployments' do
|
384
|
+
deployments = Models::Deployment.order_by(:name.asc).map { |deployment|
|
385
|
+
name = deployment.name
|
386
|
+
|
387
|
+
releases = deployment.release_versions.map { |rv|
|
388
|
+
Hash['name', rv.release.name, 'version', rv.version.to_s]
|
389
|
+
}
|
390
|
+
|
391
|
+
stemcells = deployment.stemcells.map { |sc|
|
392
|
+
Hash['name', sc.name, 'version', sc.version]
|
393
|
+
}
|
394
|
+
|
395
|
+
Hash['name', name, 'releases', releases, 'stemcells', stemcells]
|
396
|
+
}
|
397
|
+
|
398
|
+
json_encode(deployments)
|
399
|
+
end
|
400
|
+
|
401
|
+
get '/deployments/:name' do
|
402
|
+
deployment = @deployment_manager.find_by_name(params[:name])
|
403
|
+
@deployment_manager.deployment_to_json(deployment)
|
404
|
+
end
|
405
|
+
|
406
|
+
get '/deployments/:name/vms' do
|
407
|
+
deployment = @deployment_manager.find_by_name(params[:name])
|
408
|
+
|
409
|
+
format = params[:format]
|
410
|
+
if format == 'full'
|
411
|
+
task = @vm_state_manager.fetch_vm_state(@user, deployment, format)
|
412
|
+
redirect "/tasks/#{task.id}"
|
413
|
+
else
|
414
|
+
@deployment_manager.deployment_vms_to_json(deployment)
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
delete '/deployments/:name' do
|
419
|
+
deployment = @deployment_manager.find_by_name(params[:name])
|
420
|
+
|
421
|
+
options = {}
|
422
|
+
options['force'] = true if params['force'] == 'true'
|
423
|
+
options['keep_snapshots'] = true if params['keep_snapshots'] == 'true'
|
424
|
+
task = @deployment_manager.delete_deployment(@user, deployment, options)
|
425
|
+
redirect "/tasks/#{task.id}"
|
426
|
+
end
|
427
|
+
|
428
|
+
# Property management
|
429
|
+
get '/deployments/:deployment/properties' do
|
430
|
+
properties = @property_manager.get_properties(params[:deployment]).map do |property|
|
431
|
+
{ 'name' => property.name, 'value' => property.value }
|
432
|
+
end
|
433
|
+
json_encode(properties)
|
434
|
+
end
|
435
|
+
|
436
|
+
get '/deployments/:deployment/properties/:property' do
|
437
|
+
property = @property_manager.get_property(params[:deployment], params[:property])
|
438
|
+
json_encode('value' => property.value)
|
439
|
+
end
|
440
|
+
|
441
|
+
post '/deployments/:deployment/properties', :consumes => [:json] do
|
442
|
+
payload = json_decode(request.body)
|
443
|
+
@property_manager.create_property(params[:deployment], payload['name'], payload['value'])
|
444
|
+
status(204)
|
445
|
+
end
|
446
|
+
|
447
|
+
post '/deployments/:deployment/ssh', :consumes => [:json] do
|
448
|
+
payload = json_decode(request.body)
|
449
|
+
task = @instance_manager.ssh(@user, payload)
|
450
|
+
redirect "/tasks/#{task.id}"
|
451
|
+
end
|
452
|
+
|
453
|
+
put '/deployments/:deployment/properties/:property', :consumes => [:json] do
|
454
|
+
payload = json_decode(request.body)
|
455
|
+
@property_manager.update_property(params[:deployment], params[:property], payload['value'])
|
456
|
+
status(204)
|
457
|
+
end
|
458
|
+
|
459
|
+
delete '/deployments/:deployment/properties/:property' do
|
460
|
+
@property_manager.delete_property(params[:deployment], params[:property])
|
461
|
+
status(204)
|
462
|
+
end
|
463
|
+
|
464
|
+
# Cloud check
|
465
|
+
|
466
|
+
# Initiate deployment scan
|
467
|
+
post '/deployments/:deployment/scans' do
|
468
|
+
start_task { @problem_manager.perform_scan(@user, params[:deployment]) }
|
469
|
+
end
|
470
|
+
|
471
|
+
# Get the list of problems for a particular deployment
|
472
|
+
get '/deployments/:deployment/problems' do
|
473
|
+
problems = @problem_manager.get_problems(params[:deployment]).map do |problem|
|
474
|
+
{
|
475
|
+
'id' => problem.id,
|
476
|
+
'type' => problem.type,
|
477
|
+
'data' => problem.data,
|
478
|
+
'description' => problem.description,
|
479
|
+
'resolutions' => problem.resolutions
|
480
|
+
}
|
481
|
+
end
|
482
|
+
|
483
|
+
json_encode(problems)
|
484
|
+
end
|
485
|
+
|
486
|
+
# Try to resolve a set of problems
|
487
|
+
put '/deployments/:deployment/problems', :consumes => [:json] do
|
488
|
+
payload = json_decode(request.body)
|
489
|
+
start_task { @problem_manager.apply_resolutions(@user, params[:deployment], payload['resolutions']) }
|
490
|
+
end
|
491
|
+
|
492
|
+
put '/deployments/:deployment/scan_and_fix', :consumes => :json do
|
493
|
+
jobs_json = json_decode(request.body)['jobs']
|
494
|
+
# payload: [['j1', 'i1'], ['j1', 'i2'], ['j2', 'i1'], ...]
|
495
|
+
payload = convert_job_instance_hash(jobs_json)
|
496
|
+
|
497
|
+
start_task { @problem_manager.scan_and_fix(@user, params[:deployment], payload) }
|
498
|
+
end
|
499
|
+
|
500
|
+
get '/tasks' do
|
501
|
+
dataset = Models::Task.dataset
|
502
|
+
limit = params['limit']
|
503
|
+
if limit
|
504
|
+
limit = limit.to_i
|
505
|
+
limit = 1 if limit < 1
|
506
|
+
dataset = dataset.limit(limit)
|
507
|
+
end
|
508
|
+
|
509
|
+
states = params['state'].to_s.split(',')
|
510
|
+
|
511
|
+
if states.size > 0
|
512
|
+
dataset = dataset.filter(:state => states)
|
513
|
+
end
|
514
|
+
|
515
|
+
verbose = params['verbose'] || '1'
|
516
|
+
if verbose == '1'
|
517
|
+
dataset = dataset.filter(type: %w[
|
518
|
+
update_deployment
|
519
|
+
delete_deployment
|
520
|
+
update_release
|
521
|
+
delete_release
|
522
|
+
update_stemcell
|
523
|
+
delete_stemcell
|
524
|
+
create_snapshot
|
525
|
+
delete_snapshot
|
526
|
+
snapshot_deployment
|
527
|
+
])
|
528
|
+
end
|
529
|
+
|
530
|
+
tasks = dataset.order_by(:timestamp.desc).map do |task|
|
531
|
+
if task_timeout?(task)
|
532
|
+
task.state = :timeout
|
533
|
+
task.save
|
534
|
+
end
|
535
|
+
@task_manager.task_to_hash(task)
|
536
|
+
end
|
537
|
+
|
538
|
+
content_type(:json)
|
539
|
+
json_encode(tasks)
|
540
|
+
end
|
541
|
+
|
542
|
+
get '/tasks/:id' do
|
543
|
+
task = @task_manager.find_task(params[:id])
|
544
|
+
if task_timeout?(task)
|
545
|
+
task.state = :timeout
|
546
|
+
task.save
|
547
|
+
end
|
548
|
+
|
549
|
+
content_type(:json)
|
550
|
+
json_encode(@task_manager.task_to_hash(task))
|
551
|
+
end
|
552
|
+
|
553
|
+
# Sends back output of given task id and params[:type]
|
554
|
+
# Example: `get /tasks/5/output?type=event` will send back the file
|
555
|
+
# at /var/vcap/store/director/tasks/5/event
|
556
|
+
get '/tasks/:id/output' do
|
557
|
+
log_type = params[:type] || 'debug'
|
558
|
+
task = @task_manager.find_task(params[:id])
|
559
|
+
|
560
|
+
if task.output.nil?
|
561
|
+
halt(204)
|
562
|
+
end
|
563
|
+
|
564
|
+
log_file = @task_manager.log_file(task, log_type)
|
565
|
+
|
566
|
+
if File.file?(log_file)
|
567
|
+
send_file(log_file, :type => 'text/plain')
|
568
|
+
else
|
569
|
+
status(204)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
delete '/task/:id' do
|
574
|
+
task_id = params[:id]
|
575
|
+
task = @task_manager.find_task(task_id)
|
576
|
+
|
577
|
+
if task.state != 'processing' && task.state != 'queued'
|
578
|
+
status(400)
|
579
|
+
body("Cannot cancel task #{task_id}: invalid state (#{task.state})")
|
580
|
+
else
|
581
|
+
task.state = :cancelling
|
582
|
+
task.save
|
583
|
+
status(204)
|
584
|
+
body("Cancelling task #{task_id}")
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
# JMS and MB: We don't know why this code exists. According to JP it shouldn't. We want to remove it.
|
589
|
+
# To get comforable with that idea, we log something we can look for in production.
|
590
|
+
#
|
591
|
+
# GET /resources/deadbeef
|
592
|
+
get '/resources/:id' do
|
593
|
+
@logger.warn('Something is proxying a blob through the director. Find out why before we remove this method. ZAUGYZ')
|
594
|
+
tmp_file = @resource_manager.get_resource_path(params[:id])
|
595
|
+
send_disposable_file(tmp_file, :type => 'application/x-gzip')
|
596
|
+
end
|
597
|
+
|
598
|
+
post '/backups' do
|
599
|
+
start_task { @backup_manager.create_backup(@user) }
|
600
|
+
end
|
601
|
+
|
602
|
+
get '/backups' do
|
603
|
+
send_file @backup_manager.destination_path
|
604
|
+
end
|
605
|
+
|
606
|
+
get '/info' do
|
607
|
+
status = {
|
608
|
+
'name' => Config.name,
|
609
|
+
'uuid' => Config.uuid,
|
610
|
+
'version' => "#{VERSION} (#{Config.revision})",
|
611
|
+
'user' => @user,
|
612
|
+
'cpi' => Config.cloud_type,
|
613
|
+
'features' => {
|
614
|
+
'dns' => {
|
615
|
+
'status' => Config.dns_enabled?,
|
616
|
+
'extras' => { 'domain_name' => dns_domain_name }
|
617
|
+
},
|
618
|
+
'compiled_package_cache' => {
|
619
|
+
'status' => Config.use_compiled_package_cache?,
|
620
|
+
'extras' => { 'provider' => Config.compiled_package_cache_provider }
|
621
|
+
},
|
622
|
+
'snapshots' => {
|
623
|
+
'status' => Config.enable_snapshots
|
624
|
+
}
|
625
|
+
}
|
626
|
+
}
|
627
|
+
content_type(:json)
|
628
|
+
json_encode(status)
|
629
|
+
end
|
630
|
+
|
631
|
+
put '/resurrection', consumes: :json do
|
632
|
+
payload = json_decode(request.body)
|
633
|
+
|
634
|
+
@resurrector_manager.set_pause_for_all(payload['resurrection_paused'])
|
635
|
+
status(200)
|
636
|
+
end
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|