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,58 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ module ApplyPlan
5
+ class Package
6
+
7
+ class InstallationError < StandardError; end
8
+
9
+ include ApplyPlan::Helpers
10
+
11
+ attr_reader :install_path
12
+ attr_reader :link_path
13
+
14
+ def initialize(spec)
15
+ validate_spec(spec)
16
+
17
+ @base_dir = Bosh::Agent::Config.base_dir
18
+ @name = spec['name']
19
+ @version = spec['version']
20
+ @checksum = spec['sha1']
21
+ @blobstore_id = spec['blobstore_id']
22
+
23
+ @install_path = File.join(@base_dir, 'data', 'packages',
24
+ @name, @version)
25
+ @link_path = File.join(@base_dir, 'packages', @name)
26
+ end
27
+
28
+ def install_for_job(job)
29
+ unless @installed_for_sys
30
+ fetch_bits
31
+ @installed_for_sys = true
32
+ end
33
+ create_symlink_in_job(job) if job
34
+ rescue SystemCallError => e
35
+ install_failed("System call error: #{e.message}")
36
+ end
37
+
38
+ private
39
+
40
+ def create_symlink_in_job(job)
41
+ symlink_path = symlink_path_in_job(job)
42
+ FileUtils.mkdir_p(File.dirname(symlink_path))
43
+
44
+ Bosh::Agent::Util.create_symlink(@install_path, symlink_path)
45
+ end
46
+
47
+ def symlink_path_in_job(job)
48
+ File.join(job.install_path, 'packages', @name)
49
+ end
50
+
51
+ def install_failed(message)
52
+ raise InstallationError, 'Failed to install package ' +
53
+ "'#{@name}': #{message}"
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,96 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ module ApplyPlan
5
+ class Plan
6
+
7
+ attr_reader :deployment
8
+ attr_reader :jobs
9
+ attr_reader :packages
10
+
11
+ def initialize(spec)
12
+ unless spec.is_a?(Hash)
13
+ raise ArgumentError, "Invalid spec format, Hash expected, " +
14
+ "#{spec.class} given"
15
+ end
16
+
17
+ @spec = spec
18
+ @deployment = spec["deployment"]
19
+ @jobs = []
20
+ @packages = []
21
+ @config_binding = Bosh::Agent::Util.config_binding(spec)
22
+
23
+ job_spec = spec["job"]
24
+ package_specs = spec["packages"]
25
+
26
+ # By default stemcell VM has '' as job
27
+ # in state.yml, handling this very special case
28
+ if job_spec && job_spec != ""
29
+ job_name = job_spec["name"]
30
+ if is_legacy_spec?(job_spec)
31
+ @jobs << Job.new(job_name, job_spec["template"], job_spec,
32
+ @config_binding)
33
+ else
34
+ job_spec["templates"].each do |template_spec|
35
+ @jobs << Job.new(job_name, template_spec["name"], template_spec,
36
+ @config_binding)
37
+ end
38
+ end
39
+ end
40
+
41
+ if package_specs
42
+ unless package_specs.is_a?(Hash)
43
+ raise ArgumentError, "Invalid package specs format " +
44
+ "in apply spec, Hash expected " +
45
+ "#{package_specs.class} given"
46
+ end
47
+
48
+ package_specs.each_pair do |package_name, package_spec|
49
+ @packages << Package.new(package_spec)
50
+ end
51
+ end
52
+ end
53
+
54
+ def is_legacy_spec?(job_spec)
55
+ return job_spec["template"] && !job_spec["templates"]
56
+ end
57
+
58
+ def has_jobs?
59
+ !@jobs.empty?
60
+ end
61
+
62
+ def has_packages?
63
+ !@packages.empty?
64
+ end
65
+
66
+ def configured?
67
+ @spec.key?("configuration_hash")
68
+ end
69
+
70
+ def install_jobs
71
+ @jobs.each do |job|
72
+ job.install
73
+ end
74
+ end
75
+
76
+ def install_packages
77
+ @jobs.each do |job|
78
+ @packages.each do |package|
79
+ package.install_for_job(job)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Configure the 1+ job templates (job colocation)
85
+ # They are reversed for the purposes of ensuring monit
86
+ # starts them in the order that they are specified
87
+ # in the original deployment manifest
88
+ def configure_jobs
89
+ @jobs.reverse.each_with_index do |job, job_index|
90
+ job.configure(job_index)
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,341 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require 'rexml/document'
4
+ require 'netaddr'
5
+ require 'erb'
6
+ require 'tempfile'
7
+ require 'fileutils'
8
+ require 'pathname'
9
+ require 'openssl'
10
+
11
+ module Bosh::Agent
12
+ class Bootstrap
13
+ include Bosh::Exec
14
+
15
+ def initialize
16
+ FileUtils.mkdir_p(File.join(base_dir, 'bosh'))
17
+ @platform = Bosh::Agent::Config.platform
18
+ end
19
+
20
+ def logger
21
+ Bosh::Agent::Config.logger
22
+ end
23
+
24
+ def base_dir
25
+ Bosh::Agent::Config.base_dir
26
+ end
27
+
28
+ def store_path
29
+ File.join(base_dir, 'store')
30
+ end
31
+
32
+ def configure
33
+ logger.info("Configuring instance")
34
+
35
+ load_settings
36
+ logger.info("Loaded settings: #{@settings.inspect}")
37
+
38
+ if @settings
39
+ update_iptables
40
+ update_passwords
41
+ update_agent_id
42
+ update_credentials
43
+ update_hostname
44
+ update_mbus
45
+ update_blobstore
46
+ setup_networking
47
+ update_time
48
+ setup_data_disk
49
+ setup_tmp
50
+
51
+ Bosh::Agent::Monit.setup_monit_user
52
+ Bosh::Agent::Monit.setup_alerts
53
+
54
+ mount_persistent_disk
55
+ harden_permissions
56
+ end
57
+ { "settings" => @settings }
58
+ end
59
+
60
+ def load_settings
61
+ @settings = Bosh::Agent::Settings.load
62
+ Bosh::Agent::Config.settings = @settings
63
+ end
64
+
65
+ def iptables(cmd)
66
+ output = %x{iptables #{cmd} 2> /dev/null}
67
+ if $?.exitstatus != 0
68
+ raise Bosh::Agent::Error, "`iptables #{cmd}` failed"
69
+ end
70
+ output
71
+ end
72
+
73
+ def update_iptables
74
+ return unless rules = @settings['iptables']
75
+
76
+ if rules["drop_output"]
77
+ chain = "agent-filter"
78
+ append_chain = "-A OUTPUT -j #{chain}"
79
+
80
+ begin
81
+ iptables("-N #{chain}")
82
+ rescue
83
+ iptables("-F #{chain}")
84
+ end
85
+
86
+ unless iptables("-S").include?(append_chain)
87
+ iptables(append_chain)
88
+ end
89
+
90
+ rules["drop_output"].each do |dest|
91
+ rule = "-A #{chain} -d #{dest} -m owner ! --uid-owner root -j DROP"
92
+ iptables(rule)
93
+ end
94
+ end
95
+ end
96
+
97
+ def update_passwords
98
+ @platform.update_passwords(@settings) unless @settings["env"].nil?
99
+ end
100
+
101
+ def update_agent_id
102
+ Bosh::Agent::Config.agent_id = @settings["agent_id"]
103
+ end
104
+
105
+ def update_credentials
106
+ env = @settings["env"]
107
+ if env && bosh_env = env["bosh"]
108
+ if bosh_env["credentials"]
109
+ Bosh::Agent::Config.credentials = bosh_env["credentials"]
110
+ end
111
+ end
112
+ end
113
+
114
+ def update_hostname
115
+ agent_id = @settings['agent_id']
116
+
117
+ template = ERB.new(ETC_HOST_TEMPLATE, 0, '%<>-')
118
+ result = template.result(binding)
119
+ File.open('/etc/hosts', 'w') { |f| f.puts(result) }
120
+
121
+ `hostname #{agent_id}`
122
+ File.open('/etc/hostname', 'w') { |f| f.puts(agent_id) }
123
+ end
124
+
125
+ def update_mbus
126
+ Bosh::Agent::Config.mbus = @settings['mbus']
127
+ end
128
+
129
+ def update_blobstore
130
+ blobstore_settings = @settings["blobstore"]
131
+
132
+ blobstore_provider = blobstore_settings["provider"]
133
+ blobstore_options = blobstore_settings["options"]
134
+
135
+ Bosh::Agent::Config.blobstore_provider = blobstore_provider
136
+ Bosh::Agent::Config.blobstore_options.merge!(blobstore_options)
137
+ end
138
+
139
+ def setup_networking
140
+ Bosh::Agent::Config.platform.setup_networking
141
+ end
142
+
143
+ def update_time
144
+ ntp_servers = @settings['ntp'].join(" ")
145
+ unless ntp_servers.empty?
146
+ logger.info("Configure ntp-servers: #{ntp_servers}")
147
+ Bosh::Agent::Util.update_file(ntp_servers, '/var/vcap/bosh/etc/ntpserver')
148
+ output = `ntpdate #{ntp_servers}`
149
+ logger.info(output)
150
+ else
151
+ logger.warn("no ntp-servers configured")
152
+ end
153
+ end
154
+
155
+ def setup_data_disk
156
+ data_mount = File.join(base_dir, "data")
157
+ FileUtils.mkdir_p(data_mount)
158
+
159
+ data_disk = Bosh::Agent::Config.platform.get_data_disk_device_name
160
+ if data_disk
161
+ unless File.blockdev?(data_disk)
162
+ logger.warn("Data disk is not a block device: #{data_disk}")
163
+ return
164
+ end
165
+
166
+ swap_partition = "#{data_disk}1"
167
+ data_partition = "#{data_disk}2"
168
+
169
+ swap_turned_on = sh("cat /proc/swaps | grep #{swap_partition}", :on_error => :return).success?
170
+ data_partition_mounted = sh("mount | grep #{data_partition}", :on_error => :return).success?
171
+
172
+ if Dir.glob("#{data_disk}[1-2]").empty?
173
+ logger.info("Found unformatted drive")
174
+ logger.info("Partition #{data_disk}")
175
+ Bosh::Agent::Util.partition_disk(data_disk, data_sfdisk_input)
176
+
177
+ logger.info("Create swap and data partitions")
178
+ sh "mkswap #{swap_partition}"
179
+
180
+ mke2fs_options = ["-t ext4", "-j"]
181
+ mke2fs_options << "-E lazy_itable_init=1" if Bosh::Agent::Util.lazy_itable_init_enabled?
182
+ sh "/sbin/mke2fs #{mke2fs_options.join(" ")} #{data_partition}"
183
+ end
184
+
185
+ unless swap_turned_on
186
+ logger.info("Swapon partition #{swap_partition}")
187
+ sh "swapon #{swap_partition}"
188
+ end
189
+
190
+ unless data_partition_mounted
191
+ unless Pathname.new(data_mount).mountpoint?
192
+ logger.info("Mount data partition #{data_partition} to #{data_mount}")
193
+ sh "mount #{data_partition} #{data_mount}"
194
+ end
195
+ end
196
+ end
197
+
198
+ setup_data_sys
199
+ end
200
+
201
+ def data_sfdisk_input
202
+ ",#{swap_size},S\n,,L\n"
203
+ end
204
+
205
+ def swap_size
206
+ data_disk = Bosh::Agent::Config.platform.get_data_disk_device_name
207
+ disk_size = Util.block_device_size(data_disk)
208
+ if mem_total > disk_size/2
209
+ return (disk_size/2)/1024
210
+ else
211
+ return mem_total/1024
212
+ end
213
+ end
214
+
215
+ def mem_total
216
+ # MemTotal: 3952180 kB
217
+ File.readlines('/proc/meminfo').first.split(/\s+/)[1].to_i
218
+ end
219
+
220
+ def setup_data_sys
221
+ %w{log run}.each do |dir|
222
+ path = "#{base_dir}/data/sys/#{dir}"
223
+ %x[mkdir -p #{path}]
224
+ %x[chown root:vcap #{path}]
225
+ %x[chmod 0750 #{path}]
226
+ end
227
+ %x[ln -nsf #{base_dir}/data/sys #{base_dir}/sys]
228
+ end
229
+
230
+ def setup_tmp
231
+ # use a custom TMPDIR for agent itself
232
+ agent_tmp_dir = File.join(base_dir, 'data', 'tmp')
233
+ FileUtils.mkdir_p(agent_tmp_dir)
234
+ ENV["TMPDIR"] = agent_tmp_dir
235
+
236
+ # first time: for /tmp on the root fs
237
+ tmp_permissions
238
+
239
+ unless Pathname.new('/tmp').mountpoint?
240
+ tmp_size = 128
241
+ root_tmp = File.join(base_dir, 'data', 'root_tmp')
242
+
243
+ # If it's not mounted on /tmp - we don't care - blow it away
244
+ %x[/usr/bin/truncate -s #{tmp_size}M #{root_tmp}]
245
+ %x[chmod 0700 #{root_tmp}]
246
+ %x[mke2fs -t ext4 -m 1 -F #{root_tmp}]
247
+
248
+ %x[mount -t ext4 -o loop #{root_tmp} /tmp]
249
+
250
+ # 2nd time for the new /tmp mount
251
+ tmp_permissions
252
+ end
253
+ end
254
+
255
+ def tmp_permissions
256
+ %x[chown root:#{BOSH_APP_USER} /tmp]
257
+ %x[chmod 0770 /tmp]
258
+ %x[chmod 0700 /var/tmp]
259
+ end
260
+
261
+ def mount_persistent_disk
262
+ if @settings['disks']['persistent'].keys.size > 1
263
+ # hell on earth
264
+ raise Bosh::Agent::FatalError, "Fatal: more than one persistent disk on boot"
265
+ else
266
+ cid = @settings['disks']['persistent'].keys.first
267
+ if cid
268
+ Bosh::Agent::Config.platform.mount_persistent_disk(cid)
269
+ end
270
+ end
271
+ end
272
+
273
+ def harden_permissions
274
+ setup_cron_at_allow
275
+
276
+ # use this instead of removing vcap from the cdrom group, as there
277
+ # is no way to easily do that from the command line
278
+ root_only_rw = %w{
279
+ /dev/sr0
280
+ }
281
+ root_only_rw.each do |path|
282
+ %x[chmod 0660 #{path}]
283
+ %x[chown root:root #{path}]
284
+ end
285
+
286
+ root_app_user_rw = %w{
287
+ /dev/log
288
+ }
289
+ root_app_user_rw.each do |path|
290
+ %x[chmod 0660 #{path}]
291
+ %x[chown root:#{BOSH_APP_USER} #{path}]
292
+ end
293
+
294
+ root_app_user_rwx = %w{
295
+ /dev/shm
296
+ /var/lock
297
+ }
298
+ root_app_user_rwx.each do |path|
299
+ %x[chmod 0770 #{path}]
300
+ %x[chown root:#{BOSH_APP_USER} #{path}]
301
+ end
302
+
303
+ root_rw_app_user_read = %w{
304
+ /etc/cron.allow
305
+ /etc/at.allow
306
+ }
307
+ root_rw_app_user_read.each do |path|
308
+ %x[chmod 0640 #{path}]
309
+ %x[chown root:#{BOSH_APP_USER} #{path}]
310
+ end
311
+
312
+ no_other_read = %w{
313
+ /data/vcap/data
314
+ /data/vcap/store
315
+ }
316
+ no_other_read.each do |path|
317
+ %[chmod o-r #{path}]
318
+ end
319
+
320
+ end
321
+
322
+ def setup_cron_at_allow
323
+ %w{/etc/cron.allow /etc/at.allow}.each do |file|
324
+ File.open(file, 'w') { |fh| fh.puts(BOSH_APP_USER) }
325
+ end
326
+ end
327
+
328
+ ETC_HOST_TEMPLATE = <<TEMPLATE
329
+ 127.0.0.1 localhost <%= agent_id %>
330
+
331
+ # The following lines are desirable for IPv6 capable hosts
332
+ ::1 localhost ip6-localhost ip6-loopback <%= agent_id %>
333
+ fe00::0 ip6-localnet
334
+ ff00::0 ip6-mcastprefix
335
+ ff02::1 ip6-allnodes
336
+ ff02::2 ip6-allrouters
337
+ ff02::3 ip6-allhosts
338
+ TEMPLATE
339
+
340
+ end
341
+ end
@@ -0,0 +1,5 @@
1
+ require 'bosh_agent/configuration'
2
+
3
+ module Bosh::Agent
4
+ Config = Configuration.new
5
+ end
@@ -0,0 +1,102 @@
1
+ module Bosh::Agent
2
+ class Configuration
3
+ DEFAULT_BASE_DIR = '/var/vcap'
4
+ CONFIG_OPTIONS = [
5
+ :base_dir,
6
+ :logger,
7
+ :mbus,
8
+ :agent_id,
9
+ :configure,
10
+ :blobstore,
11
+ :blobstore_provider,
12
+ :blobstore_options,
13
+ :system_root,
14
+ :infrastructure_name,
15
+ :platform_name,
16
+ :nats,
17
+ :process_alerts,
18
+ :smtp_port,
19
+ :smtp_user,
20
+ :smtp_password,
21
+ :heartbeat_interval,
22
+ :settings_file,
23
+ :settings,
24
+ :state,
25
+ :credentials
26
+ ]
27
+
28
+ CONFIG_OPTIONS.each do |option|
29
+ attr_accessor option
30
+ end
31
+
32
+ def clear
33
+ CONFIG_OPTIONS.each do |option|
34
+ send("#{option}=", nil)
35
+ end
36
+ end
37
+
38
+ def setup(config)
39
+ @configure = config['configure']
40
+
41
+ # it is the responsibillity of the caller to make sure the dir exist
42
+ logging_config = config.fetch('logging', {})
43
+ @logger = Logger.new(logging_config.fetch('file', STDOUT))
44
+ @logger.level = Logger.const_get(logging_config.fetch('level', 'info').upcase)
45
+
46
+ @base_dir = config['base_dir'] || DEFAULT_BASE_DIR
47
+ @agent_id = config['agent_id']
48
+
49
+ @mbus = config['mbus']
50
+
51
+ @blobstore_options = config['blobstore_options']
52
+ @blobstore_provider = config['blobstore_provider']
53
+
54
+ @infrastructure_name = config['infrastructure_name']
55
+ @platform_name = config['platform_name']
56
+
57
+ @system_root = config['root_dir'] || '/'
58
+
59
+ @process_alerts = config['process_alerts']
60
+ @smtp_port = config['smtp_port']
61
+ @smtp_user = 'vcap'
62
+ @smtp_password = random_password(8)
63
+
64
+ @heartbeat_interval = config['heartbeat_interval']
65
+
66
+ unless @configure
67
+ @logger.info("Configuring Agent with: #{config.inspect}")
68
+ end
69
+
70
+ @settings_file = File.join(@base_dir, 'bosh', 'settings.json')
71
+
72
+ @credentials = config['credentials']
73
+
74
+ @settings = {}
75
+
76
+ @state = State.new(File.join(@base_dir, 'bosh', 'state.yml'))
77
+ end
78
+
79
+ def infrastructure
80
+ @infrastructure ||= Bosh::Agent::Infrastructure.new(@infrastructure_name).infrastructure
81
+ end
82
+
83
+ def platform
84
+ @platform ||= Bosh::Agent::Platform.platform(@platform_name)
85
+ end
86
+
87
+ def random_password(len)
88
+ OpenSSL::Random.random_bytes(len).unpack('H*')[0]
89
+ end
90
+
91
+ def default_ip
92
+ ip = nil
93
+ @state['networks'].each do |k, v|
94
+ ip = v['ip'] if ip.nil?
95
+ if v.key?('default')
96
+ ip = v['ip']
97
+ end
98
+ end
99
+ ip
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,103 @@
1
+ module Bosh::Agent
2
+ class DiskUtil
3
+ class << self
4
+ def logger
5
+ Bosh::Agent::Config.logger
6
+ end
7
+
8
+ def base_dir
9
+ Bosh::Agent::Config.base_dir
10
+ end
11
+
12
+ def mount_entry(partition)
13
+ File.read('/proc/mounts').lines.select { |l| l.match(/#{partition}/) }.first
14
+ end
15
+
16
+ GUARD_RETRIES = 600
17
+ GUARD_SLEEP = 1
18
+
19
+ def umount_guard(mountpoint)
20
+ umount_attempts = GUARD_RETRIES
21
+
22
+ loop do
23
+ umount_output = `umount #{mountpoint} 2>&1`
24
+
25
+ if $?.exitstatus == 0
26
+ break
27
+ elsif umount_attempts != 0 && umount_output =~ /device is busy/
28
+ #when umount2 syscall fails and errno == EBUSY, umount.c outputs:
29
+ # "umount: %s: device is busy.\n"
30
+ sleep GUARD_SLEEP
31
+ umount_attempts -= 1
32
+ else
33
+ raise Bosh::Agent::MessageHandlerError,
34
+ "Failed to umount #{mountpoint}: #{umount_output}"
35
+ end
36
+ end
37
+
38
+ attempts = GUARD_RETRIES - umount_attempts
39
+ logger.info("umount_guard #{mountpoint} succeeded (#{attempts})")
40
+ end
41
+
42
+ # Pay a penalty on this check the first time a persistent disk is added to a system
43
+ def ensure_no_partition?(disk, partition)
44
+ check_count = 2
45
+ check_count.times do
46
+ if sfdisk_lookup_partition(disk, partition).empty?
47
+ # keep on trying
48
+ else
49
+ if File.blockdev?(partition)
50
+ return false # break early if partition is there
51
+ end
52
+ end
53
+ sleep 1
54
+ end
55
+
56
+ # Double check that the /dev entry is there
57
+ if File.blockdev?(partition)
58
+ return false
59
+ else
60
+ return true
61
+ end
62
+ end
63
+
64
+ def sfdisk_lookup_partition(disk, partition)
65
+ `sfdisk -Llq #{disk}`.lines.select { |l| l.match(%q{/\A#{partition}.*83.*Linux}) }
66
+ end
67
+
68
+ def get_usage
69
+ usage = {
70
+ system: fs_usage_safe('/')
71
+ }
72
+ ephemeral_percent = fs_usage_safe(File.join(base_dir, 'data'))
73
+ usage[:ephemeral] = ephemeral_percent if ephemeral_percent
74
+ persistent_percent = fs_usage_safe(File.join(base_dir, 'store'))
75
+ usage[:persistent] = persistent_percent if persistent_percent
76
+
77
+ usage
78
+ end
79
+
80
+ private
81
+ # Calculate file_system_usage
82
+ def fs_usage_safe(path)
83
+ sigar = SigarBox.create_sigar
84
+ fs_list = sigar.file_system_list
85
+
86
+ fs = fs_list.find {|fs| fs.dir_name == path}
87
+ return unless fs
88
+
89
+ usage = sigar.file_system_usage(path)
90
+ space_usage_percent = (usage.use_percent * 100)
91
+
92
+ # inode pct calculation taken from 'df' src
93
+ # http://lingrok.org/xref/coreutils/src/df.c
94
+ inode_total = usage.files
95
+ inode_used_100 = (inode_total - usage.free_files) * 100
96
+ inode_usage_percent = inode_used_100 / inode_total + (inode_used_100 % inode_total != 0 ? 1 : 0)
97
+
98
+ { percent: space_usage_percent.to_i.to_s, inode_percent: inode_usage_percent.to_i.to_s }
99
+ end
100
+
101
+ end
102
+ end
103
+ end