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.
Files changed (76) hide show
  1. data/CHANGELOG +0 -0
  2. data/bin/bosh_agent +102 -0
  3. data/lib/bosh_agent/alert.rb +191 -0
  4. data/lib/bosh_agent/alert_processor.rb +96 -0
  5. data/lib/bosh_agent/apply_plan/helpers.rb +30 -0
  6. data/lib/bosh_agent/apply_plan/job.rb +235 -0
  7. data/lib/bosh_agent/apply_plan/package.rb +58 -0
  8. data/lib/bosh_agent/apply_plan/plan.rb +96 -0
  9. data/lib/bosh_agent/bootstrap.rb +341 -0
  10. data/lib/bosh_agent/config.rb +5 -0
  11. data/lib/bosh_agent/configuration.rb +102 -0
  12. data/lib/bosh_agent/disk_util.rb +103 -0
  13. data/lib/bosh_agent/errors.rb +25 -0
  14. data/lib/bosh_agent/ext.rb +48 -0
  15. data/lib/bosh_agent/file_aggregator.rb +78 -0
  16. data/lib/bosh_agent/file_matcher.rb +45 -0
  17. data/lib/bosh_agent/handler.rb +440 -0
  18. data/lib/bosh_agent/heartbeat.rb +74 -0
  19. data/lib/bosh_agent/heartbeat_processor.rb +45 -0
  20. data/lib/bosh_agent/http_handler.rb +135 -0
  21. data/lib/bosh_agent/infrastructure/aws/registry.rb +177 -0
  22. data/lib/bosh_agent/infrastructure/aws/settings.rb +59 -0
  23. data/lib/bosh_agent/infrastructure/aws.rb +17 -0
  24. data/lib/bosh_agent/infrastructure/dummy.rb +24 -0
  25. data/lib/bosh_agent/infrastructure/openstack/registry.rb +220 -0
  26. data/lib/bosh_agent/infrastructure/openstack/settings.rb +76 -0
  27. data/lib/bosh_agent/infrastructure/openstack.rb +17 -0
  28. data/lib/bosh_agent/infrastructure/vsphere/settings.rb +135 -0
  29. data/lib/bosh_agent/infrastructure/vsphere.rb +16 -0
  30. data/lib/bosh_agent/infrastructure.rb +25 -0
  31. data/lib/bosh_agent/message/apply.rb +184 -0
  32. data/lib/bosh_agent/message/base.rb +38 -0
  33. data/lib/bosh_agent/message/compile_package.rb +250 -0
  34. data/lib/bosh_agent/message/drain.rb +195 -0
  35. data/lib/bosh_agent/message/list_disk.rb +25 -0
  36. data/lib/bosh_agent/message/logs.rb +108 -0
  37. data/lib/bosh_agent/message/migrate_disk.rb +55 -0
  38. data/lib/bosh_agent/message/mount_disk.rb +102 -0
  39. data/lib/bosh_agent/message/ssh.rb +109 -0
  40. data/lib/bosh_agent/message/state.rb +47 -0
  41. data/lib/bosh_agent/message/unmount_disk.rb +29 -0
  42. data/lib/bosh_agent/monit.rb +354 -0
  43. data/lib/bosh_agent/monit_client.rb +158 -0
  44. data/lib/bosh_agent/mounter.rb +42 -0
  45. data/lib/bosh_agent/ntp.rb +32 -0
  46. data/lib/bosh_agent/platform/centos/disk.rb +27 -0
  47. data/lib/bosh_agent/platform/centos/network.rb +39 -0
  48. data/lib/bosh_agent/platform/centos/templates/centos-ifcfg.erb +9 -0
  49. data/lib/bosh_agent/platform/centos/templates/dhclient_conf.erb +56 -0
  50. data/lib/bosh_agent/platform/centos/templates/logrotate.erb +8 -0
  51. data/lib/bosh_agent/platform/centos.rb +4 -0
  52. data/lib/bosh_agent/platform/dummy/templates/dummy_template.erb +1 -0
  53. data/lib/bosh_agent/platform/linux/adapter.rb +36 -0
  54. data/lib/bosh_agent/platform/linux/disk.rb +121 -0
  55. data/lib/bosh_agent/platform/linux/logrotate.rb +32 -0
  56. data/lib/bosh_agent/platform/linux/network.rb +124 -0
  57. data/lib/bosh_agent/platform/linux/password.rb +22 -0
  58. data/lib/bosh_agent/platform/linux.rb +4 -0
  59. data/lib/bosh_agent/platform/ubuntu/network.rb +59 -0
  60. data/lib/bosh_agent/platform/ubuntu/templates/dhclient_conf.erb +56 -0
  61. data/lib/bosh_agent/platform/ubuntu/templates/interfaces.erb +14 -0
  62. data/lib/bosh_agent/platform/ubuntu/templates/logrotate.erb +8 -0
  63. data/lib/bosh_agent/platform/ubuntu.rb +4 -0
  64. data/lib/bosh_agent/platform.rb +26 -0
  65. data/lib/bosh_agent/remote_exception.rb +62 -0
  66. data/lib/bosh_agent/runner.rb +36 -0
  67. data/lib/bosh_agent/settings.rb +61 -0
  68. data/lib/bosh_agent/sigar_box.rb +26 -0
  69. data/lib/bosh_agent/smtp_server.rb +96 -0
  70. data/lib/bosh_agent/state.rb +100 -0
  71. data/lib/bosh_agent/syslog_monitor.rb +53 -0
  72. data/lib/bosh_agent/template.rb +50 -0
  73. data/lib/bosh_agent/util.rb +190 -0
  74. data/lib/bosh_agent/version.rb +8 -0
  75. data/lib/bosh_agent.rb +92 -0
  76. 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