我們會通過bin/vcap_dev start命令來啓動所有的cf組件,當然,也可以指定某些組件,比如bin/vcap_dev start health_manager。
下面大致研究下流程。
1. vcap_dev文件
首先是vcap_dev文件,前面主要處理了命令參數以及路徑等問題。最後可以看到
exec_cmd("#{ruby_binary} #{vcap_launch} #{command} #{vcap_components["components"].join(" ")} -c #{deployment_config_path} -v #{vcap_path} -l #{deployment_info["deployment_log_path"]}")
exec_cmd意思就是執行cmd,而ruby_binary是ruby,vcap_launch就是和vcap_dev同位置的vcap文件,後面的command就是我們的啓動指令start,當然可能是stop,restart之類的。
2. vcap文件
所以我們就可以跑去vcap文件看個究竟了。
因爲本文研究start,所以直接看vcap文件的start函數:
def start
if !running?
pid = fork do
# Capture STDOUT when no log file is configured
if !log_file?
stdout = File.open(log_file, 'a')
stdout.truncate(0)
STDOUT.reopen(stdout)
stderr = File.open(log_file, 'a')
STDERR.reopen(stderr)
end
# Make sure db is setup, this is slow and we should make it faster, but
# should help for now.
if is_cloud_controller?
cc_dir = File.expand_path(File.join(DIR, '..', 'cloud_controller'))
Dir.chdir(cc_dir) { `bundle exec rake db:migrate` }
end
exec("#{component_start_path}")
end
Process.detach(pid)
start = Time.now
while ((Time.now - start) < 20)
break if running?
sleep (0.25)
end
end
status
if !running?
if File.exists?(log_file)
log = File.read(log_file)
STDERR.puts "LOG:\n #{log}" if !log.empty?
end
end
end
其他的不理會,重點語句是exec("#{component_start_path}"),當然cc還需要做一個db migrate。那麼我們看component_start_path,這也是個函數。這個函數所做的事情就是跑去vcap的相應目錄下面,然後執行bin目錄下的同名文件。以health manager爲例,它執行vcap/bin/health_manager文件,同時以-c傳入.deployment/devbox/config下面的health_manager.yml文件。那麼vcap_dev
start任務就交接完成了,接下來由bin下面的腳本執行了。
這裏的vcap路徑下有bin目錄,而vcap/health manager下面也有bin,vcap腳本調用的是vcap下的bin。之前搞錯了。那麼看health manager的bin腳本:
exec(File.expand_path("../../health_manager/bin/health_manager", __FILE__), *ARGV)
他就直接調用vcap/health_manager/bin/health_manager腳本了
3. bin腳本
然後我們看看bin下面的腳本都在做什麼:
home = File.join(File.dirname(__FILE__), '/..')
ENV['BUNDLE_GEMFILE'] = "#{home}/Gemfile"
require File.join(home, 'lib/health_manager')
很簡單,就是設置了bundle gemfile的環境變量,然後指向lib下的health_manager文件。Lib下的health_manager.rb主要有三個部分,第一個部分是module CloudController,用來添加非常多的依賴(require),目前不清楚這麼做的意義。第二部分是HealthManager類,那就不提了。重要的是第三部分,也就是文檔末尾的一些代碼:
if $0 == __FILE__ || File.expand_path($0) == File.expand_path(File.join(File.dirname(__FILE__), '../bin/health_manager'))
config_path = ENV["CLOUD_FOUNDRY_CONFIG_PATH"] || File.join(File.dirname(__FILE__), '../config')
config_file = File.join(config_path, "health_manager.yml")
options = OptionParser.new do |opts|
opts.banner = 'Usage: healthmanager [OPTIONS]'
opts.on("-c", "--config [ARG]", "Configuration File") do |opt|
config_file = opt
end
opts.on("-h", "--help", "Help") do
puts opts
exit
end
end
options.parse!(ARGV.dup)
begin
config = YAML.load_file(config_file)
rescue => e
$stderr.puts "Could not read configuration file: #{e}"
exit 1
end
EM.epoll
EM.run { HealthManager.start(config) }
end
首先去讀config file,然後解析了options參數,我們知道bin腳本已經傳入了-c參數,所以在options解析中,config會覆蓋掉。在讀取config之後,就使用Event Machine啓動HealthManager了。EM.epoll是一個linux下的調用命令,對我們沒有意義。EM.run就是我們要看的,可以看到這裏只調用了HealthManager.start函數。後面就不再深入了,大致的流程就是完成配置,然後開啓NATS,訂閱NATS事件,然後發送NATS消息。
總結一下:vcap_dev和vcap腳本都用來處理安裝之後的啓動停止等任務,他們會調用vcap/bin目錄下對應的腳本,而這些腳本又會去相應組件的目錄下執行更爲詳細的任務