mirror of
https://github.com/fluent/fluentd-ui.git
synced 2025-08-16 03:07:06 +02:00
Merge pull request #16 from treasure-data/redesign_fluentd_management
[wip] fix up fluentd process management
This commit is contained in:
commit
94e1f7fd39
@ -5,7 +5,7 @@ PATH
|
|||||||
bcrypt (~> 3.1.5)
|
bcrypt (~> 3.1.5)
|
||||||
bundler (~> 1.5)
|
bundler (~> 1.5)
|
||||||
coffee-rails (~> 4.0.0)
|
coffee-rails (~> 4.0.0)
|
||||||
fluentd (= 0.10.46)
|
fluentd (~> 0.10.48)
|
||||||
font-awesome-rails
|
font-awesome-rails
|
||||||
haml-rails (~> 0.5.3)
|
haml-rails (~> 0.5.3)
|
||||||
httpclient
|
httpclient
|
||||||
@ -81,14 +81,14 @@ GEM
|
|||||||
factory_girl_rails (4.4.1)
|
factory_girl_rails (4.4.1)
|
||||||
factory_girl (~> 4.4.0)
|
factory_girl (~> 4.4.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
fluentd (0.10.46)
|
fluentd (0.10.48)
|
||||||
cool.io (>= 1.1.1, < 2.0.0, != 1.2.0)
|
cool.io (>= 1.1.1, < 2.0.0, != 1.2.0)
|
||||||
http_parser.rb (>= 0.5.1, < 0.7.0)
|
http_parser.rb (>= 0.5.1, < 0.7.0)
|
||||||
json (>= 1.4.3)
|
json (>= 1.4.3)
|
||||||
msgpack (>= 0.4.4, < 0.6.0, != 0.5.3, != 0.5.2, != 0.5.1, != 0.5.0)
|
msgpack (>= 0.4.4, < 0.6.0, != 0.5.3, != 0.5.2, != 0.5.1, != 0.5.0)
|
||||||
sigdump (~> 0.2.2)
|
sigdump (~> 0.2.2)
|
||||||
yajl-ruby (~> 1.0)
|
yajl-ruby (~> 1.0)
|
||||||
font-awesome-rails (4.0.3.1)
|
font-awesome-rails (4.1.0.0)
|
||||||
railties (>= 3.2, < 5.0)
|
railties (>= 3.2, < 5.0)
|
||||||
haml (4.0.5)
|
haml (4.0.5)
|
||||||
tilt
|
tilt
|
||||||
|
37
app/controllers/fluentd/agents_controller.rb
Normal file
37
app/controllers/fluentd/agents_controller.rb
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
class Fluentd::AgentsController < ApplicationController
|
||||||
|
before_action :find_fluentd
|
||||||
|
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
unless @fluentd.agent.start
|
||||||
|
flash[:error] = t("error.fluentd_start_failed")
|
||||||
|
end
|
||||||
|
redirect_to fluentd_agent_path(@fluentd), status: 303 # 303 is change HTTP Verb GET
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
unless @fluentd.agent.stop
|
||||||
|
flash[:error] = t("error.fluentd_stop_failed")
|
||||||
|
end
|
||||||
|
redirect_to fluentd_agent_path(@fluentd), status: 303 # 303 is change HTTP Verb GET
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
unless @fluentd.agent.restart
|
||||||
|
flash[:error] = t("error.fluentd_restart_failed")
|
||||||
|
end
|
||||||
|
redirect_to fluentd_agent_path(@fluentd), status: 303 # 303 is change HTTP Verb GET
|
||||||
|
end
|
||||||
|
|
||||||
|
def log
|
||||||
|
render text: @fluentd.agent.log, content_type: "text/plain"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_fluentd
|
||||||
|
@fluentd = Fluentd.find(params[:fluentd_id])
|
||||||
|
end
|
||||||
|
end
|
@ -1,32 +0,0 @@
|
|||||||
class Fluentd::DaemonsController < ApplicationController
|
|
||||||
before_action :login_required
|
|
||||||
before_action :fluentd
|
|
||||||
|
|
||||||
def show
|
|
||||||
end
|
|
||||||
|
|
||||||
def start
|
|
||||||
fluentd.start
|
|
||||||
render :show
|
|
||||||
end
|
|
||||||
|
|
||||||
def stop
|
|
||||||
fluentd.stop
|
|
||||||
render :show
|
|
||||||
end
|
|
||||||
|
|
||||||
def reload
|
|
||||||
fluentd.reload
|
|
||||||
render :show
|
|
||||||
end
|
|
||||||
|
|
||||||
def log
|
|
||||||
render text: fluentd.log, content_type: "text/plain"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def fluentd
|
|
||||||
@fluentd ||= Fluentd.new(Rails.root + "tmp" + "fluentd") # TODO
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,7 +1,47 @@
|
|||||||
class FluentdController < ApplicationController
|
class FluentdController < ApplicationController
|
||||||
before_action :login_required
|
before_action :find_fluentd, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@daemons = [Fluentd.new(Rails.root + "tmp" + "fluentd")] # TODO
|
@fluentds = Fluentd.all
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@fluentd = Fluentd.new(Fluentd::Agent::Fluentd::DEFAULT_OPTIONS) # TODO: not fluentd type
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@fluentd = Fluentd.new(fluentd_params)
|
||||||
|
unless @fluentd.save
|
||||||
|
return render :new
|
||||||
|
end
|
||||||
|
redirect_to fluentd_index_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
# TODO: should restart if changed file path? or just do "dirty" flagged?
|
||||||
|
@fluentd.update_attributes(fluentd_params)
|
||||||
|
unless @fluentd.save
|
||||||
|
return render :edit
|
||||||
|
end
|
||||||
|
redirect_to fluentd_index_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@fluentd.agent.stop if @fluentd.agent.running?
|
||||||
|
@fluentd.destroy
|
||||||
|
redirect_to fluentd_index_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_fluentd
|
||||||
|
@fluentd = Fluentd.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def fluentd_params
|
||||||
|
params.require(:fluentd).permit(:log_file, :pid_file, :config_file, :variant)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
module Fluentd::DaemonsHelper
|
|
||||||
end
|
|
@ -1,109 +1,64 @@
|
|||||||
Bundler.require(:default, :development)
|
class Fluentd < ActiveRecord::Base
|
||||||
|
before_validation :expand_paths
|
||||||
|
validates :variant, inclusion: { in: proc { Fluentd.variants } }
|
||||||
|
validates :log_file, presence: true
|
||||||
|
validates :pid_file, presence: true
|
||||||
|
validates :config_file, presence: true
|
||||||
|
validate :validate_permissions
|
||||||
|
|
||||||
require 'fluent/log'
|
def self.variants
|
||||||
require 'fluent/env'
|
%w(fluentd) # TODO:
|
||||||
require 'fluent/version'
|
|
||||||
require 'fluent/supervisor'
|
|
||||||
|
|
||||||
class Fluentd
|
|
||||||
attr_reader :root_dir
|
|
||||||
|
|
||||||
def initialize(root_dir)
|
|
||||||
@root_dir = root_dir
|
|
||||||
FileUtils.mkdir_p @root_dir
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def pid_file
|
def fluentd?
|
||||||
File.join(root_dir, "fluentd.pid")
|
variant == "fluentd"
|
||||||
end
|
end
|
||||||
|
|
||||||
def pid
|
def td_agent?
|
||||||
return unless File.exists?(pid_file)
|
variant == "td-agent"
|
||||||
File.read(pid_file)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_file
|
def agent
|
||||||
File.join(root_dir, "fluentd.log")
|
klass = variant.underscore.camelize
|
||||||
end
|
@agent ||= Agent.const_get(klass).new({
|
||||||
|
:pid_file => pid_file,
|
||||||
def config_file
|
:log_file => log_file,
|
||||||
file = File.join(root_dir, "fluentd.conf")
|
:config_file => config_file,
|
||||||
unless File.exists?(file)
|
|
||||||
File.open(file, "w") {|f| f.write "<source>\ntype forward\n</source>" } # TODO
|
|
||||||
end
|
|
||||||
file
|
|
||||||
end
|
|
||||||
|
|
||||||
def plugin_dir
|
|
||||||
dir = File.join(root_dir, "fluentd", "plugins")
|
|
||||||
unless Dir.exist?(dir)
|
|
||||||
FileUtils.mkdir_p(dir)
|
|
||||||
end
|
|
||||||
dir
|
|
||||||
end
|
|
||||||
|
|
||||||
def options
|
|
||||||
# TODO: https://github.com/fluent/fluentd/pull/315
|
|
||||||
{
|
|
||||||
:config_path => Fluent::DEFAULT_CONFIG_PATH,
|
|
||||||
:plugin_dirs => [Fluent::DEFAULT_PLUGIN_DIR],
|
|
||||||
:log_level => Fluent::Log::LEVEL_INFO,
|
|
||||||
:log_path => nil,
|
|
||||||
:daemonize => false,
|
|
||||||
:libs => [],
|
|
||||||
:setup_path => nil,
|
|
||||||
:chuser => nil,
|
|
||||||
:chgroup => nil,
|
|
||||||
:suppress_interval => 0,
|
|
||||||
:suppress_repeated_stacktrace => false,
|
|
||||||
:use_v1_config => false,
|
|
||||||
}.merge({
|
|
||||||
:use_v1_config => true,
|
|
||||||
:plugin_dirs => [plugin_dir],
|
|
||||||
:config_path => config_file,
|
|
||||||
:daemonize => pid_file,
|
|
||||||
:log_path => log_file,
|
|
||||||
:log_level => Fluent::Log::LEVEL_INFO,
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def running?
|
def expand_paths
|
||||||
pid && system("/bin/kill -0 #{pid}", :out => File::NULL, :err => File::NULL)
|
%w(pid_file log_file config_file).each do |column|
|
||||||
|
path = send(column)
|
||||||
|
next if path.blank?
|
||||||
|
self.send("#{column}=", File.expand_path(path))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def start
|
def validate_permissions
|
||||||
return if running?
|
%w(pid_file log_file config_file).each do |column|
|
||||||
spawn("bundle exec fluentd #{options_to_argv(options)}") # TODO
|
check_permission(column)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop
|
def check_permission(column)
|
||||||
return unless running?
|
path = send(column)
|
||||||
system("/bin/kill -TERM #{pid}")
|
return if path.blank? # if empty, presence: true will catch it
|
||||||
File.unlink(pid_file)
|
if File.exist?(path)
|
||||||
|
if File.directory?(path)
|
||||||
|
errors.add(column, :is_a_directory)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reload
|
unless File.writable?(path)
|
||||||
return unless running?
|
errors.add(column, :lack_write_permission)
|
||||||
system("/bin/kill -HUP #{pid}")
|
|
||||||
end
|
end
|
||||||
|
unless File.readable?(path)
|
||||||
def log
|
errors.add(column, :lack_read_permission)
|
||||||
File.read log_file # TODO: large log file
|
end
|
||||||
|
else
|
||||||
|
unless File.writable?(File.dirname(path))
|
||||||
|
errors.add(column, :lack_write_permission)
|
||||||
end
|
end
|
||||||
|
|
||||||
def config
|
|
||||||
::Fluentd::Configuration.new(config_file)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def options_to_argv(options)
|
|
||||||
argv = ""
|
|
||||||
argv << " --use-v1-config" if options[:use_v1_config]
|
|
||||||
argv << " -c #{options[:config_path]}" if options[:config_path].present?
|
|
||||||
argv << " -p #{options[:plugin_dir].first}" if options[:plugin_dir].present?
|
|
||||||
argv << " -d #{options[:daemonize]}" if options[:daemonize].present?
|
|
||||||
argv << " -o #{options[:log_path]}" if options[:log_path].present?
|
|
||||||
argv
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
28
app/models/fluentd/agent.rb
Normal file
28
app/models/fluentd/agent.rb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
require 'fluent/log'
|
||||||
|
require 'fluent/env'
|
||||||
|
require 'fluent/version'
|
||||||
|
require 'fluent/supervisor'
|
||||||
|
require "fluentd/agent/common"
|
||||||
|
require "fluentd/agent/fluentd"
|
||||||
|
require "fluentd/agent/td_agent"
|
||||||
|
require "fluentd/agent/remote"
|
||||||
|
|
||||||
|
class Fluentd
|
||||||
|
class Agent
|
||||||
|
# pidfile
|
||||||
|
# td-agent: /var/run/td-agent/td-agent.pid
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/td-agent.logrotate#L10
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.init#L25
|
||||||
|
# fluentd: nothing (or --daemon PIDFILE)
|
||||||
|
#
|
||||||
|
# logfile
|
||||||
|
# td-agent: /var/log/td-agent/td-agent.log
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.init#L28
|
||||||
|
# fluentd: stdout (or --log LOGFILE)
|
||||||
|
#
|
||||||
|
# config file
|
||||||
|
# td-agent: /etc/td-agent/td-agent.conf
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.postinst#L69
|
||||||
|
# fluentd: /etc/fluent/fluent.conf (by fluentd -s)
|
||||||
|
end
|
||||||
|
end
|
62
app/models/fluentd/agent/common.rb
Normal file
62
app/models/fluentd/agent/common.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# pidfile
|
||||||
|
# td-agent: /var/run/td-agent/td-agent.pid
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/td-agent.logrotate#L10
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.init#L25
|
||||||
|
# fluentd: nothing (or --daemon PIDFILE)
|
||||||
|
#
|
||||||
|
# logfile
|
||||||
|
# td-agent: /var/log/td-agent/td-agent.log
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.init#L28
|
||||||
|
# fluentd: stdout (or --log LOGFILE)
|
||||||
|
#
|
||||||
|
# config file
|
||||||
|
# td-agent: /etc/td-agent/td-agent.conf
|
||||||
|
# - https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.postinst#L69
|
||||||
|
# fluentd: /etc/fluent/fluent.conf (by fluentd -s)
|
||||||
|
|
||||||
|
class Fluentd
|
||||||
|
class Agent
|
||||||
|
module Common
|
||||||
|
attr_reader :extra_options
|
||||||
|
|
||||||
|
def initialize(options = {})
|
||||||
|
@extra_options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
def pid
|
||||||
|
return unless File.exists?(pid_file)
|
||||||
|
File.read(pid_file).to_i rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def wait_process_starting_seconds
|
||||||
|
10.seconds # wait time for fluentd pidfile created
|
||||||
|
end
|
||||||
|
|
||||||
|
def running?
|
||||||
|
pid && Process.kill(0, pid)
|
||||||
|
end
|
||||||
|
|
||||||
|
def log
|
||||||
|
File.read(log_file) # TODO: large log file
|
||||||
|
end
|
||||||
|
|
||||||
|
def pid_file
|
||||||
|
extra_options[:pid_file] || self.class.default_options[:pid_file]
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_file
|
||||||
|
extra_options[:log_file] || self.class.default_options[:log_file]
|
||||||
|
end
|
||||||
|
|
||||||
|
def config_file
|
||||||
|
extra_options[:config_file] || self.class.default_options[:config_file]
|
||||||
|
end
|
||||||
|
|
||||||
|
%w(start stop restart).each do |method|
|
||||||
|
define_method(method) do
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
77
app/models/fluentd/agent/fluentd.rb
Normal file
77
app/models/fluentd/agent/fluentd.rb
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
class Fluentd
|
||||||
|
class Agent
|
||||||
|
class Fluentd
|
||||||
|
include Common
|
||||||
|
|
||||||
|
def self.default_options
|
||||||
|
{
|
||||||
|
:pid_file => "/var/run/fluent.pid",
|
||||||
|
:log_file => "/var/log/fluent.log",
|
||||||
|
:config_file => "/etc/fluent/fluent.conf",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def options_to_argv
|
||||||
|
argv = ""
|
||||||
|
argv << " --use-v1-config"
|
||||||
|
argv << " -c #{config_file}"
|
||||||
|
argv << " -d #{pid_file}"
|
||||||
|
argv << " -o #{log_file}"
|
||||||
|
argv
|
||||||
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
return true if running?
|
||||||
|
if validate_fluentd_options
|
||||||
|
actual_start
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
return true unless running?
|
||||||
|
actual_stop
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
return false unless running?
|
||||||
|
actual_restart
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def validate_fluentd_options
|
||||||
|
system("bundle exec fluentd --dry-run #{options_to_argv}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def actual_start
|
||||||
|
spawn("bundle exec fluentd #{options_to_argv}")
|
||||||
|
wait_starting
|
||||||
|
end
|
||||||
|
|
||||||
|
def actual_stop
|
||||||
|
if Process.kill(:TERM, pid)
|
||||||
|
File.unlink(pid_file)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def actual_restart
|
||||||
|
Process.kill(:HUP, pid)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wait_starting
|
||||||
|
begin
|
||||||
|
timeout(wait_process_starting_seconds) do
|
||||||
|
loop do
|
||||||
|
break if pid && Process.kill(0, pid)
|
||||||
|
sleep 0.01
|
||||||
|
end
|
||||||
|
end
|
||||||
|
true
|
||||||
|
rescue TimeoutError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
app/models/fluentd/agent/remote.rb
Normal file
7
app/models/fluentd/agent/remote.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
class Fluentd
|
||||||
|
class Agent
|
||||||
|
class Remote # TODO
|
||||||
|
include Common
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
29
app/models/fluentd/agent/td_agent.rb
Normal file
29
app/models/fluentd/agent/td_agent.rb
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
class Fluentd
|
||||||
|
class Agent
|
||||||
|
class TdAgent
|
||||||
|
include Common
|
||||||
|
|
||||||
|
def self.default_options
|
||||||
|
{
|
||||||
|
:pid_file => "/var/run/td-agent/td-agent.pid",
|
||||||
|
:log_file => "/var/log/td-agent/td-agent.log",
|
||||||
|
:config_file => "/etc/td-agent/td-agent.conf",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
system('/etc/init.d/td-agent start')
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
system('/etc/init.d/td-agent stop')
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
# NOTE: td-agent has no reload command
|
||||||
|
# https://github.com/treasure-data/td-agent/blob/master/debian/td-agent.init#L156
|
||||||
|
system('/etc/init.d/td-agent restart')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -86,6 +86,7 @@ class Plugin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.installed
|
def self.installed
|
||||||
|
return [] unless File.exist?(gemfile_path)
|
||||||
File.read(gemfile_path).scan(/"(.*?)", "(.*?)"/).map do |plugin|
|
File.read(gemfile_path).scan(/"(.*?)", "(.*?)"/).map do |plugin|
|
||||||
new(gem_name: plugin[0], version: plugin[1])
|
new(gem_name: plugin[0], version: plugin[1])
|
||||||
end
|
end
|
||||||
|
18
app/views/fluentd/_form.html.haml
Normal file
18
app/views/fluentd/_form.html.haml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
%div.col-lg-6
|
||||||
|
- @fluentd.errors.full_messages.each do |e|
|
||||||
|
%div.alert.alert-danger= e
|
||||||
|
|
||||||
|
= form_for(:fluentd, url: url, method: method) do |f|
|
||||||
|
%div.form-group
|
||||||
|
= f.label :variant
|
||||||
|
= f.select :variant, Fluentd.variants
|
||||||
|
%div.form-group
|
||||||
|
= f.label :pid_file
|
||||||
|
= f.text_field :pid_file, class: "form-control"
|
||||||
|
%div.form-group
|
||||||
|
= f.label :log_file
|
||||||
|
= f.text_field :log_file, class: "form-control"
|
||||||
|
%div.form-group
|
||||||
|
= f.label :config_file
|
||||||
|
= f.text_field :config_file, class: "form-control"
|
||||||
|
= f.submit btn, class: "btn btn-primary"
|
13
app/views/fluentd/agents/show.html.haml
Normal file
13
app/views/fluentd/agents/show.html.haml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
- page_title t('.page_title', label: "##{@fluentd.id}")
|
||||||
|
|
||||||
|
- if flash[:error]
|
||||||
|
%div.alert.alert-danger= flash[:error]
|
||||||
|
|
||||||
|
%h4
|
||||||
|
= @fluentd.agent.running? ? t(".running") : t(".stopped")
|
||||||
|
|
||||||
|
= link_to t(".start"), start_fluentd_agent_path(@fluentd), method: :put
|
||||||
|
= link_to t(".stop"), stop_fluentd_agent_path(@fluentd), method: :put
|
||||||
|
= link_to t(".restart"), restart_fluentd_agent_path(@fluentd), method: :put
|
||||||
|
= link_to t(".log"), log_fluentd_agent_path(@fluentd)
|
||||||
|
TODO: config
|
@ -1,7 +0,0 @@
|
|||||||
%h1
|
|
||||||
= @fluentd.running? ? "running" : "stopped"
|
|
||||||
|
|
||||||
= link_to "start", start_fluentd_daemon_path(id: 1), method: :put, remote: true
|
|
||||||
= link_to "stop", stop_fluentd_daemon_path(id: 1), method: :put, remote: true
|
|
||||||
= link_to "reload", reload_fluentd_daemon_path(id: 1), method: :put, remote: true
|
|
||||||
= link_to "log", log_fluentd_daemon_path(id: 1)
|
|
3
app/views/fluentd/edit.html.haml
Normal file
3
app/views/fluentd/edit.html.haml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
- page_title t('.page_title')
|
||||||
|
|
||||||
|
= render partial: "form", locals: { btn: t(".update"), url: fluentd_path(@fluentd), method: :patch }
|
@ -1,2 +1,14 @@
|
|||||||
- @daemons.each do |d|
|
- page_title t('.page_title')
|
||||||
= link_to d, fluentd_daemon_path(fluentd_id: 1) # TODO
|
|
||||||
|
%p= link_to icon('fa-plus') << " " << t(".new"), new_fluentd_path
|
||||||
|
|
||||||
|
- @fluentds.each do |d|
|
||||||
|
%div.col-lg-6
|
||||||
|
%div.panel.panel-default
|
||||||
|
%div.panel-heading
|
||||||
|
%h4
|
||||||
|
= "fluentd ##{d.id}"
|
||||||
|
= link_to t(".edit"), edit_fluentd_path(d)
|
||||||
|
= link_to t(".destroy"), fluentd_path(d), method: :delete
|
||||||
|
%div.panel-body
|
||||||
|
= link_to t(".operation"), fluentd_agent_path(d) # TODO
|
||||||
|
3
app/views/fluentd/new.html.haml
Normal file
3
app/views/fluentd/new.html.haml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
- page_title t('.page_title')
|
||||||
|
|
||||||
|
= render partial: "form", locals: { btn: t(".create"), url: fluentd_index_path, method: :post }
|
@ -2,6 +2,14 @@
|
|||||||
<li>
|
<li>
|
||||||
<%= link_to_other icon("fa-dashboard fa-fw") << " Dashboard", root_path %>
|
<%= link_to_other icon("fa-dashboard fa-fw") << " Dashboard", root_path %>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<%= link_to_other icon("fa-puzzle-piece fa-fw") << " fluentd", fluentd_index_path %>
|
||||||
|
<ul class="nav nav-second-level">
|
||||||
|
<li>
|
||||||
|
<%= link_to_other t("terms.new"), new_fluentd_path %>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to_other icon("fa-cogs fa-fw") << " " << t('terms.plugins') << icon('fa pull-right fa-caret-down'), plugins_path %>
|
<%= link_to_other icon("fa-cogs fa-fw") << " " << t('terms.plugins') << icon('fa pull-right fa-caret-down'), plugins_path %>
|
||||||
<ul class="nav nav-second-level">
|
<ul class="nav nav-second-level">
|
||||||
|
@ -13,6 +13,7 @@ require "sprockets/railtie"
|
|||||||
# you've limited to :test, :development, or :production.
|
# you've limited to :test, :development, or :production.
|
||||||
Bundler.require(*Rails.groups)
|
Bundler.require(*Rails.groups)
|
||||||
# these gems are not required by Bundler.require
|
# these gems are not required by Bundler.require
|
||||||
|
require "sass"
|
||||||
require "haml-rails"
|
require "haml-rails"
|
||||||
require "jquery-rails"
|
require "jquery-rails"
|
||||||
require "sucker_punch"
|
require "sucker_punch"
|
||||||
|
@ -16,6 +16,11 @@ ja:
|
|||||||
fluent_version: "fluentd %{version}"
|
fluent_version: "fluentd %{version}"
|
||||||
no_alert: なし
|
no_alert: なし
|
||||||
update_password: パスワード更新
|
update_password: パスワード更新
|
||||||
|
create: 作成
|
||||||
|
update: 更新
|
||||||
|
edit: 編集
|
||||||
|
destroy: 削除
|
||||||
|
new: 新規作成
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
common: &plugin_common
|
common: &plugin_common
|
||||||
@ -45,6 +50,32 @@ ja:
|
|||||||
<<: *terms
|
<<: *terms
|
||||||
page_title: ユーザー管理
|
page_title: ユーザー管理
|
||||||
|
|
||||||
|
fluentd: &fluentd
|
||||||
|
common: &fluentd_common
|
||||||
|
<<: *terms
|
||||||
|
start: 開始
|
||||||
|
stop: 停止
|
||||||
|
restart: 再起動
|
||||||
|
log: ログ
|
||||||
|
stopped: 停止中
|
||||||
|
running: 稼働中
|
||||||
|
operation: プロセス詳細
|
||||||
|
form:
|
||||||
|
<<: *fluentd_common
|
||||||
|
index:
|
||||||
|
<<: *fluentd_common
|
||||||
|
page_title: fluentd
|
||||||
|
new:
|
||||||
|
<<: *fluentd_common
|
||||||
|
page_title: fluentd | 追加
|
||||||
|
edit:
|
||||||
|
<<: *fluentd_common
|
||||||
|
page_title: fluentd | 編集
|
||||||
|
agents:
|
||||||
|
show:
|
||||||
|
<<: *fluentd_common
|
||||||
|
page_title: "fluentd %{label}"
|
||||||
|
|
||||||
misc:
|
misc:
|
||||||
common: &misc_common
|
common: &misc_common
|
||||||
<<: *terms
|
<<: *terms
|
||||||
@ -61,11 +92,17 @@ ja:
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
login_failed: ログインに失敗しました。
|
login_failed: ログインに失敗しました。
|
||||||
|
fluentd_start_failed: fluentdの起動に失敗しました。
|
||||||
|
fluentd_stop_failed: fluentdの停止に失敗しました。
|
||||||
|
fluentd_restart_failed: fluentdの再起動に失敗しました。
|
||||||
|
|
||||||
activerecord:
|
activerecord:
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
wrong_password: が違います
|
wrong_password: が違います
|
||||||
|
lack_read_permission: の読み込み権限がありません
|
||||||
|
lack_write_permission: の書き込み権限がありません
|
||||||
|
is_a_directory: はディレクトリです。ファイルを指定してください
|
||||||
|
|
||||||
models:
|
models:
|
||||||
user: user #g
|
user: user #g
|
||||||
@ -78,3 +115,8 @@ ja:
|
|||||||
current_password: 現在のパスワード
|
current_password: 現在のパスワード
|
||||||
password: パスワード
|
password: パスワード
|
||||||
password_confirmation: パスワード(確認)
|
password_confirmation: パスワード(確認)
|
||||||
|
fluentd:
|
||||||
|
log_file: ログファイル
|
||||||
|
pid_file: PIDファイル
|
||||||
|
config_file: 設定ファイル
|
||||||
|
variant: タイプ
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
root "fluentd#index" # TODO: change to dashboard
|
root "fluentd#index" # TODO: change to dashboard
|
||||||
|
|
||||||
resources :fluentd, only: [:index] do
|
resources :fluentd do
|
||||||
resource :daemon, only: [:show], module: :fluentd do
|
resource :agent, only: [:show], module: :fluentd do
|
||||||
put "start"
|
put "start"
|
||||||
put "stop"
|
put "stop"
|
||||||
put "reload"
|
put "restart"
|
||||||
get "log"
|
get "log"
|
||||||
end
|
end
|
||||||
resource :setting, only: [:show, :edit, :update], module: :fluentd do
|
resource :setting, only: [:show, :edit, :update], module: :fluentd do
|
||||||
|
12
db/migrate/20140522055753_create_fluentds.rb
Normal file
12
db/migrate/20140522055753_create_fluentds.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class CreateFluentds < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :fluentds do |t|
|
||||||
|
t.string :variant, null: false # fluentd, td-agent, or remote
|
||||||
|
t.string :pid_file
|
||||||
|
t.string :log_file
|
||||||
|
t.string :config_file
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
11
db/schema.rb
11
db/schema.rb
@ -11,7 +11,16 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20140522023140) do
|
ActiveRecord::Schema.define(version: 20140522055753) do
|
||||||
|
|
||||||
|
create_table "fluentds", force: true do |t|
|
||||||
|
t.string "variant", null: false
|
||||||
|
t.string "pid_file"
|
||||||
|
t.string "log_file"
|
||||||
|
t.string "config_file"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "login_tokens", force: true do |t|
|
create_table "login_tokens", force: true do |t|
|
||||||
t.string "token_id", null: false
|
t.string "token_id", null: false
|
||||||
|
@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|||||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||||
spec.require_paths = ["lib"]
|
spec.require_paths = ["lib"]
|
||||||
|
|
||||||
spec.add_dependency "fluentd", "0.10.46"
|
spec.add_dependency "fluentd", "~> 0.10.48"
|
||||||
spec.add_dependency 'rails', '4.1.1'
|
spec.add_dependency 'rails', '4.1.1'
|
||||||
spec.add_dependency 'sucker_punch', "~> 1.0.5"
|
spec.add_dependency 'sucker_punch', "~> 1.0.5"
|
||||||
spec.add_dependency 'i18n_generators', '1.2.1'
|
spec.add_dependency 'i18n_generators', '1.2.1'
|
||||||
|
8
spec/factories/fluentd.rb
Normal file
8
spec/factories/fluentd.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FactoryGirl.define do
|
||||||
|
factory :fluentd do
|
||||||
|
variant "fluentd"
|
||||||
|
log_file (Rails.root + "tmp/fluentd-test/fluentd.log").to_s
|
||||||
|
pid_file (Rails.root + "tmp/fluentd-test/fluentd.pid").to_s
|
||||||
|
config_file (Rails.root + "tmp/fluentd-test/fluentd.conf").to_s
|
||||||
|
end
|
||||||
|
end
|
@ -1,15 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
# Specs in this file have access to a helper object that includes
|
|
||||||
# the MiscsHelper. For example:
|
|
||||||
#
|
|
||||||
# describe MiscsHelper do
|
|
||||||
# describe "string concat" do
|
|
||||||
# it "concats two strings with spaces" do
|
|
||||||
# expect(helper.concat_strings("this","that")).to eq("this that")
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
describe MiscsHelper do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
end
|
|
119
spec/models/fluentd/agent_spec.rb
Normal file
119
spec/models/fluentd/agent_spec.rb
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Fluentd::Agent do
|
||||||
|
shared_examples_for "Agent has common behavior" do |klass|
|
||||||
|
describe "#extra_options" do
|
||||||
|
context "blank" do
|
||||||
|
let(:options) { {} }
|
||||||
|
it { instance.pid_file.should == described_class.default_options[:pid_file] }
|
||||||
|
it { instance.log_file.should == described_class.default_options[:log_file] }
|
||||||
|
it { instance.config_file.should == described_class.default_options[:config_file] }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "given" do
|
||||||
|
let(:options) do
|
||||||
|
{
|
||||||
|
:pid_file => pid_file,
|
||||||
|
:log_file => log_file,
|
||||||
|
:config_file => config_file,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:pid_file) { "pid" }
|
||||||
|
let(:log_file) { "log" }
|
||||||
|
let(:config_file) { "config" }
|
||||||
|
|
||||||
|
it { instance.pid_file.should == pid_file }
|
||||||
|
it { instance.log_file.should == log_file }
|
||||||
|
it { instance.config_file.should == config_file }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:instance) { described_class.new(options) }
|
||||||
|
let(:options) { {} }
|
||||||
|
|
||||||
|
describe "Fluentd" do
|
||||||
|
let(:described_class) { Fluentd::Agent::Fluentd } # override nested described_class behavior as https://github.com/rspec/rspec-core/issues/1114
|
||||||
|
|
||||||
|
it_should_behave_like "Agent has common behavior"
|
||||||
|
|
||||||
|
describe "#options_to_argv" do
|
||||||
|
subject { instance.options_to_argv }
|
||||||
|
it { should include("-c #{instance.config_file}") }
|
||||||
|
it { should include("-d #{instance.pid_file}") }
|
||||||
|
it { should include("-o #{instance.log_file}") }
|
||||||
|
it { should include("--use-v1-config") }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#start" do
|
||||||
|
before { instance.stub(:running?).and_return { running } }
|
||||||
|
|
||||||
|
context "running" do
|
||||||
|
let(:running) { true }
|
||||||
|
after { instance.start }
|
||||||
|
|
||||||
|
it { instance.should_not_receive(:validate_fluentd_options) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "not running" do
|
||||||
|
let(:running) { false }
|
||||||
|
after { instance.start }
|
||||||
|
|
||||||
|
it { instance.should_receive(:validate_fluentd_options) }
|
||||||
|
|
||||||
|
context "validate_fluentd_options success" do
|
||||||
|
before { instance.stub(:validate_fluentd_options).and_return { true } }
|
||||||
|
it { instance.should_receive(:actual_start) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "validate_fluentd_options fail" do
|
||||||
|
before { instance.stub(:validate_fluentd_options).and_return { false } }
|
||||||
|
it { instance.should_not_receive(:actual_start) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#stop" do
|
||||||
|
before { instance.stub(:running?).and_return { running } }
|
||||||
|
|
||||||
|
context "running" do
|
||||||
|
let(:running) { true }
|
||||||
|
after { instance.stop }
|
||||||
|
|
||||||
|
it { instance.should_receive(:actual_stop) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "not running" do
|
||||||
|
let(:running) { false }
|
||||||
|
after { instance.stop }
|
||||||
|
|
||||||
|
it { instance.should_not_receive(:actual_stop) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#restart" do
|
||||||
|
before { instance.stub(:running?).and_return { running } }
|
||||||
|
|
||||||
|
context "running" do
|
||||||
|
let(:running) { true }
|
||||||
|
after { instance.restart }
|
||||||
|
|
||||||
|
it { instance.should_receive(:actual_restart) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "not running" do
|
||||||
|
let(:running) { false }
|
||||||
|
after { instance.restart }
|
||||||
|
|
||||||
|
it { instance.should_not_receive(:actual_restart) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "TdAgent" do
|
||||||
|
let(:described_class) { Fluentd::Agent::TdAgent } # override nested described_class behavior as https://github.com/rspec/rspec-core/issues/1114
|
||||||
|
|
||||||
|
it_should_behave_like "Agent has common behavior"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
127
spec/models/fluentd_spec.rb
Normal file
127
spec/models/fluentd_spec.rb
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Fluentd do
|
||||||
|
shared_examples_for "path permission" do |column|
|
||||||
|
let(:path) { fluentd.send(column) }
|
||||||
|
|
||||||
|
subject do
|
||||||
|
fluentd.check_permission(column)
|
||||||
|
fluentd.errors
|
||||||
|
end
|
||||||
|
|
||||||
|
context "file exists" do
|
||||||
|
before { FileUtils.touch(path) }
|
||||||
|
after { FileUtils.chmod(0755, path) }
|
||||||
|
|
||||||
|
context "writable" do
|
||||||
|
before { FileUtils.chmod(0600, path) }
|
||||||
|
it { should be_blank }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "not writable" do
|
||||||
|
before { FileUtils.chmod(0400, path) }
|
||||||
|
it { should_not be_blank }
|
||||||
|
it { subject.get(column).should include(I18n.t('activerecord.errors.messages.lack_write_permission')) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "not readable" do
|
||||||
|
before { FileUtils.chmod(0200, path) }
|
||||||
|
it { should_not be_blank }
|
||||||
|
it { subject.get(column).should include(I18n.t('activerecord.errors.messages.lack_read_permission')) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "is directory" do
|
||||||
|
before { fluentd.send("#{column}=", Rails.root + "tmp") }
|
||||||
|
it { should_not be_blank }
|
||||||
|
it { subject.get(column).should include(I18n.t('activerecord.errors.messages.is_a_directory')) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "file not exists" do
|
||||||
|
let(:dir) { File.dirname(path) }
|
||||||
|
before { FileUtils.rm path }
|
||||||
|
after { FileUtils.chmod_R(0755, dir) }
|
||||||
|
|
||||||
|
context "writable" do
|
||||||
|
before { FileUtils.chmod(0700, dir) }
|
||||||
|
it { should be_blank }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "not writable" do
|
||||||
|
before { FileUtils.chmod(0500, dir) }
|
||||||
|
it { should_not be_blank }
|
||||||
|
it { subject.get(column).should include(I18n.t('activerecord.errors.messages.lack_write_permission')) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:fluentd) { FactoryGirl.build(:fluentd) }
|
||||||
|
|
||||||
|
describe "#valid?" do
|
||||||
|
before do
|
||||||
|
%w(pid_file log_file config_file).each do |column|
|
||||||
|
FileUtils.mkdir_p File.dirname(fluentd.send(column))
|
||||||
|
FileUtils.touch fluentd.send(column)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { fluentd }
|
||||||
|
|
||||||
|
describe "variant" do
|
||||||
|
before { fluentd.variant = variant }
|
||||||
|
|
||||||
|
context "fluentd" do
|
||||||
|
let(:variant) { "fluentd" }
|
||||||
|
it { should be_valid }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "foobar (not declared in Fluentd.variants)" do
|
||||||
|
let(:variant) { "foobar" }
|
||||||
|
it { should_not be_valid }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "pid_file" do
|
||||||
|
it_should_behave_like "path permission", :pid_file
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "log_file" do
|
||||||
|
it_should_behave_like "path permission", :log_file
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "config_file" do
|
||||||
|
it_should_behave_like "path permission", :config_file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "variant" do
|
||||||
|
before { fluentd.variant = variant }
|
||||||
|
|
||||||
|
context "= fluentd" do
|
||||||
|
let(:variant) { "fluentd" }
|
||||||
|
it { fluentd.should be_fluentd }
|
||||||
|
it { fluentd.should_not be_td_agent }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "= td-agent" do
|
||||||
|
let(:variant) { "td-agent" }
|
||||||
|
it { fluentd.should_not be_fluentd }
|
||||||
|
it { fluentd.should be_td_agent }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#agent" do
|
||||||
|
before { fluentd.variant = variant }
|
||||||
|
subject { fluentd.agent }
|
||||||
|
|
||||||
|
context "fluentd" do
|
||||||
|
let(:variant) { "fluentd" }
|
||||||
|
it { should be_instance_of(Fluentd::Agent::Fluentd) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "td-agent" do
|
||||||
|
let(:variant) { "td-agent" }
|
||||||
|
it { should be_instance_of(Fluentd::Agent::TdAgent) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -64,12 +64,4 @@ RSpec.configure do |config|
|
|||||||
config.after(:each) do
|
config.after(:each) do
|
||||||
DatabaseCleaner.clean
|
DatabaseCleaner.clean
|
||||||
end
|
end
|
||||||
|
|
||||||
config.before(:each) do
|
|
||||||
system('sync') if ENV["CIRCLECI"] # file operations are unstable on Circle CI
|
|
||||||
end
|
|
||||||
|
|
||||||
config.after(:each) do
|
|
||||||
system('sync') if ENV["CIRCLECI"] # file operations are unstable on Circle CI
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user