1

我正在定义我的服务器设置,如下所示:

task :test do
  role(:frontend) {[server1,server2,server3, {:user=> "frontend-user", :options => {:log_location=>"HOW DO I READ THIS??"}}]}
  role(:backend) {...}
  role(:db) {...}
  role(:mq) {...}
end

task :staging do
  role(:frontend) {[server1,server2,server3, {:user=> "frontend-user", :options => {:log_location=>"HOW DO I READ THIS??"}}]}
  role(:backend) {...}
  role(:db) {...}
  role(:mq) {...}
end

task :prod do
  role(:frontend) {[server1,server2,server3, {:user=> "frontend-user", :options => {:log_location=>"HOW DO I READ THIS??"}}]}
  role(:backend) {...}
  role(:db) {...}
  role(:mq) {...}
end

这是为了包含传统企业系统的所有复杂性。

现在,从一项任务中,我想阅读log_location.

任务示例:

namespace :log do
  desc "list all log files"
  task :list do
    run %(ls -1 #{log_location}/*/*.log)
  end
end

问题是变量log_location未定义。

/.rvm/gems/ruby-2.0.0-p0/gems/capistrano-2.14.2/lib/capistrano/configuration/namespaces.rb:193:in method_missing': undefined local variable or methodlog_location' for # (NameError)

  1. 如何访问该变量?
  2. 是否有更智能/更简单的方法来设置此自定义变量?
4

3 回答 3

1

我很抱歉说你看不懂。传递给的块task()不在服务器上下文中执行,因此该块实际上不知道它在哪个服务器上运行。

多年来,经典的解决方法是上传一个看起来像这样的配置文件:

---
  hostname1:
    log_file_location: "/var/log/hostname1/foo/bar"
  hostname2:
    log_file_location: "/var/log/hostname2/foo/bar"

(或类似的)并在加载配置时使用机器主机名。

我知道这不是一个很好的解决方法,因此在即将推出的 Capistrano 版本(参见 Github 的 v3 分支)中,有一个看起来像这样的功能:

host1 = SSHKit::Host.new 'user@example.com'
host2 = SSHKit::Host.new 'user@example.org'

host1.properties = {log_file_location: "/foo/bar"}
host2.properties.log_file_location = "/bar/baz"

on hosts do |host|
  target = "/var/www/sites/"
  if host.hostname =~ /org/
    target += "dotorg"
  else
    target += "dotcom"
  end
  execute! :head, '-n 20', host.properties.log_file_location
  execute! :git, :clone, "git@git.#{host.hostname}", target
end

( SSHKit 示例) -SSHKit是 Capistrano 的新后端驱动程序。

v3 分支可能还没有准备好迎接黄金时间,我们在内部取得了很大的成功,但是文档非常糟糕,根本不存在。然而,该代码实际上是一个数量级不那么强大的命令,我认为您会发现它的可读性很强。

于 2013-03-26T09:13:14.303 回答
0

实际上,我能够提取log_location变量,但最终得到的解决方案有一个限制:

我仅将日志位置用于一种环境。这在我当前的项目中没有问题,因为我一次针对一个角色运行 capistrano 任务。

为了测试这个设置,我做了这个任务:

namespace :support do 
  desc "Test if the log location variable is correctly fetched from configuration"
  task :test_log_location do
    find_servers_for_task(current_task).each do |server|
      # puts server.host
      # puts server.port
      # puts server.user
      # puts server.options
      result = "LOG LOCATION: #{server.options[:log_location]}"
      #puts result
      logger.info result 
    end
  end
end

然后,对于 :log 命名空间中的任务,我定义了变量set :log_location并定义了:current_role变量:

namespace :log do
  def set_log_location 
    #set_log_location
    #puts fetch(:log_location)
    log_location = nil
    options      = nil
    find_servers_for_task(current_task).each do |server|
      # puts server.host
      # puts server.port
      # puts server.user
      # puts server.options
      options = server.options
      log_location = server.options[:log_location]
      #log_location = server.options[:current_role]
    end
    msg1="FATAL: you need to specify 'ROLES=frontend,backend,mq' (or one of them) from command line"
    msg2="FATAL: Could not get log_location from environment/server options. I can only see these options: #{options}"

    raise msg1 if ENV['ROLES'].nil? 
    raise msg2 if log_location.nil?

    set :log_location, log_location
    set :current_role, ENV['ROLES'].split(',').first
    logger.info %(CURRENT_ROLE #{fetch(:current_role)})
    logger.info %(THE LOG LOCATION IS: #{fetch(:log_location)})
  end
end

最后,我使用了一个单独的方法来完全限定日志路径(我的设置需要 - 也在:log命名空间中):

  def log_location
    log_names = {
      :frontend => "*/play.log",
      :backend => "*Weblogic*/*.{log,out}"
    }
    loc = "#{fetch(:log_location)}/#{log_names[fetch(:current_role).to_sym]}"
    logger.info "using the log location of '#{loc}'"
    loc
  end

现在,每个任务都可以像这样使用特定的日志位置:

  desc "list all log files"
  task :list do
    set_log_location
    run %(ls -l #{log_location})
  end

我相信这可以做得更优雅,但它对我有用

于 2013-04-02T20:00:17.670 回答
0

你需要这个:https ://github.com/capistrano/capistrano/wiki/2.x-Multistage-Extension

这意味着您可以将特定于阶段的代码隔离在以阶段命名的单独文件中。如果您想测试共享 deploy.rb 中的阶段名称,您也可以这样做,如下所示:

把它放在你的 deploy.rb

task :show_stage do
   puts(stage)
end

从命令行测试

$ cap staging show_stage
staging
于 2013-03-26T10:45:06.757 回答