diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ecf823b..23fa7b9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -9,6 +9,7 @@ class ApplicationController < ActionController::Base helper_method :fluentd_exists? before_action :login_required before_action :set_locale + before_action :notice_new_fluentd_ui_available def current_user return unless session[:succeed_password] @@ -50,6 +51,12 @@ class ApplicationController < ActionController::Base private + def notice_new_fluentd_ui_available + if FluentdUI.update_available? + flash[:info] = I18n.t("messages.available_new_fluentd_ui", version: FluentdUI.latest_version, update_url: misc_information_path) + end + end + def find_fluentd @fluentd = Fluentd.instance end diff --git a/app/controllers/misc_controller.rb b/app/controllers/misc_controller.rb index b405a5e..6a71c33 100644 --- a/app/controllers/misc_controller.rb +++ b/app/controllers/misc_controller.rb @@ -9,4 +9,24 @@ class MiscController < ApplicationController @env = ENV @plugins = Plugin.installed end + + def update_fluentd_ui + FluentdUiRestart.new.async.perform + @current_pid = $$ + render "update_fluentd_ui", layout: "sign_in" + end + + def upgrading_status + if FluentdUiRestart::LOCK.present? + return render text: "updating" + end + + if $$.to_s == params[:old_pid] + # restarting fluentd-ui is finished, but PID doesn't changed. + # maybe error occured at FluentdUiRestart#perform + render text: "failed" + else + render text: "finished" + end + end end diff --git a/app/models/plugin.rb b/app/models/plugin.rb index 0d257ad..9da967c 100644 --- a/app/models/plugin.rb +++ b/app/models/plugin.rb @@ -22,6 +22,8 @@ class Plugin self.version ||= latest_version if valid? && gem_install + # NOTE: also updating fluentd-ui gem is used this method, that shouldn't be recorded + return true unless gem_name.start_with?("fluent-plugin-") File.open(gemfile_path, "a") do |f| f.puts format_gemfile end diff --git a/app/views/layouts/sign_in.html.erb b/app/views/layouts/sign_in.html.erb index cb304a3..23e537d 100644 --- a/app/views/layouts/sign_in.html.erb +++ b/app/views/layouts/sign_in.html.erb @@ -18,14 +18,7 @@
- + <%= yield %>
diff --git a/app/views/misc/information.html.haml b/app/views/misc/information.html.haml index cee12d7..2f07f1a 100644 --- a/app/views/misc/information.html.haml +++ b/app/views/misc/information.html.haml @@ -1,55 +1,64 @@ - page_title t('.page_title') -%div.col-lg-6 - %div.panel.panel-info - %div.panel-heading - %h4= t ".version" - %div.panel-body - %dl{class: "dl-horizontal"} - %dt ruby - %dd= RUBY_DESCRIPTION - %dt fluentd - %dd= Fluent::VERSION - %dt fluentd-ui - %dd= FluentdUI::VERSION +- if FluentdUI.update_available? + .row + .col-lg-12 + %p + = link_to misc_update_fluentd_ui_path, class: "btn btn-primary btn-lg", method: :post do + = t('.update_fluentd_ui', version: FluentdUI.latest_version) + = t('.update_fluentd_ui_caution') +.row + %div.col-lg-6 + %div.panel.panel-default + %div.panel-heading + %h4= t ".version" + %div.panel-body + %dl{class: "dl-horizontal"} + %dt ruby + %dd= RUBY_DESCRIPTION + %dt fluentd + %dd= Fluent::VERSION + %dt fluentd-ui + %dd= FluentdUI::VERSION -%div.col-lg-6 - %div.panel.panel-default - %div.panel-heading - %h4= t('.installed_plugins') - %div.panel-body - - if @plugins.present? - %table{class: "table table-hover", id: "plugins-table"} - %thead - %tr - %th= t('plugins.common.name') - %th= t('plugins.common.version') - %tbody - - @plugins.each do |plugin| + %div.col-lg-6 + %div.panel.panel-default + %div.panel-heading + %h4= t('.installed_plugins') + %div.panel-body + - if @plugins.present? + %table{class: "table table-hover", id: "plugins-table"} + %thead %tr - %td= plugin.gem_name - %td= plugin.installed_version - - else - = t "plugins.common.no_installed" + %th= t('plugins.common.name') + %th= t('plugins.common.version') + %tbody + - @plugins.each do |plugin| + %tr + %td= plugin.gem_name + %td= plugin.installed_version + - else + = t "plugins.common.no_installed" -%div.col-lg-12 - %div.panel.panel-default - %div.panel-heading - %h4 - %a{"data-toggle" => "collapse", "href" => "#env-table"} - = icon('fa-caret-down') - = t('.env') - %table{class: "table table-hover collapse", id: "env-table"} - %thead - %tr - %th= t('.env_key') - %th= t('.env_value') - %tbody - - @env.each_pair do |key, value| +.row + %div.col-lg-12 + %div.panel.panel-default + %div.panel-heading + %h4 + %a{"data-toggle" => "collapse", "href" => "#env-table"} + = icon('fa-caret-down') + = t('.env') + %table{class: "table table-hover collapse", id: "env-table"} + %thead %tr - %td= key - %td= value + %th= t('.env_key') + %th= t('.env_value') + %tbody + - @env.each_pair do |key, value| + %tr + %td= key + %td= value :javascript $(document).ready(function() { diff --git a/app/views/misc/update_fluentd_ui.html.haml b/app/views/misc/update_fluentd_ui.html.haml new file mode 100644 index 0000000..4d345bb --- /dev/null +++ b/app/views/misc/update_fluentd_ui.html.haml @@ -0,0 +1,45 @@ +.panel.panel-default + .panel-heading + = t('.update_title') + .panel-body + #processing + = icon('fa-lg fa-gear fa-spin') + = t('.updating') + #finished{style: "display: none"} + = icon('fa-lg fa-check') + = t('.update_finish') + %p= link_to t('misc.information.page_title'), misc_information_path + #failed{style: "display: none"} + = icon('fa-lg fa-exclamation-circle') + = t('.failed') + %p= link_to t('misc.information.page_title'), misc_information_path + +:javascript + var CURRENT_PID = "#{@current_pid}"; + + function ping() { + setTimeout(function(){ + jQuery.ajax({ + url: "#{misc_upgrading_status_path}", + type: "GET", + data: { old_pid: CURRENT_PID } + }) + .fail(ping) + .done(function(status){ + switch(status) { + case "updating": + ping(); + break; + case "failed": + jQuery('#processing').hide(); + jQuery('#failed').show(); + break; + case "finished": + jQuery('#processing').hide(); + jQuery('#finished').show(); + break; + } + }); + }, 3000); + } + ping(); diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml index bae46db..5fbf579 100644 --- a/app/views/sessions/new.html.haml +++ b/app/views/sessions/new.html.haml @@ -1,8 +1,13 @@ -= render partial: "shared/error" -= form_for(:session, url: sessions_path) do |f| - %div.form-group - = f.text_field :name, placeholder: "Name" - %div.form-group - = f.password_field :password, placeholder: "Password" - - = submit_tag t("terms.sign_in"), class: "btn btn-success" +.login-panel.panel.panel-default + .panel-heading + %h3.panel-title + = t('messages.please_sign_in') + .panel-body + = render partial: "shared/error" + = form_for(:session, url: sessions_path) do |f| + %div.form-group + = f.text_field :name, placeholder: "Name" + %div.form-group + = f.password_field :password, placeholder: "Password" + + = submit_tag t("terms.sign_in"), class: "btn btn-success" diff --git a/app/views/shared/_flash.html.haml b/app/views/shared/_flash.html.haml index c430717..3da9db9 100644 --- a/app/views/shared/_flash.html.haml +++ b/app/views/shared/_flash.html.haml @@ -5,4 +5,6 @@ - if flash[:success] %p.alert.alert-success =raw flash[:success] - + - if flash[:info] + %p.alert.alert-info + =raw flash[:info] diff --git a/app/workers/fluentd_ui_restart.rb b/app/workers/fluentd_ui_restart.rb new file mode 100644 index 0000000..5ce7258 --- /dev/null +++ b/app/workers/fluentd_ui_restart.rb @@ -0,0 +1,38 @@ +class FluentdUiRestart + include SuckerPunch::Job + + LOCK = [] + + def lock! + raise "update process is still running" if LOCK.present? + LOCK << true + end + + def unlock! + LOCK.shift + end + + def perform + lock! + sleep 5 # delay for render updating HTML + + # NOTE: install will be failed before released fluentd-ui gem + SuckerPunch.logger.info "[restart] install new fluentd-ui" + Plugin.new(gem_name: "fluentd-ui").install! + + if Rails.env.production? + cmd = %W(#{Rails.root}/bin/fluentd-ui start) + else + cmd = %W(bundle exec rails s) + end + + SuckerPunch.logger.info "[restart] will restart" + Bundler.with_clean_env do + restarter = "#{Rails.root}/bin/fluentd-ui-restart" + Process.spawn(*[restarter, $$.to_s, *cmd, *ARGV]) && Process.kill(:TERM, $$) + end + ensure + # don't reach here if restart is successful + unlock! + end +end diff --git a/app/workers/fluentd_ui_update_check.rb b/app/workers/fluentd_ui_update_check.rb new file mode 100644 index 0000000..633e6c9 --- /dev/null +++ b/app/workers/fluentd_ui_update_check.rb @@ -0,0 +1,15 @@ +class FluentdUiUpdateCheck + include SuckerPunch::Job + + def perform + pl = Plugin.new(gem_name: "fluentd-ui") + if pl.gem_versions # NOTE: fluentd-ui is not released yet, so `pl.latest_version` will fail for now + FluentdUI.latest_version = pl.latest_version + end + later(3600) # will be checked every hour + end + + def later(sec) + after(sec) { perform } + end +end diff --git a/bin/fluentd-ui-restart b/bin/fluentd-ui-restart new file mode 100755 index 0000000..3b25c45 --- /dev/null +++ b/bin/fluentd-ui-restart @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby + +pid = ARGV.shift +begin + loop do + # wait old fluentd-ui process shutdown + Process.kill(0, pid.to_i) + sleep 0.1 + end +rescue Errno::ESRCH + exec(*ARGV) +end diff --git a/config/application.rb b/config/application.rb index b0c8fef..549f741 100644 --- a/config/application.rb +++ b/config/application.rb @@ -38,5 +38,7 @@ module FluentdUi # If AR will be used, please comment in and check timezone. # config.active_record.default_timezone = :local # config.time_zone = + + require Rails.root.join("lib", "fluentd-ui") end end diff --git a/config/locales/translation_en.yml b/config/locales/translation_en.yml index 6d6d76f..535e49d 100644 --- a/config/locales/translation_en.yml +++ b/config/locales/translation_en.yml @@ -3,6 +3,7 @@ en: need_restart: need to restart fluentd-ui please_sign_in: Sign in destroy_succeed_fluentd_setting: Deleted fluentd setting + available_new_fluentd_ui: 'fluentd-ui %{version} is available. Go to system information page' terms: &terms sign_in: Sign in @@ -186,6 +187,14 @@ en: env_key: Key env_value: Value page_title: System Information + update_fluentd_ui: Update fluentd-ui + update_fluentd_ui_caution: "Note: fluentd will not restart" + update_fluentd_ui: + <<: *misc_common + update_title: Updating fluentd-ui + updating: Updating.. + update_finish: Update finished! + failed: Failed to update. Please see fluentd-ui log tutorials: common: &tutorials_common diff --git a/config/locales/translation_ja.yml b/config/locales/translation_ja.yml index 8bcc69e..2f5b4a7 100644 --- a/config/locales/translation_ja.yml +++ b/config/locales/translation_ja.yml @@ -3,6 +3,7 @@ ja: need_restart: fluentd-uiの再起動が必要です please_sign_in: ログイン destroy_succeed_fluentd_setting: fluentdの設定を削除しました + available_new_fluentd_ui: 'fluentd-ui %{version}にアップデートできます。システム情報ページへ' terms: &terms sign_in: ログイン @@ -182,6 +183,14 @@ ja: env_key: キー env_value: 値 page_title: システム情報 + update_fluentd_ui: fluentd-uiを更新 + update_fluentd_ui_caution: ※fluentdは再起動されません + update_fluentd_ui: + <<: *misc_common + update_title: fluentd-ui 更新 + updating: 更新中 + update_finish: 更新が完了しました + failed: 更新に失敗しました。fluentd-uiのログをご確認ください tutorials: common: &tutorials_common diff --git a/config/routes.rb b/config/routes.rb index 39a586d..da70d3f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,6 +37,8 @@ Rails.application.routes.draw do get "misc" => "misc#show" get "misc/information" + post "misc/update_fluentd_ui" + get "misc/upgrading_status" namespace :polling do get "alerts" diff --git a/lib/fluentd-ui.rb b/lib/fluentd-ui.rb index ead308a..b4e001f 100644 --- a/lib/fluentd-ui.rb +++ b/lib/fluentd-ui.rb @@ -1,2 +1,16 @@ module FluentdUI + def self.latest_version=(version) + @latest = version + end + + def self.latest_version + @latest + end + + def self.update_available? + return unless @latest + latest = Gem::Version.new(@latest) + current = Gem::Version.new(::FluentdUI::VERSION) + latest > current + end end