# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one # or more contributor license agreements. Licensed under the Elastic License; # you may not use this file except in compliance with the Elastic License. require "logstash/bootstrap_check/default_config" module LogStash module ConfigManagement # Override the default Logstash's bootstrap check # instead of making the `-e` and the `-f` mandatory we rely # on the elasticsearch source. # # If we don't use config management we checks for CLI flags/logstash.yml options class BootstrapCheck include LogStash::Util::Loggable # pipeline ID must begin with a letter or underscore and contain only letters, underscores, dashes, and numbers # wildcard character `*` is also acceptable and follows globbing rules PIPELINE_ID_PATTERN = %r{\A[a-z_*][a-z_\-0-9*]*\Z}i def self.check(settings) check_path_config(settings) if settings.get("config.string") raise LogStash::BootstrapCheckError, "You cannot use -e since Elasticsearch is configured as the config store." end if settings.get("config.test_and_exit") raise LogStash::BootstrapCheckError, "You cannot use -t since Elasticsearch is configured as the config store" end if !settings.get("modules.cli").empty? || !settings.get("modules").empty? raise LogStash::BootstrapCheckError, "You cannot use --modules since Elasticsearch is configured as the config store" end interval = settings.get("xpack.management.logstash.poll_interval") # override core settings, so the agent will trigger the auto reload settings.set("config.reload.automatic", true) settings.set("config.reload.interval", interval) pipeline_ids = settings.get("xpack.management.pipeline.id") if pipeline_ids.reject { |id| id.strip.empty? }.empty? raise LogStash::BootstrapCheckError, "You need to specify the ID of the pipelines with the `xpack.management.pipeline.id` options in your logstash.yml" end invalid_patterns = pipeline_ids.reject { |entry| PIPELINE_ID_PATTERN =~ entry } if invalid_patterns.any? raise LogStash::BootstrapCheckError, "Pipeline id in `xpack.management.pipeline.id` must begin with a letter or underscore and contain only letters, underscores, dashes, and numbers. The asterisk wildcard `*` can also be used. Invalid ids: #{invalid_patterns.join(', ')}" end duplicate_ids = find_duplicate_ids(pipeline_ids) if duplicate_ids.size > 0 raise LogStash::BootstrapCheckError, "Duplicate pipeline ids found in `xpack.management.pipeline.id`, defined IDs must be unique, Duplicated ids: #{duplicate_ids.join(', ')}" end logger.info("Using Elasticsearch as config store", :pipeline_id => pipeline_ids, :poll_interval => "#{interval}ns") end def self.check_path_config(settings) path_config = settings.get("path.config") return if (path_config.nil? || path_config.empty?) configs_count = Dir.glob(path_config).size return if configs_count.zero? msg = sprintf("There are config files (%i) in the '%s' folder.", configs_count, path_config) msg.concat(" Elasticsearch is configured as the config store so configs cannot be sourced") msg.concat(" via the command line with -f or via logstash.yml with path.config") logger.error(msg) raise LogStash::BootstrapCheckError, msg end def self.find_duplicate_ids(ids) normalized_ids = ids.dup .map(&:to_s) .map(&:strip) .map(&:downcase) .group_by { |id| id } duplicate_ids = [] ids.each do |id| if normalized_ids.fetch(id.downcase).size > 1 duplicate_ids << id end end # We normalize the pipeline id into lowercase string, # this allow us to detect weird capitalized ids and all lowercase ids. # But when reporting the ids, its more useful to the user # report the `uniq` with the appropriate capitalization. # # Example: # pipeline1, pipeline1 => ["pipeline1"] # pipeline1, PIPELINE1 => ["pipeline1", "PIPELINE1"] duplicate_ids.uniq end end end end