Skip to content

Commit 1a7ccd0

Browse files
authored
Merge pull request #220 from yaauie/ci-boundary-for-geoip-manager
ci: refactor specs with useful boundary from LS-core extension
2 parents 9e5cc7d + c839418 commit 1a7ccd0

File tree

5 files changed

+140
-78
lines changed

5 files changed

+140
-78
lines changed

.ci/run.sh

Lines changed: 0 additions & 9 deletions
This file was deleted.

.travis.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import:
22
- logstash-plugins/.ci:travis/[email protected]
33

44
env:
5+
- DISTRIBUTION=default ELASTIC_STACK_VERSION=8.x
6+
- DISTRIBUTION=oss ELASTIC_STACK_VERSION=8.x
7+
- DISTRIBUTION=default ELASTIC_STACK_VERSION=8.x SNAPSHOT=true
8+
- DISTRIBUTION=oss ELASTIC_STACK_VERSION=8.x SNAPSHOT=true
59
- DISTRIBUTION=default ELASTIC_STACK_VERSION=7.x
10+
- DISTRIBUTION=oss ELASTIC_STACK_VERSION=7.x
611
- DISTRIBUTION=default ELASTIC_STACK_VERSION=7.x SNAPSHOT=true
7-
- DISTRIBUTION=default ELASTIC_STACK_VERSION=8.x SNAPSHOT=true
12+
- DISTRIBUTION=oss ELASTIC_STACK_VERSION=7.x SNAPSHOT=true

spec/filters/geoip_online_spec.rb

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,97 @@
11
# encoding: utf-8
2+
require 'pathname'
23
require "logstash/devutils/rspec/spec_helper"
34
require "insist"
45
require "logstash/filters/geoip"
56
require_relative 'test_helper'
67

78
describe LogStash::Filters::GeoIP do
9+
context "when no database_path is given" do
810

9-
before(:each) do
10-
::File.delete(METADATA_PATH) if ::File.exist?(METADATA_PATH)
11-
end
11+
let(:last_db_path_recorder) do
12+
Module.new do
13+
attr_reader :last_db_path
14+
def setup_filter(db_path)
15+
@last_db_path = db_path
16+
super
17+
end
18+
end
19+
end
1220

13-
describe "config without database path in LS >= 7.14", :aggregate_failures do
14-
before(:each) do
15-
dir_path = Stud::Temporary.directory
16-
File.open(dir_path + '/uuid', 'w') { |f| f.write(SecureRandom.uuid) }
17-
allow(LogStash::SETTINGS).to receive(:get).and_call_original
18-
allow(LogStash::SETTINGS).to receive(:get).with("xpack.geoip.downloader.enabled").and_return(true)
19-
allow(LogStash::SETTINGS).to receive(:get).with("xpack.geoip.download.endpoint").and_return(nil)
20-
allow(LogStash::SETTINGS).to receive(:get).with("path.data").and_return(dir_path)
21+
let(:plugin_config) { Hash["source" => "[source][ip]", "target" => "[target]"] }
22+
let(:plugin) { described_class.new(plugin_config).extend(last_db_path_recorder) }
23+
let(:event) { LogStash::Event.new("source" => { "ip" => "173.9.34.107" }) }
24+
25+
shared_examples "event enrichment" do
26+
it 'enriches events' do
27+
plugin.register
28+
plugin.filter(event)
29+
30+
expect(event.get("target")).to include('ip')
31+
end
2132
end
2233

23-
let(:plugin) { LogStash::Filters::GeoIP.new("source" => "[target][ip]") }
34+
database_management_available = (MAJOR >= 8 || (MAJOR == 7 && MINOR >= 14)) && !LogStash::OSS
35+
if database_management_available
36+
context "when geoip database management is available" do
37+
38+
let(:mock_manager) do
39+
double('LogStash::Filters::Geoip::DatabaseManager').tap do |m|
40+
allow(m).to receive(:subscribe_database_path) do |db_type, explicit_path, plugin_instance|
41+
explicit_path || mock_managed[db_type]
42+
end
43+
allow(m).to receive(:unsubscribe_database_path).with(any_args)
44+
end
45+
end
46+
47+
# The extension to this plugin that lives in Logstash core will _always_ provide a valid
48+
# database path, and how it does so is not the concern of this plugin. We emulate this
49+
# behaviour here by copying the vendored CC-licensed db's into a temporary path
50+
let(:mock_managed) do
51+
managed_path = Pathname.new(temp_data_path).join("managed", Time.now.to_i.to_s).tap(&:mkpath)
52+
53+
managed_city_db_path = Pathname.new(DEFAULT_CITY_DB_PATH).basename.expand_path(managed_path).to_path
54+
FileUtils.cp(DEFAULT_CITY_DB_PATH, managed_city_db_path)
2455

