logstash-filter-ipinfo-db-zuin 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +20 -3
- data/docs/index.asciidoc +5 -1
- data/lib/logstash/filters/ipinfo-db.rb +34 -11
- data/logstash-filter-ipinfo-db-zuin.gemspec +3 -1
- data/spec/filters/ipinfo-db_spec.rb +40 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1962e6ef9deb4779538f53751b6a1dc5c923cdefa9f6f55cbbc49ca975508f22
|
|
4
|
+
data.tar.gz: 03b6b14aaa3f41fd6e79f036c394edc471d8c27f3a295be1e649be9dc52ca6ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc2dcf4bec7885b0922dd9fc2d3edd58162f239178e98491095bca67771e6480c69a06aac6297eb90e02406c162b1aa9112e29eaea8479242642050bd8435c6d
|
|
7
|
+
data.tar.gz: b2c07c3692ac8e86c61c8705c1c27d11a8b30b999a4db7630d331b9a18258451918cb0eb3a5192c086e717c33e1b0480df6006e3868b492512984c8a0ab2bc25
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## 0.4.0
|
|
2
|
+
|
|
3
|
+
- Recover from an existing invalid database file (for example truncated or empty): with `token`
|
|
4
|
+
set, log a warning and download a fresh copy; without it, fail with a message saying to delete or
|
|
5
|
+
replace the file (#3)
|
|
6
|
+
|
|
7
|
+
## 0.3.0
|
|
8
|
+
|
|
9
|
+
- Declare `required_ruby_version >= 3.1` in the gemspec. Logstash 8.19 (JRuby 9.4, Ruby 3.1
|
|
10
|
+
compatible) is the oldest runtime verified in CI; Logstash 9.x ships JRuby 10.
|
|
11
|
+
|
|
1
12
|
## 0.2.0
|
|
2
13
|
|
|
3
14
|
- Forked as `logstash-filter-ipinfo-db-zuin` (filter name stays `ipinfo-db`)
|
data/README.md
CHANGED
|
@@ -53,13 +53,14 @@ The lookup result is written to the `ipinfo-db` field. For `8.8.8.8` it looks li
|
|
|
53
53
|
|---|---|---|
|
|
54
54
|
| `source` | (required) | Field containing the IP address (IPv4 or IPv6). Hostnames are not resolved. |
|
|
55
55
|
| `target` | `ipinfo-db` | Field to write the result into. |
|
|
56
|
-
| `token` | none | ipinfo.io token, used only to download the database when the file does not exist. |
|
|
57
|
-
| `database` | `<path.data>/plugins/filters/ipinfo-db/country_asn.mmdb` | Path to the `.mmdb` file. Downloaded there if missing. |
|
|
56
|
+
| `token` | none | ipinfo.io token, used only to download the database: when the file does not exist, or is not a valid database. |
|
|
57
|
+
| `database` | `<path.data>/plugins/filters/ipinfo-db/country_asn.mmdb` | Path to the `.mmdb` file. Downloaded there if missing, or if the file there is not a valid database (with `token`). |
|
|
58
58
|
| `database_age_warning_days` | `30` | Log a warning when the database is older than this. `0` disables it. |
|
|
59
59
|
| `tag_on_failure` | `["_ipinfo_db_lookup_failure"]` | Tags added when the field is missing, the value is not a valid IP, or the lookup fails. IPs that are simply not in the database are not tagged. |
|
|
60
60
|
|
|
61
61
|
The plugin does not update the database automatically. To refresh it, delete the file and restart
|
|
62
|
-
Logstash, or replace the file with a newer copy
|
|
62
|
+
Logstash (needs `token`, to download it again), or replace the file with a newer copy and restart or
|
|
63
|
+
reload the pipeline. See [docs/index.asciidoc](docs/index.asciidoc) for the
|
|
63
64
|
full reference.
|
|
64
65
|
|
|
65
66
|
## Development
|
|
@@ -72,6 +73,11 @@ bundle install
|
|
|
72
73
|
bundle exec rspec
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
Run them with Logstash's JRuby and JDK, and pass the JVM flags that `bin/logstash` normally adds itself
|
|
77
|
+
(the `JVM_FLAGS` list in `verify/verify.sh`) through `JAVA_OPTS`. Without them the pipeline specs fail
|
|
78
|
+
with `IllegalAccessError` on `jdk.compiler`. The easiest way to get this right is `verify/verify.sh`
|
|
79
|
+
(below), which runs the suite inside the official Logstash image.
|
|
80
|
+
|
|
75
81
|
The default suite runs offline against `spec/fixtures/ipinfo-test.mmdb`, a tiny synthetic database
|
|
76
82
|
(documentation IP ranges only) generated by `spec/fixtures/generate_ipinfo_test_mmdb.py`. The live test,
|
|
77
83
|
which downloads the real database from ipinfo.io, is tagged `integration` and excluded by default:
|
|
@@ -114,6 +120,17 @@ Or add it to the Logstash `Gemfile` from your local checkout, then run `bin/logs
|
|
|
114
120
|
gem "logstash-filter-ipinfo-db-zuin", :path => "/path/to/logstash-filter-ipinfo-db"
|
|
115
121
|
```
|
|
116
122
|
|
|
123
|
+
## Releasing
|
|
124
|
+
|
|
125
|
+
1. Set `s.version` in `logstash-filter-ipinfo-db-zuin.gemspec`, and add a `## <version>` section at the
|
|
126
|
+
top of `CHANGELOG.md` (rename `## Unreleased` if there is one).
|
|
127
|
+
2. Merge to `main`.
|
|
128
|
+
|
|
129
|
+
`.github/workflows/tag.yml` sees the new gemspec version and pushes `v<version>`. That tag starts
|
|
130
|
+
`.github/workflows/release.yml`, which checks that the tag, gemspec and newest CHANGELOG section agree,
|
|
131
|
+
runs the verification above, publishes the gem to RubyGems via trusted publishing, and creates the
|
|
132
|
+
GitHub Release. Versions with a letter (e.g. `0.4.0.rc1`) are published as pre-releases.
|
|
133
|
+
|
|
117
134
|
## Help
|
|
118
135
|
|
|
119
136
|
Open an issue at https://github.com/reflective-technology/logstash-filter-ipinfo-db/issues, or ask in the
|
data/docs/index.asciidoc
CHANGED
|
@@ -63,7 +63,11 @@ filter plugins.
|
|
|
63
63
|
|
|
64
64
|
Path to the ipinfo `.mmdb` database file. If the file exists, the plugin uses it as is. If it does not exist,
|
|
65
65
|
the plugin downloads it to this path on startup using <<plugins-{type}s-{plugin}-token>>, creating parent
|
|
66
|
-
directories as needed.
|
|
66
|
+
directories as needed. If the file exists but is not a valid `.mmdb` database (for example truncated or
|
|
67
|
+
empty), the plugin logs a warning and downloads a fresh copy when `token` is set; without a token it fails to
|
|
68
|
+
start with a message saying to delete or replace the file.
|
|
69
|
+
|
|
70
|
+
`path.data` is the Logstash data directory (for example `/var/lib/logstash` for
|
|
67
71
|
deb/rpm installs and `/usr/share/logstash/data` in Docker). Use an absolute path; a relative path is resolved
|
|
68
72
|
against the Logstash working directory.
|
|
69
73
|
|
|
@@ -196,25 +196,48 @@ class LogStash::Filters::IpinfoDb < LogStash::Filters::Base
|
|
|
196
196
|
|
|
197
197
|
@db = self.class.with_path_lock(path) do
|
|
198
198
|
if File.exist?(path)
|
|
199
|
-
self.class.acquire_reader(path) ||
|
|
199
|
+
self.class.acquire_reader(path) || load_or_replace_invalid(path)
|
|
200
200
|
else
|
|
201
|
-
|
|
202
|
-
raise LogStash::ConfigurationError, "ipinfo-db: database file #{
|
|
203
|
-
end
|
|
204
|
-
reader, identity = download_database
|
|
205
|
-
# A rename keeps inode, size and mtime, so a different identity here means
|
|
206
|
-
# another process replaced the file after our rename: load what is there.
|
|
207
|
-
if File.exist?(path) && self.class.file_identity(path) == identity
|
|
208
|
-
self.class.store_reader(path, identity, reader)
|
|
209
|
-
else
|
|
210
|
-
self.class.load_reader(path)
|
|
201
|
+
unless token_set?
|
|
202
|
+
raise LogStash::ConfigurationError, "ipinfo-db: database file #{path} not found. Set `token` to download it, or place the file there."
|
|
211
203
|
end
|
|
204
|
+
download_and_cache(path)
|
|
212
205
|
end
|
|
213
206
|
end
|
|
214
207
|
end
|
|
215
208
|
|
|
216
209
|
private
|
|
217
210
|
|
|
211
|
+
def token_set?
|
|
212
|
+
!(@token.nil? || @token.value.to_s.empty?)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Load an existing database file. If it is not a valid database (for example
|
|
216
|
+
# truncated by an older version or edited by hand), download a fresh copy when
|
|
217
|
+
# a token is set; otherwise fail with a message saying how to fix it.
|
|
218
|
+
def load_or_replace_invalid(path)
|
|
219
|
+
self.class.load_reader(path)
|
|
220
|
+
rescue MaxMind::DB::InvalidDatabaseError => e
|
|
221
|
+
unless token_set?
|
|
222
|
+
raise LogStash::ConfigurationError, "ipinfo-db: database file #{path} is not a valid .mmdb file (#{e.message}). " \
|
|
223
|
+
"Delete or replace it, or set `token` to download a fresh copy."
|
|
224
|
+
end
|
|
225
|
+
@logger.warn("ipinfo database file is not a valid .mmdb file; downloading a fresh copy", :path => path, :error => e.message)
|
|
226
|
+
download_and_cache(path)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Download the database to path (replacing any file there) and cache its reader.
|
|
230
|
+
def download_and_cache(path)
|
|
231
|
+
reader, identity = download_database
|
|
232
|
+
# A rename keeps inode, size and mtime, so a different identity here means
|
|
233
|
+
# another process replaced the file after our rename: load what is there.
|
|
234
|
+
if File.exist?(path) && self.class.file_identity(path) == identity
|
|
235
|
+
self.class.store_reader(path, identity, reader)
|
|
236
|
+
else
|
|
237
|
+
self.class.load_reader(path)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
218
241
|
# Warn when the loaded database is older than database_age_warning_days,
|
|
219
242
|
# based on the build time stored in the database itself.
|
|
220
243
|
def check_database_age
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = 'logstash-filter-ipinfo-db-zuin'
|
|
3
|
-
s.version = '0.
|
|
3
|
+
s.version = '0.4.0'
|
|
4
4
|
s.licenses = ['Apache-2.0']
|
|
5
5
|
s.summary = 'Logstash Filter Plugin for IPinfoDb'
|
|
6
6
|
s.description = 'This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline ' \
|
|
@@ -10,6 +10,8 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.authors = ['ZUIN RD']
|
|
11
11
|
s.email = 'rd@zuin.ai'
|
|
12
12
|
s.require_paths = ['lib']
|
|
13
|
+
# Oldest runtime verified in CI: Logstash 8.19 ships JRuby 9.4, which is Ruby 3.1 compatible.
|
|
14
|
+
s.required_ruby_version = '>= 3.1'
|
|
13
15
|
|
|
14
16
|
# Files
|
|
15
17
|
s.files = Dir['lib/**/*','spec/**/*','docs/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE']
|
|
@@ -269,6 +269,46 @@ describe LogStash::Filters::IpinfoDb do
|
|
|
269
269
|
let(:data_dir) { Dir.mktmpdir }
|
|
270
270
|
after { FileUtils.rm_rf(data_dir) }
|
|
271
271
|
|
|
272
|
+
def stub_download_of_fixture
|
|
273
|
+
allow(Down).to receive(:download) do
|
|
274
|
+
Tempfile.new("ipinfo-download").tap do |file|
|
|
275
|
+
file.binmode
|
|
276
|
+
file.write(File.binread(FIXTURE_DATABASE))
|
|
277
|
+
file.flush
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
{ "corrupt" => "not a database", "empty" => "" }.each do |kind, content|
|
|
283
|
+
it "replaces an existing #{kind} database file with a fresh download when a token is set" do
|
|
284
|
+
database = File.join(data_dir, "country_asn.mmdb")
|
|
285
|
+
File.write(database, content)
|
|
286
|
+
stub_download_of_fixture
|
|
287
|
+
plugin = described_class.new("source" => "ip", "database" => database, "token" => "t", "database_age_warning_days" => 0)
|
|
288
|
+
expect(plugin.logger).to receive(:warn).with(/not a valid \.mmdb file; downloading a fresh copy/, hash_including(:path => database))
|
|
289
|
+
|
|
290
|
+
plugin.register
|
|
291
|
+
|
|
292
|
+
expect(Down).to have_received(:download).once
|
|
293
|
+
expect(File.binread(database)).to eq(File.binread(FIXTURE_DATABASE))
|
|
294
|
+
expect(Dir.children(data_dir)).to eq(["country_asn.mmdb"])
|
|
295
|
+
event = LogStash::Event.new("ip" => "192.0.2.10")
|
|
296
|
+
plugin.filter(event)
|
|
297
|
+
expect(event.get("[ipinfo-db][country]")).to eq("US")
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
it "fails with instructions when an existing database file is invalid and no token is set" do
|
|
302
|
+
database = File.join(data_dir, "country_asn.mmdb")
|
|
303
|
+
File.write(database, "not a database")
|
|
304
|
+
expect(Down).not_to receive(:download)
|
|
305
|
+
plugin = described_class.new("source" => "ip", "database" => database)
|
|
306
|
+
|
|
307
|
+
expect { plugin.register }.to raise_error(LogStash::ConfigurationError,
|
|
308
|
+
/#{Regexp.escape(database)} is not a valid \.mmdb file .*Delete or replace it, or set `token`/)
|
|
309
|
+
expect(File.read(database)).to eq("not a database") # left for the user to inspect
|
|
310
|
+
end
|
|
311
|
+
|
|
272
312
|
it "defaults to a file under path.data" do
|
|
273
313
|
allow(LogStash::SETTINGS).to receive(:get_value).and_call_original
|
|
274
314
|
allow(LogStash::SETTINGS).to receive(:get_value).with("path.data").and_return(data_dir)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: logstash-filter-ipinfo-db-zuin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ZUIN RD
|
|
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
101
101
|
requirements:
|
|
102
102
|
- - ">="
|
|
103
103
|
- !ruby/object:Gem::Version
|
|
104
|
-
version: '
|
|
104
|
+
version: '3.1'
|
|
105
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
107
107
|
- - ">="
|