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,76 @@
1
+ # Copyright (c) 2009-2013 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ class Infrastructure::Openstack::Settings
5
+
6
+ VIP_NETWORK_TYPE = "vip"
7
+ DHCP_NETWORK_TYPE = "dynamic"
8
+ MANUAL_NETWORK_TYPE = "manual"
9
+
10
+ SUPPORTED_NETWORK_TYPES = [
11
+ VIP_NETWORK_TYPE, DHCP_NETWORK_TYPE, MANUAL_NETWORK_TYPE
12
+ ]
13
+
14
+ ##
15
+ # Returns the logger
16
+ #
17
+ # @return [Logger] Bosh Agent logger
18
+ def logger
19
+ Bosh::Agent::Config.logger
20
+ end
21
+
22
+ ##
23
+ # Loads the the settings for this agent and set ups the public OpenSSH key.
24
+ #
25
+ # @return [Hash] Agent Settings
26
+ def load_settings
27
+ setup_openssh_key
28
+ Infrastructure::Openstack::Registry.get_settings
29
+ end
30
+
31
+ ##
32
+ # Returns the authorized keys filename for the Bosh user.
33
+ #
34
+ # @return [String] authorized keys filename
35
+ def authorized_keys
36
+ File.join(File::SEPARATOR, "home", BOSH_APP_USER, ".ssh", "authorized_keys")
37
+ end
38
+
39
+ ##
40
+ # Retrieves the public OpenSSH key and stores it at the authorized_keys file.
41
+ #
42
+ # @return [void]
43
+ def setup_openssh_key
44
+ public_key = Infrastructure::Openstack::Registry.get_openssh_key
45
+ return if public_key.nil? || public_key.empty?
46
+
47
+ FileUtils.mkdir_p(File.dirname(authorized_keys))
48
+ FileUtils.chmod(0700, File.dirname(authorized_keys))
49
+ FileUtils.chown(Bosh::Agent::BOSH_APP_USER, Bosh::Agent::BOSH_APP_GROUP, File.dirname(authorized_keys))
50
+
51
+ File.open(authorized_keys, "w") { |f| f.write(public_key) }
52
+ FileUtils.chown(Bosh::Agent::BOSH_APP_USER, Bosh::Agent::BOSH_APP_GROUP, authorized_keys)
53
+ FileUtils.chmod(0644, authorized_keys)
54
+ end
55
+
56
+ ##
57
+ # Gets the network settings for this agent.
58
+ #
59
+ # @param [String] network_name Network name
60
+ # @param [Hash] network_properties Network properties
61
+ # @return [Hash] Network settings
62
+ def get_network_settings(network_name, network_properties)
63
+ type = network_properties["type"] || "manual"
64
+ unless type && SUPPORTED_NETWORK_TYPES.include?(type)
65
+ raise Bosh::Agent::StateError, "Unsupported network type '%s', valid types are: %s" %
66
+ [type, SUPPORTED_NETWORK_TYPES.join(", ")]
67
+ end
68
+
69
+ # Nothing to do for "vip" and "manual" networks
70
+ return nil if [VIP_NETWORK_TYPE, MANUAL_NETWORK_TYPE].include? type
71
+
72
+ Bosh::Agent::Util.get_network_info
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ class Infrastructure::Openstack
5
+ require 'bosh_agent/infrastructure/openstack/settings'
6
+ require 'bosh_agent/infrastructure/openstack/registry'
7
+
8
+ def load_settings
9
+ Settings.new.load_settings
10
+ end
11
+
12
+ def get_network_settings(network_name, properties)
13
+ Settings.new.get_network_settings(network_name, properties)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,135 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ class Infrastructure::Vsphere::Settings
5
+ DEFAULT_CDROM_RETRY_WAIT = 0.5
6
+
7
+ attr_accessor :cdrom_retry_wait
8
+
9
+ def initialize
10
+ base_dir = Bosh::Agent::Config.base_dir
11
+ @logger = Bosh::Agent::Config.logger
12
+ @cdrom_retry_wait = DEFAULT_CDROM_RETRY_WAIT
13
+ @cdrom_settings_mount_point = File.join(base_dir, 'bosh', 'settings')
14
+ @cdrom_device = nil
15
+ end
16
+
17
+ def cdrom_device
18
+ unless @cdrom_device
19
+ # only do this when not already done
20
+ cd_drive = File.read("/proc/sys/dev/cdrom/info").slice(/drive name:\s*\S*/).slice(/\S*\z/)
21
+ @cdrom_device = "/dev/#{cd_drive.strip}"
22
+ end
23
+ @cdrom_device
24
+ end
25
+
26
+ def load_settings
27
+ load_cdrom_settings
28
+ end
29
+
30
+ def load_cdrom_settings
31
+ check_cdrom
32
+ create_cdrom_settings_mount_point
33
+ mount_cdrom
34
+
35
+ env_file = File.join(@cdrom_settings_mount_point, 'env')
36
+
37
+ begin
38
+ settings_json = File.read(env_file)
39
+ @settings = Yajl::Parser.new.parse(settings_json)
40
+ rescue
41
+ raise Bosh::Agent::LoadSettingsError, 'Failed to read/write env/settings.json'
42
+ ensure
43
+ umount_cdrom
44
+ eject_cdrom
45
+ end
46
+ @settings
47
+ end
48
+
49
+ def check_cdrom
50
+ # Below we do a number of retries to work around race conditions both
51
+ # when inserting a virtual cdrom in vSphere and how udev handles
52
+ # detection of the new media.
53
+ #
54
+ # Part of what the udev cdrom-id helper will do is to open /dev/cdrom
55
+ # with O_EXCL, which will give us EBUSY - however, the exact timing of
56
+ # this is a little harder - so we retry.
57
+
58
+ # First give the cdrom media a little time to get detected
59
+ 5.times do
60
+ begin
61
+ read_cdrom_byte
62
+ break
63
+ rescue => e
64
+ @logger.info("Waiting for #{cdrom_device} (ENOMEDIUM): #{e.inspect}")
65
+ end
66
+ sleep @cdrom_retry_wait
67
+ end
68
+
69
+ # Second read - invoke udevadmin settle
70
+ begin
71
+ read_cdrom_byte
72
+ rescue => e
73
+ # Do nothing
74
+ ensure
75
+ # udevadm settle default timeout is 120 seconds
76
+ udevadm_settle_out = udevadm_settle
77
+ @logger.info("udevadm: #{udevadm_settle_out}")
78
+ end
79
+
80
+ # Read successfuly from cdrom for 2.5 seconds
81
+ 5.times do
82
+ begin
83
+ read_cdrom_byte
84
+ rescue Errno::EBUSY
85
+ @logger.info("Waiting for udev cdrom-id (EBUSY)")
86
+ # do nothing
87
+ rescue Errno::ENOMEDIUM # 1.8: Errno::E123
88
+ @logger.info("Waiting for #{cdrom_device} (ENOMEDIUM or ENOTBLK)")
89
+ # do nothing
90
+ end
91
+ sleep @cdrom_retry_wait
92
+ end
93
+
94
+ begin
95
+ read_cdrom_byte
96
+ rescue Errno::EBUSY, Errno::ENOMEDIUM # 1.8: Errno::E123
97
+ raise Bosh::Agent::LoadSettingsError, "No bosh cdrom env: #{e.inspect}"
98
+ end
99
+ end
100
+
101
+ def udevadm_settle
102
+ if File.exists? "/sbin/udevadm"
103
+ Bosh::Exec.sh "/sbin/udevadm settle"
104
+ elsif File.exists? "/sbin/udevsettle"
105
+ Bosh::Exec.sh "/sbin/udevsettle"
106
+ else
107
+ raise Bosh::Agent::LoadSettingsError, "No udevsettle"
108
+ end
109
+ end
110
+
111
+ def read_cdrom_byte
112
+ File.read(cdrom_device, 1)
113
+ end
114
+
115
+ def create_cdrom_settings_mount_point
116
+ FileUtils.mkdir_p(@cdrom_settings_mount_point)
117
+ FileUtils.chmod(0700, @cdrom_settings_mount_point)
118
+ end
119
+
120
+ def mount_cdrom
121
+ result = Bosh::Exec.sh "mount #{cdrom_device} #@cdrom_settings_mount_point 2>&1"
122
+ raise Bosh::Agent::LoadSettingsError,
123
+ "Failed to mount settings on #@cdrom_settings_mount_point: #{result.output}" if result.failed?
124
+ end
125
+
126
+ def umount_cdrom
127
+ Bosh::Exec.sh "umount #@cdrom_settings_mount_point 2>&1"
128
+ end
129
+
130
+ def eject_cdrom
131
+ Bosh::Exec.sh "eject #{cdrom_device}"
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ class Infrastructure::Vsphere
5
+ require 'bosh_agent/infrastructure/vsphere/settings'
6
+
7
+ def load_settings
8
+ Settings.new.load_settings
9
+ end
10
+
11
+ def get_network_settings(network_name, properties)
12
+ # Nothing to do
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+ require 'bosh_agent'
3
+
4
+ module Bosh::Agent
5
+ class UnknownInfrastructure < StandardError; end
6
+
7
+ class Infrastructure
8
+
9
+ def initialize(infrastructure_name)
10
+ @name = infrastructure_name
11
+ infrastructure = File.join(File.dirname(__FILE__), 'infrastructure', "#{infrastructure_name}.rb")
12
+
13
+ if File.exist?(infrastructure)
14
+ require infrastructure
15
+ else
16
+ raise UnknownInfrastructure, "infrastructure '#{infrastructure_name}' not found"
17
+ end
18
+ end
19
+
20
+ def infrastructure
21
+ Infrastructure.const_get(@name.capitalize).new
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,184 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ module Message
5
+ class Apply < Base
6
+
7
+ def self.long_running?; true end
8
+
9
+ def self.process(args)
10
+ self.new(args).apply
11
+ end
12
+
13
+ def initialize(args)
14
+ @platform = Bosh::Agent::Config.platform
15
+
16
+ if args.size < 1
17
+ raise ArgumentError, "not enough arguments"
18
+ end
19
+
20
+ @new_spec = args.first
21
+ unless @new_spec.is_a?(Hash)
22
+ raise ArgumentError, "invalid spec, Hash expected, " +
23
+ "#{@new_spec.class} given"
24
+ end
25
+
26
+ # Note: new spec needs to be updated before a plan is
27
+ # created which binds to this new spec
28
+ #
29
+ # Collect network state from the infrastructure
30
+ # - Loop through each network
31
+ # - Get network settings for each network
32
+ if @new_spec["networks"]
33
+ @new_spec["networks"].each do |network, properties|
34
+ infrastructure = Bosh::Agent::Config.infrastructure
35
+ network_settings =
36
+ infrastructure.get_network_settings(network, properties)
37
+ logger.debug("current network settings from VM: #{network_settings.inspect}")
38
+ logger.debug("new network settings to be applied: #{properties.inspect}")
39
+ if network_settings
40
+ @new_spec["networks"][network].merge!(network_settings)
41
+ logger.debug("merged network settings: #{@new_spec["networks"].inspect}")
42
+ end
43
+ end
44
+ end
45
+
46
+ @old_spec = Bosh::Agent::Config.state.to_hash
47
+
48
+ @old_plan = Bosh::Agent::ApplyPlan::Plan.new(@old_spec)
49
+ @new_plan = Bosh::Agent::ApplyPlan::Plan.new(@new_spec)
50
+
51
+ %w(bosh jobs packages monit).each do |dir|
52
+ FileUtils.mkdir_p(File.join(base_dir, dir))
53
+ end
54
+ end
55
+
56
+ def apply
57
+ logger.info("Applying: #{@new_spec.inspect}")
58
+
59
+ if !@old_plan.deployment.empty? &&
60
+ @old_plan.deployment != @new_plan.deployment
61
+ raise Bosh::Agent::MessageHandlerError,
62
+ "attempt to apply #{@new_plan.deployment} " +
63
+ "to #{old_plan.deployment}"
64
+ end
65
+
66
+ # FIXME: tests
67
+ # if @state["configuration_hash"] == @new_spec["configuration_hash"]
68
+ # return @state
69
+ # end
70
+
71
+ if @new_plan.configured?
72
+ begin
73
+ delete_job_monit_files
74
+ apply_job
75
+ apply_packages
76
+ configure_job
77
+ reload_monit
78
+ @platform.update_logging(@new_spec)
79
+ rescue Exception => e
80
+ raise Bosh::Agent::MessageHandlerError,
81
+ "#{e.message}: #{e.backtrace}"
82
+ end
83
+ end
84
+
85
+ # FIXME: assumption right now: if apply succeeds state should be
86
+ # identical with apply spec
87
+ Bosh::Agent::Config.state.write(@new_spec)
88
+ @new_spec
89
+
90
+ rescue Bosh::Agent::StateError => e
91
+ raise Bosh::Agent::MessageHandlerError, e
92
+ end
93
+
94
+ private
95
+
96
+ def delete_job_monit_files
97
+ dir = File.join(base_dir, "monit", "job")
98
+ logger.info("Removing job-specific monit files: #{dir}")
99
+
100
+ # Remove all symlink targets
101
+ Dir.glob(File.join(dir, "*")).each do |f|
102
+ if File.symlink?(f)
103
+ logger.info("Removing monit symlink target file: " +
104
+ "#{File.readlink(f)}")
105
+ FileUtils.rm_rf(File.readlink(f))
106
+ end
107
+ end
108
+
109
+ FileUtils.rm_rf(dir)
110
+ end
111
+
112
+ def apply_job
113
+ if @new_plan.has_jobs?
114
+ @new_plan.install_jobs
115
+ else
116
+ logger.info("No job")
117
+ end
118
+ end
119
+
120
+ def apply_packages
121
+ if @new_plan.has_packages?
122
+ @new_plan.install_packages
123
+ else
124
+ logger.info("No packages")
125
+ end
126
+
127
+ cleanup_packages
128
+ end
129
+
130
+ def configure_job
131
+ if @new_plan.has_jobs?
132
+ @new_plan.configure_jobs
133
+ end
134
+ end
135
+
136
+ # We GC packages - leaving the package union of old spec and new spec
137
+ def cleanup_packages
138
+ delete_old_packages
139
+ delete_old_symlinks
140
+ end
141
+
142
+ def delete_old_packages
143
+ files_to_keep = Set.new
144
+
145
+ (@old_plan.packages + @new_plan.packages).each do |package|
146
+ files_to_keep << package.install_path
147
+ end
148
+
149
+ glob = File.join(base_dir, "data", "packages", "*", "*")
150
+
151
+ Dir[glob].each do |path|
152
+ unless files_to_keep.include?(path)
153
+ logger.info("Removing old package version: #{path}")
154
+ FileUtils.rm_rf(path)
155
+ end
156
+ end
157
+ end
158
+
159
+ def delete_old_symlinks
160
+ files_to_keep = Set.new
161
+
162
+ (@old_plan.packages + @new_plan.packages).each do |package|
163
+ files_to_keep << package.link_path
164
+ end
165
+
166
+ glob = File.join(base_dir, "packages", "*")
167
+
168
+ Dir[glob].each do |path|
169
+ unless files_to_keep.include?(path)
170
+ logger.info("Removing old package link: #{path}")
171
+ FileUtils.rm_rf(path)
172
+ end
173
+ end
174
+ end
175
+
176
+ def reload_monit
177
+ if Bosh::Agent::Config.configure
178
+ Bosh::Agent::Monit.reload
179
+ end
180
+ end
181
+
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Agent
4
+ module Message
5
+ class Base
6
+
7
+ def logger
8
+ Bosh::Agent::Config.logger
9
+ end
10
+
11
+ def base_dir
12
+ Bosh::Agent::Config.base_dir
13
+ end
14
+
15
+ def logs_dir
16
+ File.join(base_dir, "sys", "log")
17
+ end
18
+
19
+ def settings
20
+ Bosh::Agent::Config.settings
21
+ end
22
+
23
+ def store_path
24
+ File.join(base_dir, 'store')
25
+ end
26
+
27
+ def store_migration_target
28
+ File.join(base_dir, 'store_migraton_target')
29
+ end
30
+
31
+ def handler_error(message)
32
+ logger.error("Handler error: #{message}")
33
+ raise Bosh::Agent::MessageHandlerError, message
34
+ end
35
+
36
+ end
37
+ end
38
+ end