Skip to content

Commit

Permalink
plugin manager: add --no-expand flag for list command (#17124)
Browse files Browse the repository at this point in the history
* plugin manager: add --no-expand flag for list command

Allows us to avoid expanding aliases and integration plugins

* spec: escape expected output in regexp
  • Loading branch information
yaauie authored Feb 27, 2025
1 parent d40386a commit 793e8c0
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 12 deletions.
31 changes: 19 additions & 12 deletions lib/pluginmanager/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class LogStash::PluginManager::List < LogStash::PluginManager::Command
parameter "[PLUGIN]", "Part of plugin name to search for, leave empty for all plugins"

option "--installed", :flag, "List only explicitly installed plugins using bin/logstash-plugin install ...", :default => false
option "--[no-]expand", :flag, "Expand integration plugins and aliases", :default => true
option "--verbose", :flag, "Also show plugin version number", :default => false
option "--group", "NAME", "Filter plugins per group: input, output, filter, codec or integration" do |arg|
raise(ArgumentError, "should be one of: input, output, filter, codec, integration") unless ['input', 'output', 'filter', 'codec', 'pack', 'integration'].include?(arg)
Expand All @@ -40,23 +41,29 @@ def execute
line = "#{spec.name}"
line += " (#{spec.version})" if verbose?
puts(line)
if LogStash::PluginManager::ALIASES.has_value?(spec.name)
alias_plugin = LogStash::PluginManager::ALIASES.key(spec.name)
puts("└── #{alias_plugin} (alias)") unless installed_plugin_names.include?(alias_plugin)
end
if spec.metadata.fetch("logstash_group", "") == "integration"
integration_plugins = spec.metadata.fetch("integration_plugins", "").split(",")
integration_plugins.each_with_index do |integration_plugin, i|
if i == integration_plugins.size - 1
puts(" └── #{integration_plugin}")
else
puts(" ├── #{integration_plugin}")
end
if expand?
active_aliases = LogStash::PluginManager.find_aliases(spec.name)
.reject {|alias_name| installed_plugin_names.include?(alias_name)}
display_children(active_aliases.map {|alias_name| "#{alias_name} (alias)"})

if spec.metadata.fetch("logstash_group", "") == "integration"
integration_plugins = spec.metadata.fetch("integration_plugins", "").split(",")
display_children(integration_plugins)
end
end
end
end

def display_children(children)
if children.any?
most, last = children[0...-1], children[-1]
most.each do |entry|
puts(" ├── #{entry}")
end
puts(" └── #{last}")
end
end

def filtered_specs
@filtered_specs ||= begin
# start with all locally installed plugin gems regardless of the Gemfile content
Expand Down
10 changes: 10 additions & 0 deletions lib/pluginmanager/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ def self.load_aliases_definitions(path = File.expand_path('plugin_aliases.yml',
# Defines the plugin alias, must be kept in synch with Java class org.logstash.plugins.AliasRegistry
ALIASES = load_aliases_definitions()

def self.resolve_alias(alias_name)
ALIASES[alias_name]
end

def self.find_aliases(plugin_name)
ALIASES.each_with_object([]) do |(alias_name, candidate_plugin_name), aliases|
aliases << alias_name if candidate_plugin_name == plugin_name
end.compact.uniq
end

class ValidationError < StandardError; end

# check for valid logstash plugin gem name & version or .gem file, logs errors to $stdout
Expand Down
3 changes: 3 additions & 0 deletions qa/integration/fixtures/list_spec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
services:
- logstash
94 changes: 94 additions & 0 deletions qa/integration/specs/cli/list_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require_relative '../../framework/fixture'
require_relative '../../framework/settings'
require_relative '../../services/logstash_service'
require_relative '../../framework/helpers'
require "logstash/devutils/rspec/spec_helper"

describe "CLI > logstash-plugin remove" do
before(:all) do
@fixture = Fixture.new(__FILE__)
@logstash_plugin = @fixture.get_service("logstash").plugin_cli
end

context "listing plugins" do

let(:sub_heading_pattern) do
Regexp.union(" ├──"," └──")
end

let(:version_pattern) do
/[0-9]+[.][0-9][0-9a-z.]+/
end

def parse_output(output)
output.split(/\n(?! )/)
end

context "--verbose" do
it "successfully lists a single plugin" do
list_command = @logstash_plugin.run("list --verbose logstash-integration-jdbc")
expect(list_command.exit_code).to eq(0)
expect(list_command.stderr_and_stdout).to match(/^logstash-integration-jdbc [(]#{version_pattern}[)]/)
end
it "successfully lists all plugins" do
list_command = @logstash_plugin.run("list --verbose")
expect(list_command.exit_code).to eq(0)
expect(list_command.stderr_and_stdout).to match(/^logstash-integration-jdbc [(]#{version_pattern}[)]/)
expect(list_command.stderr_and_stdout).to match(/^logstash-input-beats [(]#{version_pattern}[)]/)
expect(list_command.stderr_and_stdout).to match(/^logstash-output-elasticsearch [(]#{version_pattern}[)]/)
end
end

it "expands integration plugins" do
list_command = @logstash_plugin.run("list logstash-integration-jdbc")
expect(list_command.exit_code).to eq(0)
plugins = list_command.stderr_and_stdout.split(/\n(?! )/)

integration_plugin = plugins.find { |plugin_output| plugin_output.match(/^logstash-integration-jdbc\b/) }
expect(integration_plugin).to match(/^#{sub_heading_pattern} #{Regexp.escape("logstash-input-jdbc")}$/)
expect(integration_plugin).to match(/^#{sub_heading_pattern} #{Regexp.escape("logstash-filter-jdbc_static")}$/)
end

it "expands plugin aliases" do
list_command = @logstash_plugin.run("list logstash-input-beats")
expect(list_command.exit_code).to eq(0)
plugins = list_command.stderr_and_stdout.split(/\n(?! )/)

alias_plugin = plugins.find { |plugin_output| plugin_output.match(/^logstash-input-beats\b/) }
expect(alias_plugin).to match(/^#{sub_heading_pattern} #{Regexp.escape("logstash-input-elastic_agent (alias)")}$/)
end

context "--no-expand" do
it "does not expand integration plugins" do
list_command = @logstash_plugin.run("list --no-expand")
expect(list_command.exit_code).to eq(0)
expect(list_command.stderr_and_stdout).to match(/^logstash-integration-jdbc\b/)
expect(list_command.stderr_and_stdout).to_not include("logstash-input-jdbc") # known integrated plugin
expect(list_command.stderr_and_stdout).to_not include("logstash-filter-jdbc") # known integrated plugin
end
it "does not expand plugin aliases" do
list_command = @logstash_plugin.run("list --no-expand")
expect(list_command.exit_code).to eq(0)
expect(list_command.stderr_and_stdout).to match(/^logstash-input-beats\b/)
expect(list_command.stderr_and_stdout).to_not include("logstash-input-elastic_agent") # known alias
end
end
end
end

0 comments on commit 793e8c0

Please sign in to comment.