25-
context "restart the plugin" do
26-
let(:event) { LogStash::Event.new("target" => { "ip" => "173.9.34.107" }) }
27-
let(:event2) { LogStash::Event.new("target" => { "ip" => "55.159.212.43" }) }
56+
managed_asn_db_path = Pathname.new(DEFAULT_ASN_DB_PATH).basename.expand_path(managed_path).to_path
57+
FileUtils.cp(DEFAULT_ASN_DB_PATH, managed_asn_db_path)
2858

29-
it "should use the same database" do
30-
unless plugin.load_database_manager?
31-
logstash_path = ENV['LOGSTASH_PATH'] || '/usr/share/logstash' # docker logstash home
32-
stub_const('LogStash::Environment::LOGSTASH_HOME', logstash_path)
59+
{
60+
'City' => managed_city_db_path,
61+
'ASN' => managed_asn_db_path,
62+
}
3363
end
3464

35-
plugin.register
36-
plugin.filter(event)
37-
plugin.close
38-
first_dirname = get_metadata_city_database_name
39-
plugin.register
40-
plugin.filter(event2)
41-
plugin.close
42-
second_dirname = get_metadata_city_database_name
65+
before(:each) do
66+
allow_any_instance_of(described_class).to receive(:load_database_manager?).and_return(true)
67+
stub_const("LogStash::Filters::Geoip::DatabaseManager", double("DatabaseManager.Class", :instance => mock_manager))
68+
end
4369

44-
expect(first_dirname).not_to be_nil
45-
expect(first_dirname).to eq(second_dirname)
46-
expect(File).to exist(get_file_path(first_dirname))
70+
let(:temp_data_path) { Stud::Temporary.directory }
71+
after(:each) do
72+
FileUtils.rm_rf(temp_data_path) if File.exist?(temp_data_path)
73+
end
74+
75+
it "uses a managed database" do
76+
plugin.register
77+
plugin.filter(event)
78+
expect(plugin.last_db_path).to_not be_nil
79+
expect(plugin.last_db_path).to start_with(temp_data_path)
80+
end
81+
82+
include_examples "event enrichment"
4783
end
48-
end
49-
end if MAJOR >= 8 || (MAJOR == 7 && MINOR >= 14)
50-
51-
describe "config without database path in LS < 7.14" do
52-
context "should run in offline mode" do
53-
config <<-CONFIG
54-
filter {
55-
geoip {
56-
source => "ip"
57-
}
58-
}
59-
CONFIG
60-
61-
sample("ip" => "173.9.34.107") do
62-
insist { subject.get("geoip") }.include?("ip")
63-
expect(::File.exist?(METADATA_PATH)).to be_falsey
84+
else
85+
context "when geoip database management is not available" do
86+
87+
include_examples "event enrichment"
88+
89+
it "uses a plugin-vendored database" do
90+
plugin.register
91+
expect(plugin.last_db_path).to_not be_nil
92+
expect(plugin.last_db_path).to include("/vendor/")
93+
end
6494
end
6595
end
66-
end if MAJOR < 7 || (MAJOR == 7 && MINOR < 14)
96+
end
6797
end

spec/filters/geoip_spec.rb

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
end
2020
end
2121

22-
describe ">= 7.14" do
22+
shared_examples "with database manager" do
2323
it "load_database_manager? should be true" do
2424
expect(plugin.load_database_manager?).to be_truthy
2525
end
26-
end if MAJOR >= 8 || (MAJOR == 7 && MINOR >= 14)
26+
end
2727

