diff --git a/app/controllers/api/config_definitions_controller.rb b/app/controllers/api/config_definitions_controller.rb index be88c04..e5b8e68 100644 --- a/app/controllers/api/config_definitions_controller.rb +++ b/app/controllers/api/config_definitions_controller.rb @@ -41,6 +41,12 @@ class Api::ConfigDefinitionsController < ApplicationController advancedOptions: transport_advanced_options } end + + if type == "output" && name == "forward" + tls_options = build_options(target, target.tls_options) + options[:tlsOptions] = tls_options + end + render json: options end diff --git a/app/form_builders/fluentd_form_builder.rb b/app/form_builders/fluentd_form_builder.rb index 3db57d8..a135be2 100644 --- a/app/form_builders/fluentd_form_builder.rb +++ b/app/form_builders/fluentd_form_builder.rb @@ -34,7 +34,7 @@ class FluentdFormBuilder < ActionView::Helpers::FormBuilder def enum_field(key, options) label(key, nil, data: { toggle: "tooltip", placement: "right" }, title: object.desc(key)) + - select(key, object.list_of(key), options, { class: "enum" }) + select(key, object.list_of(key), options, { class: "enum form-control" }) end def bool_field(key, options) @@ -58,9 +58,10 @@ class FluentdFormBuilder < ActionView::Helpers::FormBuilder section_class = object.class._sections[key] children = object.__send__(key) || { "0" => {} } html = "" + html_class = "js-nested-column #{section_class.multi ? "js-multiple" : ""}" children.each do |index, child| - html << content_tag("div", class: "js-nested-column #{section_class.multi ? "js-multiple" : ""}") do + html << content_tag("div", class: html_class) do _html = "" _html << append_and_remove_links if section_class.multi _html << label(key, nil, data: { toggle: "tooltip", placement: "right" }, title: object.desc(key)) @@ -83,8 +84,8 @@ class FluentdFormBuilder < ActionView::Helpers::FormBuilder end def append_and_remove_links - %Q!#{icon('fa-plus')} ! + - %Q! ! + %Q!#{icon('fa-plus')} ! + + %Q! ! end def icon(classes, inner=nil) diff --git a/app/javascript/packs/config_field.js b/app/javascript/packs/config_field.js index fd72481..5496a62 100644 --- a/app/javascript/packs/config_field.js +++ b/app/javascript/packs/config_field.js @@ -1,4 +1,5 @@ 'use strict' +import 'lodash/lodash' const ConfigField = { template: "#vue-config-field", @@ -16,15 +17,32 @@ const ConfigField = { } }, + filters: { + humanize: function(value) { + return _.capitalize(value.replace(/_/g, " ")) + } + }, + mounted: function() { - this.expression = this.initialExpression - this.timeFormat = this.initialTimeFormat - this.$on("hook:updated", () => { - this.$nextTick(() => { - console.log("config-field hook:updated") - $("[data-toggle=tooltip]").tooltip("dispose") - $("[data-toggle=tooltip]").tooltip("enable") - }) + if (this.option.name === "expression") { + this.expression = this.initialExpression + } + if (this.option.name === "time_format") { + this.timeFormat = this.initialTimeFormat + } + }, + + updated: function() { + if (this.option.name === "expression") { + this.expression = this.initialExpression + } + if (this.option.name === "time_format") { + this.timeFormat = this.initialTimeFormat + } + this.$nextTick(() => { + console.log("config-field updated") + $("[data-toggle=tooltip]").tooltip("dispose") + $("[data-toggle=tooltip]").tooltip("enable") }) }, @@ -45,10 +63,19 @@ const ConfigField = { methods: { inputId: function(pluginType, option) { - return `setting_${pluginType}_0__${option.name}` + if (pluginType === "output") { + return `setting_${option.name}` + } else { + return `setting_${pluginType}_0__${option.name}` + } + }, inputName: function(pluginType, option) { - return `setting[${pluginType}[0]][${option.name}]` + if (pluginType === "output") { + return `setting[${option.name}]` + } else { + return `setting[${pluginType}[0]][${option.name}]` + } }, checked: function(checked) { if (checked === true || checked === "true") { diff --git a/app/javascript/packs/out_forward_setting.js b/app/javascript/packs/out_forward_setting.js new file mode 100644 index 0000000..98b3546 --- /dev/null +++ b/app/javascript/packs/out_forward_setting.js @@ -0,0 +1,14 @@ +'use strict' + +import TransportConfig from "./transport_config" +import OwnedPluginForm from "./owned_plugin_form" + +$(document).ready(() => { + new Vue({ + el: "#out-forward-setting", + components: { + "transport-config": TransportConfig, + "owned-plugin-form": OwnedPluginForm, + } + }) +}) diff --git a/app/javascript/packs/owned_plugin_form.js b/app/javascript/packs/owned_plugin_form.js index fd595e5..45f10aa 100644 --- a/app/javascript/packs/owned_plugin_form.js +++ b/app/javascript/packs/owned_plugin_form.js @@ -132,19 +132,6 @@ const OwnedPluginForm = { }, selectName: function(pluginType) { return `setting[${pluginType}_type]` - }, - inputId: function(pluginType, option) { - return `setting_${pluginType}_0__${option.name}` - }, - inputName: function(pluginType, option) { - return `setting[${pluginType}[0]][${option.name}]` - }, - checked: function(checked) { - if (checked === true || checked === "true") { - return "checked" - } else { - return "" - } } } } diff --git a/app/javascript/packs/transport_config.js b/app/javascript/packs/transport_config.js new file mode 100644 index 0000000..40e2967 --- /dev/null +++ b/app/javascript/packs/transport_config.js @@ -0,0 +1,60 @@ +'use strict' + +import ConfigField from './config_field' + +const TransportConfig = { + template: "#vue-transport-config", + components: { + "config-field": ConfigField + }, + props: [ + "pluginType", + "pluginName" + ], + data: function() { + return { + transportType: "tcp", + options: ["tcp", "tls"], + tlsOptions: [] + } + }, + computed: { + token: function() { + return Rails.csrfToken() + } + }, + filters: { + toUpper: function(value) { + return _.toUpper(value) + } + }, + mounted: function() { + }, + methods: { + onChange: function() { + console.log(this.pluginType, this.pluginName, this.transportType) + this.updateSection() + }, + + updateSection: function() { + if (this.transportType === "tcp") { + return + } + $.ajax({ + method: "GET", + url: "/api/config_definitions", + headers: { + 'X-CSRF-Token': this.token + }, + data: { + type: this.pluginType, + name: this.pluginName + } + }).then((data) => { + this.tlsOptions = data.tlsOptions + }) + } + } +} + +export { TransportConfig as default } diff --git a/app/javascript/packs/transport_section.js b/app/javascript/packs/transport_section.js new file mode 100644 index 0000000..a57b4c5 --- /dev/null +++ b/app/javascript/packs/transport_section.js @@ -0,0 +1,71 @@ +'use strict' +import 'lodash/lodash' + +import ConfigField from './config_field' + +$(document).ready(() => { + new Vue({ + el: '#transport-section', + components: { + "config-field": ConfigField + }, + props: [ + "transportType", + ], + propsData: { + "transportType": "tcp" + }, + data: function() { + return { + pluginType: null, + pluginName: null, + options: ["tcp", "tls"], + commonOptions: [], + advancedOptions: [] + + } + }, + computed: { + token: function() { + return Rails.csrfToken() + } + }, + filters: { + toUpper: function(value) { + return _.toUpper(value) + } + }, + beforeMount: function() { + this.pluginType = this.$el.attributes.pluginType.nodeValue + this.pluginName = this.$el.attributes.pluginName.nodeValue + }, + mounted: function() { + }, + methods: { + onChange: function() { + console.log(this.pluginType, this.pluginName, this.transportType) + this.updateSection() + }, + + updateSection: function() { + if (this.transportType === "tcp") { + return + } + $.ajax({ + method: "GET", + url: "/api/config_definitions", + headers: { + 'X-CSRF-Token': this.token + }, + data: { + type: this.pluginType, + name: this.pluginName + } + }).then((data) => { + this.commonOptions = data.transport.commonOptions + this.advancedOptions = data.transport.advancedOptions + }) + } + } + }) +}) diff --git a/app/models/concerns/fluentd/setting/configurable.rb b/app/models/concerns/fluentd/setting/configurable.rb index 9967a7e..669067e 100644 --- a/app/models/concerns/fluentd/setting/configurable.rb +++ b/app/models/concerns/fluentd/setting/configurable.rb @@ -89,7 +89,6 @@ class Fluentd else attribute(name, :section) section_class = Class.new(::Fluentd::Setting::Section) - section_class.include(Fluentd::Setting::PluginParameter) section_class.section_name = name section_class.required = options[:required] section_class.multi = options[:multi] diff --git a/app/models/concerns/fluentd/setting/plugin_config.rb b/app/models/concerns/fluentd/setting/plugin_config.rb index e52cfa0..6207045 100644 --- a/app/models/concerns/fluentd/setting/plugin_config.rb +++ b/app/models/concerns/fluentd/setting/plugin_config.rb @@ -56,7 +56,9 @@ class Fluentd next if section_params.blank? section_params.each do |index, _section_params| sub_attrs, sub_elements = parse_attributes(_section_params) - elements << config_element(key, "", sub_attrs, sub_elements) + if sub_attrs.present? || sub_elements.present? # skip empty section + elements << config_element(key, "", sub_attrs, sub_elements) + end end end return params.to_h.reject{|key, value| skip?(key.to_sym, value) }, elements @@ -70,7 +72,7 @@ class Fluentd def skip?(key, value) return true if value.blank? if self._defaults.key?(key) - reformat_value(key, self._defaults[key]) == reformat_value(key, value) + self.class.reformat_value(key, self._defaults[key]) == self.class.reformat_value(key, value) else false end diff --git a/app/models/concerns/fluentd/setting/plugin_parameter.rb b/app/models/concerns/fluentd/setting/plugin_parameter.rb index 267fc88..70143fa 100644 --- a/app/models/concerns/fluentd/setting/plugin_parameter.rb +++ b/app/models/concerns/fluentd/setting/plugin_parameter.rb @@ -136,7 +136,7 @@ class Fluentd def reformat_value(name, value) type = column_type(name) return value if type.nil? # name == :time_key - return value if type == :enum + return value.to_sym if type == :enum return value if type == :regexp type_name = if type.is_a?(Fluentd::Setting::Type::Time) :time diff --git a/app/models/concerns/fluentd/setting/section_validator.rb b/app/models/concerns/fluentd/setting/section_validator.rb index 8238441..5f4df18 100644 --- a/app/models/concerns/fluentd/setting/section_validator.rb +++ b/app/models/concerns/fluentd/setting/section_validator.rb @@ -10,6 +10,7 @@ class Fluentd def validate_sections self._section_params.each do |name, sections| sections.each do |section| + next if section.attributes.values.all?(&:blank?) if section.invalid? errors.add(name, :invalid, message: section.errors.full_messages) end diff --git a/app/models/fluentd/setting/in_forward.rb b/app/models/fluentd/setting/in_forward.rb index db1e5e3..d4b7ba0 100644 --- a/app/models/fluentd/setting/in_forward.rb +++ b/app/models/fluentd/setting/in_forward.rb @@ -29,6 +29,35 @@ class Fluentd :blocking_timeout, ] end + + def transport_common_options + [ + :ca_path, + :cert_path, + :private_key_path, + :private_key_passphrase + ] + end + + def transport_advanced_options + [ + :version, + :ciphers, + :insecure, + :client_cert_auth, + :ca_cert_path, + :ca_private_key_path, + :ca_private_key_passphrase, + :generate_private_key_length, + :generate_cert_country, + :generate_cert_state, + :generate_cert_locality, + :generate_cert_common_name, + :generate_cert_common_name, + :generate_cert_expiration, + :generate_cert_digest + ] + end end end end diff --git a/app/models/fluentd/setting/in_syslog.rb b/app/models/fluentd/setting/in_syslog.rb index 8ed0f9d..9ff270c 100644 --- a/app/models/fluentd/setting/in_syslog.rb +++ b/app/models/fluentd/setting/in_syslog.rb @@ -27,7 +27,9 @@ class Fluentd def hidden_options [ - :parse + :parse, + :transport, + :blocking_timeout ] end end diff --git a/app/models/fluentd/setting/out_forward.rb b/app/models/fluentd/setting/out_forward.rb index d6bdcc3..2eeab4a 100644 --- a/app/models/fluentd/setting/out_forward.rb +++ b/app/models/fluentd/setting/out_forward.rb @@ -39,9 +39,20 @@ class Fluentd def hidden_options [ :inject, :buffer, + # Deprecated options :host, :port, - # We don't support TLS configuration via fluentd-ui for now. - :transport, :tls_version, :tls_ciphers, :tls_insecure_mode, :tls_verify_hostname, :tls_cert_path + :transport + ].concat(tls_options) # Hide TLS related options to customize view + end + + def tls_options + [ + :tls_version, + :tls_ciphers, + :tls_insecure_mode, + :tls_allow_self_signed_cert, + :tls_verify_hostname, + :tls_cert_path ] end end diff --git a/app/views/fluentd/settings/in_forward/_form.html.haml b/app/views/fluentd/settings/in_forward/_form.html.haml index 6ea3741..0245f08 100644 --- a/app/views/fluentd/settings/in_forward/_form.html.haml +++ b/app/views/fluentd/settings/in_forward/_form.html.haml @@ -1,16 +1,18 @@ = render "shared/setting_errors" - # NOTE: plugin_setting_form_action_url is defined at SettingConcern -= form_with(model: @setting, scope: "setting", url: plugin_setting_form_action_url(@fluentd), local: true, class: "ignore-rails-error-div", builder: FluentdFormBuilder) do |f| - - @setting.common_options.each do |key| += form_with(model: setting, scope: "setting", url: plugin_setting_form_action_url(fluentd), local: true, class: "ignore-rails-error-div", builder: FluentdFormBuilder) do |f| + - setting.common_options.each do |key| = f.field(key) + = render "shared/vue/transport_section", setting: setting, form: f + .card.card-body.bg-light %h4{"data-toggle" => "collapse", "href" => "#advanced-setting"} = icon('fa-caret-down') = t('terms.advanced_setting') #advanced-setting.collapse - - @setting.advanced_options.each do |key| + - setting.advanced_options.each do |key| = f.field(key) = f.submit t('fluentd.common.finish'), class: "btn btn-lg btn-primary pull-right" diff --git a/app/views/fluentd/settings/out_forward/_form.html.haml b/app/views/fluentd/settings/out_forward/_form.html.haml new file mode 100644 index 0000000..35b5220 --- /dev/null +++ b/app/views/fluentd/settings/out_forward/_form.html.haml @@ -0,0 +1,18 @@ += render "shared/setting_errors" + +- # NOTE: plugin_setting_form_action_url is defined at SettingConcern += form_with(model: setting, scope: "setting", url: plugin_setting_form_action_url(fluentd), local: true, class: "ignore-rails-error-div", builder: FluentdFormBuilder) do |f| + - setting.common_options.each do |key| + = f.field(key) + + = render "shared/vue/out_forward_setting", setting: setting + + .card.card-body.bg-light + %h4{"data-toggle" => "collapse", "href" => "#advanced-setting"} + = icon('fa-caret-down') + = t('terms.advanced_setting') + #advanced-setting.collapse + - setting.advanced_options.each do |key| + = f.field(key) + + = f.submit t('fluentd.common.finish'), class: "btn btn-lg btn-primary pull-right" diff --git a/app/views/shared/settings/show.html.haml b/app/views/shared/settings/show.html.haml index 89d9f01..1f342ee 100644 --- a/app/views/shared/settings/show.html.haml +++ b/app/views/shared/settings/show.html.haml @@ -6,6 +6,6 @@ = raw t("fluentd.settings.#{target_plugin_name}.option_guide") - if lookup_context.exists?("form", controller.controller_path, true) - = render "#{controller.controller_path}/form" + = render "#{controller.controller_path}/form", setting: @setting, fluentd: @fluentd - else - = render "shared/settings/form" + = render "shared/settings/form", setting: @setting, fluentd: @fluentd diff --git a/app/views/shared/vue/_config_field.html.haml b/app/views/shared/vue/_config_field.html.haml index 52e2e59..1aeaa90 100644 --- a/app/views/shared/vue/_config_field.html.haml +++ b/app/views/shared/vue/_config_field.html.haml @@ -5,7 +5,7 @@ "data-toggle" => "tooltip", "data-placement" => "right", "v-bind:title" => "option.desc"} - {{ option.name }} + {{ option.name | humanize }} %select{"v-bind:id" => "inputId(pluginType, option)", "v-bind:name" => "inputName(pluginType, option)", "class" => "form-control"} @@ -22,13 +22,13 @@ "data-toggle" => "tooltip", "data-placement" => "right", "v-bind:title" => "option.desc"} - {{ option.name }} + {{ option.name | humanize }} %template(v-else) %label{"v-bind:for" => "inputId(pluginType, option)", "data-toggle" => "tooltip", "data-placement" => "right", "v-bind:title" => "option.desc"} - {{ option.name }} + {{ option.name | humanize }} %template{"v-if" => 'option.name === "expression"'} %input{"v-bind:id" => "inputId(pluginType, option)", "v-bind:name" => "inputName(pluginType, option)", diff --git a/app/views/shared/vue/_out_forward_setting.html.haml b/app/views/shared/vue/_out_forward_setting.html.haml new file mode 100644 index 0000000..bb43462 --- /dev/null +++ b/app/views/shared/vue/_out_forward_setting.html.haml @@ -0,0 +1,13 @@ +- add_javascript_pack_tag("out_forward_setting") + += render "shared/vue/owned_plugin_form" += render "shared/vue/transport_config" + +#out-forward-setting + %owned-plugin-form{"v-bind:id" => "'buffer-section'", + "v-bind:options-json" => "'#{Fluent::Plugin::BUFFER_REGISTRY.map.keys.to_json}'", + "v-bind:initial-plugin-name" => "'#{setting.buffer_type}'", + "v-bind:plugin-type" => "'buffer'", + "v-bind:plugin-label" => "'Buffer'"} + %transport-config{"v-bind:plugin-type" => "'#{setting.plugin_type}'", + "v-bind:plugin-name" => "'#{setting.plugin_name}'"} diff --git a/app/views/shared/vue/_transport_config.html.haml b/app/views/shared/vue/_transport_config.html.haml new file mode 100644 index 0000000..53e7166 --- /dev/null +++ b/app/views/shared/vue/_transport_config.html.haml @@ -0,0 +1,20 @@ += render "shared/vue/config_field" + +%script{type: "text/x-template", id: "vue-transport-config"} + .form-group.card.card-body.bg-light + %h4 + Transport + .form-group + %select{"class" => "form-control", + "v-model" => "transportType", + "v-on:change" => "onChange"} + %option{"v-for" => "option in options", + "v-bind:value" => "option", + "v-bind:selected" => "transportType === option"} + {{ option | toUpper }} + %p{"v-if" => 'transportType === "tcp"'} + Nothing to configure + %template(v-else) + %template{"v-for" => "option in tlsOptions"} + %config-field{"v-bind:plugin-type" => "pluginType", + "v-bind:option" => "option"} diff --git a/app/views/shared/vue/_transport_section.html.haml b/app/views/shared/vue/_transport_section.html.haml new file mode 100644 index 0000000..c61877e --- /dev/null +++ b/app/views/shared/vue/_transport_section.html.haml @@ -0,0 +1,30 @@ +- add_javascript_pack_tag("transport_section") + += render "shared/vue/config_field" + +#transport-section.form-group.card.card-body.bg-light{"pluginType" => setting.plugin_type, + "pluginName" => setting.plugin_name} + %label + Transport + .form-group + %select{"class" => "form-control", + "v-model" => "transportType", + "v-on:change" => "onChange"} + %option{"v-for" => "option in options", + "v-bind:value" => "option", + "v-bind:selected" => "transportType === option"} + {{ option | toUpper }} + %p{"v-if" => 'transportType === "tcp"'} + Nothing to configure + %template(v-else) + %template{"v-for" => "option in commonOptions"} + %config-field{"v-bind:plugin-type" => "pluginType", + "v-bind:option" => "option"} + .card.card-body.bg-light + %h4{"data-toggle" => "collapse", "href" => "#transport-advanced-setting"} + = icon('fa-caret-down') + = t('terms.advanced_setting') + '(TLS)' + #transport-advanced-setting.collapse + %template{"v-for" => "option in advancedOptions"} + %config-field{"v-bind:plugin-type" => "pluginType", + "v-bind:option" => "option"}