bosh_agent 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 +0 -0
- data/bin/bosh_agent +102 -0
- data/lib/bosh_agent/alert.rb +191 -0
- data/lib/bosh_agent/alert_processor.rb +96 -0
- data/lib/bosh_agent/apply_plan/helpers.rb +30 -0
- data/lib/bosh_agent/apply_plan/job.rb +235 -0
- data/lib/bosh_agent/apply_plan/package.rb +58 -0
- data/lib/bosh_agent/apply_plan/plan.rb +96 -0
- data/lib/bosh_agent/bootstrap.rb +341 -0
- data/lib/bosh_agent/config.rb +5 -0
- data/lib/bosh_agent/configuration.rb +102 -0
- data/lib/bosh_agent/disk_util.rb +103 -0
- data/lib/bosh_agent/errors.rb +25 -0
- data/lib/bosh_agent/ext.rb +48 -0
- data/lib/bosh_agent/file_aggregator.rb +78 -0
- data/lib/bosh_agent/file_matcher.rb +45 -0
- data/lib/bosh_agent/handler.rb +440 -0
- data/lib/bosh_agent/heartbeat.rb +74 -0
- data/lib/bosh_agent/heartbeat_processor.rb +45 -0
- data/lib/bosh_agent/http_handler.rb +135 -0
- data/lib/bosh_agent/infrastructure/aws/registry.rb +177 -0
- data/lib/bosh_agent/infrastructure/aws/settings.rb +59 -0
- data/lib/bosh_agent/infrastructure/aws.rb +17 -0
- data/lib/bosh_agent/infrastructure/dummy.rb +24 -0
- data/lib/bosh_agent/infrastructure/openstack/registry.rb +220 -0
- data/lib/bosh_agent/infrastructure/openstack/settings.rb +76 -0
- data/lib/bosh_agent/infrastructure/openstack.rb +17 -0
- data/lib/bosh_agent/infrastructure/vsphere/settings.rb +135 -0
- data/lib/bosh_agent/infrastructure/vsphere.rb +16 -0
- data/lib/bosh_agent/infrastructure.rb +25 -0
- data/lib/bosh_agent/message/apply.rb +184 -0
- data/lib/bosh_agent/message/base.rb +38 -0
- data/lib/bosh_agent/message/compile_package.rb +250 -0
- data/lib/bosh_agent/message/drain.rb +195 -0
- data/lib/bosh_agent/message/list_disk.rb +25 -0
- data/lib/bosh_agent/message/logs.rb +108 -0
- data/lib/bosh_agent/message/migrate_disk.rb +55 -0
- data/lib/bosh_agent/message/mount_disk.rb +102 -0
- data/lib/bosh_agent/message/ssh.rb +109 -0
- data/lib/bosh_agent/message/state.rb +47 -0
- data/lib/bosh_agent/message/unmount_disk.rb +29 -0
- data/lib/bosh_agent/monit.rb +354 -0
- data/lib/bosh_agent/monit_client.rb +158 -0
- data/lib/bosh_agent/mounter.rb +42 -0
- data/lib/bosh_agent/ntp.rb +32 -0
- data/lib/bosh_agent/platform/centos/disk.rb +27 -0
- data/lib/bosh_agent/platform/centos/network.rb +39 -0
- data/lib/bosh_agent/platform/centos/templates/centos-ifcfg.erb +9 -0
- data/lib/bosh_agent/platform/centos/templates/dhclient_conf.erb +56 -0
- data/lib/bosh_agent/platform/centos/templates/logrotate.erb +8 -0
- data/lib/bosh_agent/platform/centos.rb +4 -0
- data/lib/bosh_agent/platform/dummy/templates/dummy_template.erb +1 -0
- data/lib/bosh_agent/platform/linux/adapter.rb +36 -0
- data/lib/bosh_agent/platform/linux/disk.rb +121 -0
- data/lib/bosh_agent/platform/linux/logrotate.rb +32 -0
- data/lib/bosh_agent/platform/linux/network.rb +124 -0
- data/lib/bosh_agent/platform/linux/password.rb +22 -0
- data/lib/bosh_agent/platform/linux.rb +4 -0
- data/lib/bosh_agent/platform/ubuntu/network.rb +59 -0
- data/lib/bosh_agent/platform/ubuntu/templates/dhclient_conf.erb +56 -0
- data/lib/bosh_agent/platform/ubuntu/templates/interfaces.erb +14 -0
- data/lib/bosh_agent/platform/ubuntu/templates/logrotate.erb +8 -0
- data/lib/bosh_agent/platform/ubuntu.rb +4 -0
- data/lib/bosh_agent/platform.rb +26 -0
- data/lib/bosh_agent/remote_exception.rb +62 -0
- data/lib/bosh_agent/runner.rb +36 -0
- data/lib/bosh_agent/settings.rb +61 -0
- data/lib/bosh_agent/sigar_box.rb +26 -0
- data/lib/bosh_agent/smtp_server.rb +96 -0
- data/lib/bosh_agent/state.rb +100 -0
- data/lib/bosh_agent/syslog_monitor.rb +53 -0
- data/lib/bosh_agent/template.rb +50 -0
- data/lib/bosh_agent/util.rb +190 -0
- data/lib/bosh_agent/version.rb +8 -0
- data/lib/bosh_agent.rb +92 -0
- metadata +332 -0
@@ -0,0 +1,250 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require 'blobstore_client'
|
4
|
+
|
5
|
+
module Bosh::Agent
|
6
|
+
module Message
|
7
|
+
# This agent message "compile_package" fetches the source package from
|
8
|
+
# the blobstore, fetches the dependency compiled packages, compiles the
|
9
|
+
# source package, packs it into a tgz blob, and uploads it to the same
|
10
|
+
# blobstore. It returns the uploaded blob's blobstore_id & sha1.
|
11
|
+
#
|
12
|
+
# This message has the following uses:
|
13
|
+
# * the bosh-release (within the stemcell_builder) to
|
14
|
+
# compile packages to the microbosh's local blobstore
|
15
|
+
# * the director requests packages be compiled during deployment
|
16
|
+
# if they are not yet compiled and available in the blobstore
|
17
|
+
#
|
18
|
+
# Source packages must have a `packaging` executable script. It can find the
|
19
|
+
# unpackaged source files in the directory it is run in (which is also provided
|
20
|
+
# as $BOSH_COMPILE_TARGET variable).
|
21
|
+
# The packaging script MUST place all compiled assets within the single folder
|
22
|
+
# specified as $BOSH_INSTALL_TARGET.
|
23
|
+
# The packaging script is also provided the environment variables $BOSH_PACKAGE_NAME
|
24
|
+
# and $BOSH_PACKAGE_VERSION
|
25
|
+
class CompilePackage
|
26
|
+
attr_accessor :blobstore_id, :package_name, :package_version, :package_sha1
|
27
|
+
attr_accessor :compile_base, :install_base
|
28
|
+
attr_reader :blobstore_client
|
29
|
+
|
30
|
+
def self.process(args)
|
31
|
+
self.new(args).start
|
32
|
+
end
|
33
|
+
def self.long_running?; true; end
|
34
|
+
|
35
|
+
def initialize(args)
|
36
|
+
bsc_provider = Bosh::Agent::Config.blobstore_provider
|
37
|
+
bsc_options = Bosh::Agent::Config.blobstore_options
|
38
|
+
@blobstore_client = Bosh::Blobstore::Client.create(bsc_provider, bsc_options)
|
39
|
+
@blobstore_id, @sha1, @package_name, @package_version, @dependencies = args
|
40
|
+
|
41
|
+
@base_dir = Bosh::Agent::Config.base_dir
|
42
|
+
|
43
|
+
# The maximum amount of disk percentage that can be used during
|
44
|
+
# compilation before an error will be thrown. This is to prevent
|
45
|
+
# package compilation throwing arbitrary errors when disk space runs
|
46
|
+
# out.
|
47
|
+
# @attr [Integer] The max percentage of disk that can be used in
|
48
|
+
# compilation.
|
49
|
+
@max_disk_usage_pct = 90
|
50
|
+
FileUtils.mkdir_p(File.join(@base_dir, 'data', 'tmp'))
|
51
|
+
|
52
|
+
@log_file = "#{@base_dir}/data/tmp/#{Bosh::Agent::Config.agent_id}"
|
53
|
+
@logger = Logger.new(@log_file)
|
54
|
+
@logger.level = Logger::DEBUG
|
55
|
+
@compile_base = "#{@base_dir}/data/compile"
|
56
|
+
@install_base = "#{@base_dir}/data/packages"
|
57
|
+
end
|
58
|
+
|
59
|
+
def start
|
60
|
+
begin
|
61
|
+
install_dependencies
|
62
|
+
get_source_package
|
63
|
+
unpack_source_package
|
64
|
+
compile
|
65
|
+
pack
|
66
|
+
result = upload
|
67
|
+
clear_log_file(@log_file)
|
68
|
+
return { "result" => result }
|
69
|
+
rescue RuntimeError => e
|
70
|
+
@logger.warn("%s\n%s" % [e.message, e.backtrace.join("\n")])
|
71
|
+
raise Bosh::Agent::MessageHandlerError, e
|
72
|
+
ensure
|
73
|
+
delete_tmp_files
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Delete the leftover compilation files after a compilation is done. This
|
79
|
+
# is done so that the reuse_compilation_vms option does not fill up a VM.
|
80
|
+
def delete_tmp_files
|
81
|
+
[@compile_base, @install_base].each do |dir|
|
82
|
+
if Dir.exists?(dir)
|
83
|
+
FileUtils.rm_rf(dir)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def install_dependencies
|
89
|
+
@logger.info("Installing Dependencies")
|
90
|
+
@dependencies.each do |pkg_name, pkg|
|
91
|
+
@logger.info("Installing depdendency: #{pkg_name} #{pkg.inspect}")
|
92
|
+
|
93
|
+
blobstore_id = pkg['blobstore_id']
|
94
|
+
sha1 = pkg['sha1']
|
95
|
+
install_dir = File.join(@install_base, pkg_name, pkg['version'])
|
96
|
+
|
97
|
+
Util.unpack_blob(blobstore_id, sha1, install_dir)
|
98
|
+
|
99
|
+
pkg_link_dst = File.join(@base_dir, 'packages', pkg_name)
|
100
|
+
FileUtils.ln_sf(install_dir, pkg_link_dst)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def get_source_package
|
105
|
+
compile_tmp = File.join(@compile_base, 'tmp')
|
106
|
+
FileUtils.mkdir_p compile_tmp
|
107
|
+
@source_file = File.join(compile_tmp, @blobstore_id)
|
108
|
+
FileUtils.rm @source_file if File.exist?(@source_file)
|
109
|
+
|
110
|
+
File.open(@source_file, 'w') do |f|
|
111
|
+
@blobstore_client.get(@blobstore_id, f)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def compile_dir
|
116
|
+
@compile_dir ||= File.join(@compile_base, @package_name)
|
117
|
+
end
|
118
|
+
|
119
|
+
def install_dir
|
120
|
+
@install_dir ||= File.join(@install_base, @package_name, @package_version.to_s)
|
121
|
+
end
|
122
|
+
|
123
|
+
def unpack_source_package
|
124
|
+
FileUtils.rm_rf compile_dir if File.directory?(compile_dir)
|
125
|
+
|
126
|
+
FileUtils.mkdir_p compile_dir
|
127
|
+
Dir.chdir(compile_dir) do
|
128
|
+
output = `tar -zxf #{@source_file} 2>&1`
|
129
|
+
@logger.info(output)
|
130
|
+
# stick the output in the blobstore
|
131
|
+
unless $?.exitstatus == 0
|
132
|
+
STDOUT.puts(output)
|
133
|
+
raise Bosh::Agent::MessageHandlerError.new(
|
134
|
+
"Compile Package Unpack Source Failure (exit code: #{$?.exitstatus})",
|
135
|
+
output)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def disk_info_as_array(path)
|
141
|
+
# "Filesystem 1024-blocks Used Available Capacity Mounted on\n
|
142
|
+
# /dev/disk0s2 195312496 92743676 102312820 48% /\n"
|
143
|
+
df_out = `df -Pk #{path} 2>&1`
|
144
|
+
unless $?.exitstatus == 0
|
145
|
+
raise Bosh::Agent::MessageHandlerError, "Command 'df -Pk #{path}' " +
|
146
|
+
"on compilation VM failed with:\n#{df_out}\nexit code: " +
|
147
|
+
"#{$?.exitstatus}"
|
148
|
+
end
|
149
|
+
|
150
|
+
# "/dev/disk0s2 195312496 92743568 102312928 48% /\n"
|
151
|
+
df_out = df_out.sub(/[^\/]*/, "")
|
152
|
+
# ["/dev/disk0s2", "195312496", "92743568", "102312928", "48%", "/\n"]
|
153
|
+
df_out.split(/[ ]+/)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Get the amount of total disk (in KBytes).
|
157
|
+
# @param [String] path Path that the disk size is being requested for.
|
158
|
+
# @return [Integer] The total disk size (in KBytes).
|
159
|
+
def disk_total(path)
|
160
|
+
disk_info_as_array(path)[1].to_i
|
161
|
+
end
|
162
|
+
|
163
|
+
# Get the amount of disk being used (in KBytes).
|
164
|
+
# @param [String] path Path that the disk usage is being requested for.
|
165
|
+
# @return [Integer] The amount being used (in KBytes).
|
166
|
+
def disk_used(path)
|
167
|
+
disk_info_as_array(path)[2].to_i
|
168
|
+
end
|
169
|
+
|
170
|
+
# Get the percentage of disk that is used on the compilation VM.
|
171
|
+
# @param [String] path Path that the disk usage is being requested for.
|
172
|
+
# @return [Float] The percentage of disk in use.
|
173
|
+
def pct_disk_used(path)
|
174
|
+
100 * disk_used(path).to_f / disk_total(path).to_f
|
175
|
+
end
|
176
|
+
|
177
|
+
def compile
|
178
|
+
FileUtils.rm_rf install_dir if File.directory?(install_dir)
|
179
|
+
FileUtils.mkdir_p install_dir
|
180
|
+
|
181
|
+
pkg_link_dst = File.join(@base_dir, 'packages', @package_name)
|
182
|
+
FileUtils.ln_sf(install_dir, pkg_link_dst)
|
183
|
+
|
184
|
+
pct_space_used = pct_disk_used(@compile_base)
|
185
|
+
if pct_space_used >= @max_disk_usage_pct
|
186
|
+
raise Bosh::Agent::MessageHandlerError,
|
187
|
+
"Compile Package Failure. Greater than #{@max_disk_usage_pct}% " +
|
188
|
+
"is used (#{pct_space_used}%."
|
189
|
+
end
|
190
|
+
Dir.chdir(compile_dir) do
|
191
|
+
|
192
|
+
# Prevent these from getting inhereted from the agent
|
193
|
+
%w{GEM_HOME BUNDLE_GEMFILE RUBYOPT}.each { |key| ENV.delete(key) }
|
194
|
+
|
195
|
+
ENV['BOSH_COMPILE_TARGET'] = compile_dir
|
196
|
+
ENV['BOSH_INSTALL_TARGET'] = pkg_link_dst
|
197
|
+
ENV['BOSH_PACKAGE_NAME'] = @package_name.to_s
|
198
|
+
ENV['BOSH_PACKAGE_VERSION'] = @package_version.to_s
|
199
|
+
if File.exist?('packaging')
|
200
|
+
@logger.info("Compiling #{@package_name} #{@package_version}")
|
201
|
+
output = `bash -x packaging 2>&1`
|
202
|
+
# stick the output in the blobstore
|
203
|
+
@logger.fatal(output)
|
204
|
+
unless $?.exitstatus == 0
|
205
|
+
raise Bosh::Agent::MessageHandlerError.new(
|
206
|
+
"Compile Package Failure (exit code: #{$?.exitstatus})", output)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def compiled_package
|
213
|
+
File.join(@source_file + ".compiled")
|
214
|
+
end
|
215
|
+
|
216
|
+
def pack
|
217
|
+
@logger.info("Packing #{@package_name} #{@package_version}")
|
218
|
+
Dir.chdir(install_dir) do
|
219
|
+
`tar -zcf #{compiled_package} .`
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Clears the log file after a compilation runs. This is needed because if
|
224
|
+
# reuse_compilation_vms is being used then without clearing the log then
|
225
|
+
# the log from each subsequent compilation will include the previous
|
226
|
+
# compilation's output.
|
227
|
+
# @param [String] log_file Path to the log file.
|
228
|
+
def clear_log_file(log_file)
|
229
|
+
File.delete(log_file) if File.exists?(log_file)
|
230
|
+
@logger = Logger.new(log_file)
|
231
|
+
end
|
232
|
+
|
233
|
+
def upload
|
234
|
+
compiled_blobstore_id = nil
|
235
|
+
File.open(compiled_package, 'r') do |f|
|
236
|
+
compiled_blobstore_id = @blobstore_client.create(f)
|
237
|
+
end
|
238
|
+
compiled_sha1 = Digest::SHA1.file(compiled_package).hexdigest
|
239
|
+
compile_log_id = @blobstore_client.create(@log_file)
|
240
|
+
@logger.info("Uploaded #{@package_name} #{@package_version} " +
|
241
|
+
"(sha1: #{compiled_sha1}, " +
|
242
|
+
"blobstore_id: #{compiled_blobstore_id})")
|
243
|
+
@logger = nil
|
244
|
+
{ "sha1" => compiled_sha1, "blobstore_id" => compiled_blobstore_id,
|
245
|
+
"compile_log_id" => compile_log_id }
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'monitor'
|
5
|
+
|
6
|
+
module Bosh::Agent
|
7
|
+
module Message
|
8
|
+
class Drain
|
9
|
+
|
10
|
+
HM_NOTIFY_TIMEOUT = 5
|
11
|
+
|
12
|
+
def self.process(args)
|
13
|
+
self.new(args).drain
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.long_running?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(args)
|
21
|
+
@logger = Bosh::Agent::Config.logger
|
22
|
+
@nats = Bosh::Agent::Config.nats
|
23
|
+
@agent_id = Bosh::Agent::Config.agent_id
|
24
|
+
@old_spec = Bosh::Agent::Config.state.to_hash
|
25
|
+
@args = args
|
26
|
+
|
27
|
+
@drain_type = args[0]
|
28
|
+
@spec = args[1]
|
29
|
+
@drain_script = DrainScript.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def job_change
|
33
|
+
if !@old_spec.key?('job')
|
34
|
+
"job_new"
|
35
|
+
elsif @old_spec['job']['sha1'] == @spec['job']['sha1']
|
36
|
+
"job_unchanged"
|
37
|
+
else
|
38
|
+
"job_changed"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash_change
|
43
|
+
if !@old_spec.key?('configuration_hash')
|
44
|
+
"hash_new"
|
45
|
+
elsif @old_spec['configuration_hash'] == @spec['configuration_hash']
|
46
|
+
"hash_unchanged"
|
47
|
+
else
|
48
|
+
"hash_changed"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def drain
|
53
|
+
@logger.info("Draining: #{@args.inspect}")
|
54
|
+
|
55
|
+
if Bosh::Agent::Config.configure
|
56
|
+
Bosh::Agent::Monit.unmonitor_services
|
57
|
+
end
|
58
|
+
|
59
|
+
case @drain_type
|
60
|
+
when "shutdown"
|
61
|
+
drain_for_shutdown
|
62
|
+
when "update"
|
63
|
+
drain_for_update
|
64
|
+
when "status"
|
65
|
+
drain_check_status
|
66
|
+
else
|
67
|
+
raise Bosh::Agent::MessageHandlerError, "Unknown drain type #{@drain_type}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def drain_for_update
|
72
|
+
if @spec.nil?
|
73
|
+
raise Bosh::Agent::MessageHandlerError, "Drain update called without apply spec"
|
74
|
+
end
|
75
|
+
|
76
|
+
if @old_spec.key?('job') && drain_script_exists?
|
77
|
+
# HACK: We go through the motions below to be able to support drain scripts written as shell scripts
|
78
|
+
run_drain_script(job_change, hash_change, updated_packages.flatten)
|
79
|
+
else
|
80
|
+
0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def drain_for_shutdown
|
85
|
+
lock = Monitor.new
|
86
|
+
delivery_cond = lock.new_cond
|
87
|
+
delivered = false
|
88
|
+
|
89
|
+
if @nats
|
90
|
+
# HM notification should be in sync with VM shutdown
|
91
|
+
Thread.new do
|
92
|
+
@nats.publish("hm.agent.shutdown.#{@agent_id}") do
|
93
|
+
lock.synchronize do
|
94
|
+
delivered = true
|
95
|
+
delivery_cond.signal
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
lock.synchronize do
|
102
|
+
delivery_cond.wait(HM_NOTIFY_TIMEOUT) unless delivered
|
103
|
+
end
|
104
|
+
|
105
|
+
if @old_spec.key?('job') && drain_script_exists?
|
106
|
+
run_drain_script("job_shutdown", "hash_unchanged", [])
|
107
|
+
else
|
108
|
+
0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def drain_check_status
|
113
|
+
run_drain_script("job_check_status", "hash_unchanged", [])
|
114
|
+
end
|
115
|
+
|
116
|
+
def run_drain_script(job_updated, hash_updated, updated_packages)
|
117
|
+
@drain_script.run(job_updated, hash_updated, updated_packages)
|
118
|
+
end
|
119
|
+
|
120
|
+
def updated_packages
|
121
|
+
updated_packages = []
|
122
|
+
|
123
|
+
return updated_packages unless @old_spec.key?('packages')
|
124
|
+
|
125
|
+
# Check old packages
|
126
|
+
updated_packages << @old_spec['packages'].find_all do |pkg_name, pkg|
|
127
|
+
if @spec['packages'].key?(pkg_name)
|
128
|
+
pkg['sha1'] != @spec['packages'][pkg_name]['sha1']
|
129
|
+
else
|
130
|
+
false
|
131
|
+
end
|
132
|
+
end.collect { |package_name, pkg| package_name }
|
133
|
+
|
134
|
+
# New packages counts as new
|
135
|
+
updated_packages << @spec['packages'].find_all do |pkg_name, pkg|
|
136
|
+
unless @old_spec['packages'].key?(pkg_name)
|
137
|
+
true
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end.collect { |package_name, pkg| package_name }
|
142
|
+
end
|
143
|
+
|
144
|
+
def drain_script_exists?
|
145
|
+
@drain_script.exists?
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
class DrainScript
|
151
|
+
attr_reader :base_dir, :job_template
|
152
|
+
|
153
|
+
def initialize(base_dir=Bosh::Agent::Config.base_dir, job_template=nil)
|
154
|
+
@base_dir = base_dir
|
155
|
+
@job_template = job_template || Bosh::Agent::Config.state.to_hash.fetch('job', {}).fetch('template', 'job')
|
156
|
+
end
|
157
|
+
|
158
|
+
def exists?
|
159
|
+
File.exists?(script_file)
|
160
|
+
end
|
161
|
+
|
162
|
+
def run(job_updated, hash_updated, updated_packages)
|
163
|
+
env = {
|
164
|
+
'PATH' => '/usr/sbin:/usr/bin:/sbin:/bin',
|
165
|
+
'BOSH_CURRENT_STATE' => Yajl::Encoder.encode(@old_spec),
|
166
|
+
'BOSH_APPLY_SPEC' => Yajl::Encoder.encode(@spec)
|
167
|
+
}
|
168
|
+
|
169
|
+
# Drain contract: on success the drain script should return a number exit(0)
|
170
|
+
stdout_rd, stdout_wr = IO.pipe
|
171
|
+
|
172
|
+
args = [ env, script_file, job_updated, hash_updated, *updated_packages ]
|
173
|
+
args += [ :out => stdout_wr, :unsetenv_others => true ]
|
174
|
+
Process.spawn(*args)
|
175
|
+
Process.wait
|
176
|
+
stdout_wr.close
|
177
|
+
|
178
|
+
exit_status = $?.exitstatus
|
179
|
+
output = stdout_rd.read
|
180
|
+
|
181
|
+
unless output.match(/\A-{0,1}\d+\Z/) && exit_status == 0
|
182
|
+
raise Bosh::Agent::MessageHandlerError,
|
183
|
+
"Drain script exit #{exit_status}: #{output}"
|
184
|
+
end
|
185
|
+
|
186
|
+
output.to_i
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
def script_file
|
191
|
+
"#{base_dir}/jobs/#{job_template}/bin/drain"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'bosh_agent/disk_util'
|
2
|
+
|
3
|
+
module Bosh::Agent
|
4
|
+
module Message
|
5
|
+
class ListDisk < Base
|
6
|
+
def self.process(args = nil)
|
7
|
+
disk_info = []
|
8
|
+
settings = Bosh::Agent::Config.settings
|
9
|
+
|
10
|
+
if settings["disks"].kind_of?(Hash) && settings["disks"]["persistent"].kind_of?(Hash)
|
11
|
+
cids = settings["disks"]["persistent"]
|
12
|
+
else
|
13
|
+
cids = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
cids.each_key do |cid|
|
17
|
+
disk = Bosh::Agent::Config.platform.lookup_disk_by_cid(cid)
|
18
|
+
partition = "#{disk}1"
|
19
|
+
disk_info << cid unless DiskUtil.mount_entry(partition).nil?
|
20
|
+
end
|
21
|
+
disk_info
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Agent
|
4
|
+
module Message
|
5
|
+
class FetchLogs < Base
|
6
|
+
|
7
|
+
def self.long_running?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.process(args)
|
12
|
+
new(args).process
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :matcher, :aggregator
|
16
|
+
|
17
|
+
def initialize(args)
|
18
|
+
@log_type = args[0]
|
19
|
+
@filters = Set.new(args[1])
|
20
|
+
@state = Bosh::Agent::Config.state.to_hash
|
21
|
+
@matcher = default_matcher
|
22
|
+
@aggregator = Bosh::Agent::FileAggregator.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def process
|
26
|
+
handler_error("matcher for #{@log_type} logs not found") unless @matcher
|
27
|
+
handler_error("aggregator for #{@log_type} logs not found") unless @aggregator
|
28
|
+
|
29
|
+
if @filters && @filters.size > 0
|
30
|
+
@matcher.globs = filter_globs
|
31
|
+
end
|
32
|
+
|
33
|
+
aggregator.matcher = @matcher
|
34
|
+
|
35
|
+
tarball_path = aggregator.generate_tarball
|
36
|
+
tarball_size = File.size(tarball_path)
|
37
|
+
|
38
|
+
logger.info("Generated log tarball: #{tarball_path} (size: #{tarball_size})")
|
39
|
+
blobstore_id = upload_tarball(tarball_path)
|
40
|
+
|
41
|
+
{ "blobstore_id" => blobstore_id }
|
42
|
+
|
43
|
+
rescue Bosh::Agent::FileAggregator::DirectoryNotFound => e
|
44
|
+
handler_error("unable to find #{@log_type} logs directory")
|
45
|
+
rescue Bosh::Agent::FileAggregator::Error => e
|
46
|
+
handler_error("error aggregating logs: #{e}")
|
47
|
+
ensure
|
48
|
+
aggregator.cleanup
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def default_matcher
|
54
|
+
case @log_type.to_s
|
55
|
+
when "job"
|
56
|
+
Bosh::Agent::JobLogMatcher.new(base_dir)
|
57
|
+
when "agent"
|
58
|
+
Bosh::Agent::AgentLogMatcher.new(base_dir)
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def filter_globs
|
65
|
+
custom_job_logs = {}
|
66
|
+
|
67
|
+
if @state["job"] && @state["job"]["logs"]
|
68
|
+
logs_spec = @state["job"]["logs"]
|
69
|
+
|
70
|
+
if logs_spec.is_a?(Hash)
|
71
|
+
custom_job_logs = logs_spec
|
72
|
+
else
|
73
|
+
logger.warn("Invalid format for job logs spec: Hash expected, #{logs_spec.class} given")
|
74
|
+
logger.warn("All custom filtering except '--all' thus disabled")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
predefined = { "all" => "**/*" }
|
79
|
+
|
80
|
+
predefined.merge(custom_job_logs).inject([]) do |result, (filter_name, glob)|
|
81
|
+
result << glob if @filters.include?(filter_name)
|
82
|
+
result
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return blobstore id of the uploaded tarball
|
87
|
+
def upload_tarball(path)
|
88
|
+
bsc_options = Bosh::Agent::Config.blobstore_options
|
89
|
+
bsc_provider = Bosh::Agent::Config.blobstore_provider
|
90
|
+
|
91
|
+
blobstore = Bosh::Blobstore::Client.create(bsc_provider, bsc_options)
|
92
|
+
|
93
|
+
logger.info("Uploading tarball to blobstore")
|
94
|
+
|
95
|
+
blobstore_id = nil
|
96
|
+
|
97
|
+
File.open(path) do |f|
|
98
|
+
blobstore_id = blobstore.create(f)
|
99
|
+
end
|
100
|
+
|
101
|
+
blobstore_id
|
102
|
+
rescue Bosh::Blobstore::BlobstoreError => e
|
103
|
+
handler_error("unable to upload logs to blobstore: #{e}")
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'bosh_agent/disk_util'
|
2
|
+
|
3
|
+
module Bosh::Agent
|
4
|
+
module Message
|
5
|
+
|
6
|
+
# Migrates persistent data from the old persistent disk to the new
|
7
|
+
# persistent disk.
|
8
|
+
#
|
9
|
+
# This message assumes that two mount messages have been received
|
10
|
+
# and processed: one to mount the old disk at /var/vcap/store and
|
11
|
+
# a second to mount the new disk at /var/vcap/store_migraton_target
|
12
|
+
# (sic).
|
13
|
+
class MigrateDisk < Base
|
14
|
+
def self.long_running?; true; end
|
15
|
+
|
16
|
+
def self.process(args)
|
17
|
+
#logger = Bosh::Agent::Config.logger
|
18
|
+
#logger.info("MigrateDisk:" + args.inspect)
|
19
|
+
|
20
|
+
self.new.migrate(args)
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
def migrate(args)
|
25
|
+
logger.info("MigrateDisk:" + args.inspect)
|
26
|
+
@old_cid, @new_cid = args
|
27
|
+
|
28
|
+
DiskUtil.umount_guard(store_path)
|
29
|
+
|
30
|
+
mount_store(@old_cid, read_only: true)
|
31
|
+
|
32
|
+
if check_mountpoints
|
33
|
+
logger.info("Copy data from old to new store disk")
|
34
|
+
`(cd #{store_path} && tar cf - .) | (cd #{store_migration_target} && tar xpf -)`
|
35
|
+
end
|
36
|
+
|
37
|
+
DiskUtil.umount_guard(store_path)
|
38
|
+
DiskUtil.umount_guard(store_migration_target)
|
39
|
+
|
40
|
+
mount_store(@new_cid)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def check_mountpoints
|
45
|
+
Pathname.new(store_path).mountpoint? && Pathname.new(store_migration_target).mountpoint?
|
46
|
+
end
|
47
|
+
|
48
|
+
def mount_store(cid, options={})
|
49
|
+
device = Config.platform.lookup_disk_by_cid(cid)
|
50
|
+
partition = "#{device}1"
|
51
|
+
Mounter.new(logger).mount(partition, store_path, options)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|