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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b36618d5861aa97840f2735fe419fd4303f858f553d883ee8f798c480153666
4
- data.tar.gz: a298c76f7316d14c68d9efca5923797c7f6f231758ace241fa7a4c723344181d
3
+ metadata.gz: 1962e6ef9deb4779538f53751b6a1dc5c923cdefa9f6f55cbbc49ca975508f22
4
+ data.tar.gz: 03b6b14aaa3f41fd6e79f036c394edc471d8c27f3a295be1e649be9dc52ca6ad
5
5
  SHA512:
6
- metadata.gz: 7e066fcca849ed60a80c95b745756185d92f5494492df4bd3a7792d011788c2243c3d91a91ee9dd5cb85ab46917b83f38d1b42125fed45f5f7e92d9c9c953040
7
- data.tar.gz: 7e38e997a2a75444dfefc2630f1632ff8a1929c5d2e66942135601d6c991e26979eb16ff2f3f3a61d61d4a681fb753026978482da72e842af9085ebb7546a272
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. See [docs/index.asciidoc](docs/index.asciidoc) for the
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. `path.data` is the Logstash data directory (for example `/var/lib/logstash` for
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) || self.class.load_reader(path)
199
+ self.class.acquire_reader(path) || load_or_replace_invalid(path)
200
200
  else
201
- if @token.nil? || @token.value.to_s.empty?
202
- raise LogStash::ConfigurationError, "ipinfo-db: database file #{@database} not found. Set `token` to download it, or place the file there."
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.2.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.2.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: '0'
104
+ version: '3.1'
105
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - ">="