28-
describe "<= 7.13" do
28+
shared_examples "without database manager" do
2929
it "load_database_manager? should be false" do
3030
expect(plugin.load_database_manager?).to be_falsey
3131
end
@@ -37,6 +37,24 @@
3737
expect(plugin.select_database_path).to eql(DEFAULT_CITY_DB_PATH)
3838
end
3939
end
40-
end if MAJOR < 7 || (MAJOR == 7 && MINOR <= 13)
40+
end
41+
42+
if MAJOR >= 8 || (MAJOR == 7 && MINOR >= 14)
43+
context "Logstash >= 7.14" do
44+
if LogStash::OSS
45+
context "OSS-only" do
46+
include_examples "without database manager"
47+
end
48+
else
49+
context "default distro" do
50+
include_examples "with database manager"
51+
end
52+
end
53+
end
54+
else
55+
describe "Logstash < 7.14" do
56+
include_examples "without database manager"
57+
end
58+
end
4159
end
4260
end

spec/filters/test_helper.rb

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,46 @@
22
require "digest"
33
require "csv"
44

5-
def get_vendor_path(filename)
6-
::File.join(::File.expand_path("../../vendor/", ::File.dirname(__FILE__)), filename)
7-
end
8-
9-
def get_data_dir
10-
::File.join(LogStash::SETTINGS.get_value("path.data"), "plugins", "filters", "geoip")
11-
end
12-
13-
def get_file_path(filename)
14-
::File.join(get_data_dir, filename)
15-
end
5+
# Since we use Logstash's x-pack WITHOUT the LogStash::Runner,
6+
# we must find it relative to logstash-core and add it to the load path.
7+
require 'pathname'
8+
logstash_core_path = Gem.loaded_specs['logstash-core']&.full_gem_path or fail("logstash-core lib not found")
9+
logstash_xpack_load_path = Pathname.new(logstash_core_path).join("../x-pack/lib").cleanpath.to_s
10+
if ENV['OSS'] == "true" || !File.exists?(logstash_xpack_load_path)
11+
$stderr.puts("X-PACK is not available")
12+
LogStash::OSS = true
13+
else
14+
if !$LOAD_PATH.include?(logstash_xpack_load_path)
15+
$stderr.puts("ADDING LOGSTASH X-PACK to load path: #{logstash_xpack_load_path}")
16+
$LOAD_PATH.unshift(logstash_xpack_load_path)
17+
end
18+
LogStash::OSS = false
1619

17-
def get_metadata_city_database_name
18-
if ::File.exist?(METADATA_PATH)
19-
city = ::CSV.read(METADATA_PATH, headers: false).select { |row| row[0].eql?("City") }.last
20-
city[3]
20+
# when running in a Logstash process that has a geoip extension available, it will
21+
# be loaded before this plugin is instantiated. In tests, we need to find and load the
22+
# appropriate extension ourselves.
23+
extension = nil
24+
extension ||= begin; require 'geoip_database_management/extension'; LogStash::const_get("GeoipDatabaseManagement::Extension"); rescue Exception; nil; end
25+
extension ||= begin; require 'filters/geoip/extension'; LogStash::const_get("Filters::Geoip::Extension"); rescue Exception; nil; end
26+
if extension
27+
$stderr.puts("loading logstash extension for geoip: #{extension}")
28+
extension.new.tap do |instance|
29+
# the extensions require logstash/runner even though they don't need to,
30+
# resulting in _all_ extensions being loaded into the registry, including
31+
# those whose dependencies are not met by this plugin's dependency graph.
32+
def instance.require(path)
33+
super unless path == "logstash/runner"
34+
end
35+
end.additionals_settings(LogStash::SETTINGS)
2136
else
22-
nil
37+
$stderr.puts("no logstash extension for geoip is available")
2338
end
2439
end
2540

26-
METADATA_PATH = get_file_path("metadata.csv")
41+
def get_vendor_path(filename)
42+
::File.join(::File.expand_path("../../vendor/", ::File.dirname(__FILE__)), filename)
43+
end
44+
2745
DEFAULT_CITY_DB_PATH = get_vendor_path("GeoLite2-City.mmdb")
2846
DEFAULT_ASN_DB_PATH = get_vendor_path("GeoLite2-ASN.mmdb")
2947

0 commit comments

Comments
 (0)